Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcvs2git2006-06-13 04:16:30 +0000
committercvs2git2006-06-13 04:16:30 +0000
commit30d866faea7c5b7a3427b7d0ecc812a8bf0ce24b (patch)
treef00e36ca9f7daa47ad5816ab1b2a71cd14019740
parent67a70de8da422c8c6dee91d6ed80a2f7eb0f246f (diff)
downloadorg.eclipse.mylyn.tasks-30d866faea7c5b7a3427b7d0ecc812a8bf0ce24b.tar.gz
org.eclipse.mylyn.tasks-30d866faea7c5b7a3427b7d0ecc812a8bf0ce24b.tar.xz
org.eclipse.mylyn.tasks-30d866faea7c5b7a3427b7d0ecc812a8bf0ce24b.zip
This commit was manufactured by cvs2svn to create tag 'Root_e_3_1'.Root_e_3_1
Sprout from e_3_1 2006-03-17 18:50:26 UTC cvs2git 'This commit was manufactured by cvs2svn to create branch 'e_3_1'.' Cherrypick from e_3_1 2006-06-13 04:16:29 UTC cvs2git 'This commit was manufactured by cvs2svn to create branch 'e_3_1'.': org.eclipse.mylyn.bugzilla.core/.classpath org.eclipse.mylyn.bugzilla.core/.settings/org.eclipse.ltk.core.refactoring.prefs org.eclipse.mylyn.bugzilla.core/META-INF/MANIFEST.MF org.eclipse.mylyn.bugzilla.core/about.html org.eclipse.mylyn.bugzilla.core/build.properties org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/AbstractReportFactory.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttachmentHandler.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttributeFactory.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaPlugin.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportElement.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportSubmitForm.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaRepositoryUtil.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskData.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/IBugzillaConstants.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/KeywordParser.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/NewBugzillaReport.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfiguration.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfigurationFactory.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryReportFactory.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxBugReportContentHandler.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxConfigurationContentHandler.java org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/XmlCleaner.java org.eclipse.mylyn.bugzilla.tests/META-INF/MANIFEST.MF org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaTaskHyperlinkDetectorTest.java org.eclipse.mylyn.bugzilla.tests/testdata/contexts/.cvsignore org.eclipse.mylyn.bugzilla.tests/testdata/contexts/empty.txt org.eclipse.mylyn.bugzilla.tests/testdata/pages/test-report-222attachment.html org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaHyperLink.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/WebBrowserDialog.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/AbstractBugzillaQueryPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaCustomQueryWizardPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaQueryTypeWizardPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/NewBugzillaQueryWizard.java org.eclipse.mylyn.help.ui/.externalToolBuilders/org.eclipse.jdt.core.javabuilder.launch org.eclipse.mylyn.help.ui/.project org.eclipse.mylyn.help.ui/.settings/org.eclipse.ltk.core.refactoring.prefs org.eclipse.mylyn.help.ui/META-INF/MANIFEST.MF org.eclipse.mylyn.help.ui/about.html org.eclipse.mylyn.help.ui/doc/contributing.html org.eclipse.mylyn.help.ui/doc/dev/changes.html org.eclipse.mylyn.help.ui/doc/dev/dependencies.vsd org.eclipse.mylyn.help.ui/doc/dev/index.html org.eclipse.mylyn.help.ui/doc/dev/model.vsd org.eclipse.mylyn.help.ui/doc/dev/plan.html org.eclipse.mylyn.help.ui/doc/faq.html org.eclipse.mylyn.help.ui/doc/images/0.4.10/bugzilla-editor.gif org.eclipse.mylyn.help.ui/doc/images/0.4.10/bugzilla-versions.gif org.eclipse.mylyn.help.ui/doc/images/0.4.10/task-activity.gif org.eclipse.mylyn.help.ui/doc/images/0.4.10/tasklist-status.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/apply-project-explorer.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/apply-task-markers.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/colors-and-fonts.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/navigate-alt-click.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/open-task-from-history.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/query-synchronization.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/resource-history-open-task.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/task-editor-hyperlinks.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/tasklist-archive.gif org.eclipse.mylyn.help.ui/doc/images/0.5.0/tasklist-backup.gif org.eclipse.mylyn.help.ui/doc/images/0.5.1/apply-tasklist.gif org.eclipse.mylyn.help.ui/doc/images/0.5.1/context-attach-popup.gif org.eclipse.mylyn.help.ui/doc/images/0.5.1/context-retrieve.gif org.eclipse.mylyn.help.ui/doc/images/0.5.1/editors-close.gif org.eclipse.mylyn.help.ui/doc/images/0.5.1/jira-query-custom.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/bugzilla-encodings-editor.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/bugzilla-encodings-settings.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/bugzilla-search.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/changesets-model-based.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/jira-editor.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/task-repository-sync.gif org.eclipse.mylyn.help.ui/doc/images/0.5.2/tasklist-apply-mylar.gif org.eclipse.mylyn.help.ui/doc/images/dev/gray.gif org.eclipse.mylyn.help.ui/doc/images/dev/tbar_l.gif org.eclipse.mylyn.help.ui/doc/images/dev/tbar_r.gif org.eclipse.mylyn.help.ui/doc/images/faq/content-assist.gif org.eclipse.mylyn.help.ui/doc/integrating.html org.eclipse.mylyn.help.ui/doc/new-0.3.html org.eclipse.mylyn.help.ui/doc/new-0.4.html org.eclipse.mylyn.help.ui/doc/new.html org.eclipse.mylyn.help.ui/doc/overview.html Cherrypick from e_3_1 2006-02-22 01:53:31 UTC cvs2git 'This commit was manufactured by cvs2svn to create branch 'e_3_1'.': org.eclipse.mylyn.bugzilla-feature/build.properties org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskListManagerTest.java org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskListNotificationManagerTest.java org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskTestUtil.java org.eclipse.mylyn.tasks.ui/.settings/org.eclipse.pde.prefs org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF org.eclipse.mylyn.tasks.ui/plugin.xml org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ScheduledTaskListRefreshJob.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/SynchronizeReportsAction.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListNotificationManager.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListNotificationPopup.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListPatternFilter.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/AddRepositoryAction.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/OpenTaskListElementAction.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskListFilteredTree.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskListView.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskRepositoryLabelProvider.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AbstractAddExistingTaskWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AbstractRepositoryClientWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AddExistingTaskWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AddRepositoryWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/EditRepositoryWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/NewQueryWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/SelectRepositoryClientPage.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/SelectRepositoryPage.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/TaskDataImportWizard.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/util/TaskListExtensionReader.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/util/TaskListSaveManager.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/util/TaskListWriter.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryClient.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/MylarTaskListPlugin.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/TaskRepositoryManager.java Cherrypick from e_3_1 2006-04-28 23:42:30 UTC cvs2git 'This commit was manufactured by cvs2svn to create branch 'e_3_1'.': org.eclipse.mylyn.bugzilla.tests/.classpath org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/AllBugzillaTests.java org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/Bugzilla220ParserTest.java org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaConfigurationTest.java org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaProductParserTest.java org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaSearchEngineTest.java org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/ReportAttachmentTest.java org.eclipse.mylyn.bugzilla.ui/.classpath org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF org.eclipse.mylyn.bugzilla.ui/plugin.xml org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaTaskHyperlinkDetector.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaUITools.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/FavoritesView.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/AbstractBugEditor.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/ExistingBugEditor.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/RepositoryTextViewer.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/search/BugzillaSearchPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositoryConnector.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositorySettingsPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTask.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskDecorator.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskEditor.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskExternalizer.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/EditBugzillaQueryWizard.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/OpenBugzillaReportJob.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugWizard.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugzillaWizardPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/BugzillaProductPage.java org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/NewBugzillaReportWizard.java Cherrypick from e_3_1 2005-11-15 18:47:18 UTC cvs2git 'This commit was manufactured by cvs2svn to create branch 'e_3_1'.': org.eclipse.mylyn-feature/feature.xml org.eclipse.mylyn.bugzilla-feature/feature.xml Delete: org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TableSorterTest.java org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskActivityViewTest.java org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskKeyComparatorTest.java org.eclipse.mylyn.tasks.ui/build.xml org.eclipse.mylyn.tasks.ui/icons/elcl16/expandall.gif org.eclipse.mylyn.tasks.ui/icons/elcl16/filter-archive.gif org.eclipse.mylyn.tasks.ui/icons/etool16/task-notes.gif org.eclipse.mylyn.tasks.ui/icons/etool16/task-repository-notes.gif org.eclipse.mylyn.tasks.ui/icons/eview16/overlay-synchronizing.gif org.eclipse.mylyn.tasks.ui/icons/eview16/priority-1.gif org.eclipse.mylyn.tasks.ui/icons/eview16/priority-2.gif org.eclipse.mylyn.tasks.ui/icons/eview16/priority-3.gif org.eclipse.mylyn.tasks.ui/icons/eview16/priority-4.gif org.eclipse.mylyn.tasks.ui/icons/eview16/priority-5.gif org.eclipse.mylyn.tasks.ui/icons/eview16/status-conflict.gif org.eclipse.mylyn.tasks.ui/icons/eview16/status-normal.gif org.eclipse.mylyn.tasks.ui/icons/eview16/status-server-context.gif org.eclipse.mylyn.tasks.ui/icons/eview16/task-activity.gif org.eclipse.mylyn.tasks.ui/icons/wizban/banner-repository.gif org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/planner/ui/TaskPlannerLabelProvider.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/PlanningPerspectiveFactory.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskArchiveFilter.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskCompletionFilter.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListColorsAndFonts.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListImageDescriptor.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/ExpandAllAction.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/FilterArchiveContainerAction.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/NewRepositoryTaskAction.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityContentProvider.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityLabelProvider.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityView.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityViewSorter.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskKeyComparator.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskListTableSorter.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/NewRepositoryTaskPage.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractTaskContainer.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/DateRangeActivityDelegate.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/DateRangeContainer.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/ITaskListChangeListener.java org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/TaskArchive.java
-rw-r--r--org.eclipse.mylyn-feature/feature.xml86
-rw-r--r--org.eclipse.mylyn.bugzilla-feature/build.properties1
-rw-r--r--org.eclipse.mylyn.bugzilla-feature/feature.xml47
-rw-r--r--org.eclipse.mylyn.bugzilla.core/.classpath13
-rw-r--r--org.eclipse.mylyn.bugzilla.core/.settings/org.eclipse.ltk.core.refactoring.prefs3
-rw-r--r--org.eclipse.mylyn.bugzilla.core/META-INF/MANIFEST.MF18
-rw-r--r--org.eclipse.mylyn.bugzilla.core/about.html27
-rw-r--r--org.eclipse.mylyn.bugzilla.core/build.properties22
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/AbstractReportFactory.java151
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttachmentHandler.java246
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttributeFactory.java94
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaPlugin.java331
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportElement.java118
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportSubmitForm.java622
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaRepositoryUtil.java682
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskData.java284
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/IBugzillaConstants.java171
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/KeywordParser.java155
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/NewBugzillaReport.java177
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfiguration.java370
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfigurationFactory.java106
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryReportFactory.java154
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxBugReportContentHandler.java261
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxConfigurationContentHandler.java399
-rw-r--r--org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/XmlCleaner.java65
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/.classpath7
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/META-INF/MANIFEST.MF24
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/AllBugzillaTests.java45
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/Bugzilla220ParserTest.java92
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaConfigurationTest.java122
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaProductParserTest.java110
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaSearchEngineTest.java109
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaTaskHyperlinkDetectorTest.java106
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/ReportAttachmentTest.java77
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/testdata/contexts/.cvsignore1
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/testdata/contexts/empty.txt0
-rw-r--r--org.eclipse.mylyn.bugzilla.tests/testdata/pages/test-report-222attachment.html859
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/.classpath11
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF33
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/plugin.xml205
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaHyperLink.java75
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaTaskHyperlinkDetector.java69
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaUITools.java366
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/FavoritesView.java574
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/WebBrowserDialog.java65
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/AbstractBugEditor.java1649
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/ExistingBugEditor.java1083
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/RepositoryTextViewer.java125
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/search/BugzillaSearchPage.java1602
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/AbstractBugzillaQueryPage.java100
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaCustomQueryWizardPage.java129
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaQueryTypeWizardPage.java85
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositoryConnector.java732
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositorySettingsPage.java131
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTask.java176
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskDecorator.java55
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskEditor.java295
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskExternalizer.java265
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/EditBugzillaQueryWizard.java100
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/NewBugzillaQueryWizard.java98
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/OpenBugzillaReportJob.java48
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugWizard.java209
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugzillaWizardPage.java770
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/BugzillaProductPage.java260
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/NewBugzillaReportWizard.java128
-rw-r--r--org.eclipse.mylyn.help.ui/.externalToolBuilders/org.eclipse.jdt.core.javabuilder.launch7
-rw-r--r--org.eclipse.mylyn.help.ui/.project22
-rw-r--r--org.eclipse.mylyn.help.ui/.settings/org.eclipse.ltk.core.refactoring.prefs3
-rw-r--r--org.eclipse.mylyn.help.ui/META-INF/MANIFEST.MF8
-rw-r--r--org.eclipse.mylyn.help.ui/about.html27
-rw-r--r--org.eclipse.mylyn.help.ui/doc/contributing.html176
-rw-r--r--org.eclipse.mylyn.help.ui/doc/dev/changes.html12395
-rw-r--r--org.eclipse.mylyn.help.ui/doc/dev/dependencies.vsdbin0 -> 42496 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/dev/index.html20
-rw-r--r--org.eclipse.mylyn.help.ui/doc/dev/model.vsdbin0 -> 144384 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/dev/plan.html371
-rw-r--r--org.eclipse.mylyn.help.ui/doc/faq.html486
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.4.10/bugzilla-editor.gifbin0 -> 7895 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.4.10/bugzilla-versions.gifbin0 -> 4141 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.4.10/task-activity.gifbin0 -> 12445 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.4.10/tasklist-status.gifbin0 -> 17872 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/apply-project-explorer.gifbin0 -> 8954 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/apply-task-markers.gifbin0 -> 8943 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/colors-and-fonts.gifbin0 -> 11573 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/navigate-alt-click.gifbin0 -> 6499 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/open-task-from-history.gifbin0 -> 13133 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/query-synchronization.gifbin0 -> 3880 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/resource-history-open-task.gifbin0 -> 10298 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/task-editor-hyperlinks.gifbin0 -> 12552 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/tasklist-archive.gifbin0 -> 13441 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.0/tasklist-backup.gifbin0 -> 4296 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.1/apply-tasklist.gifbin0 -> 10232 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.1/context-attach-popup.gifbin0 -> 8868 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.1/context-retrieve.gifbin0 -> 15495 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.1/editors-close.gifbin0 -> 4448 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.1/jira-query-custom.gifbin0 -> 9627 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/bugzilla-encodings-editor.gifbin0 -> 3263 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/bugzilla-encodings-settings.gifbin0 -> 12522 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/bugzilla-search.gifbin0 -> 10283 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/changesets-model-based.gifbin0 -> 15052 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/jira-editor.gifbin0 -> 13519 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/task-repository-sync.gifbin0 -> 7361 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/0.5.2/tasklist-apply-mylar.gifbin0 -> 19255 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/dev/gray.gifbin0 -> 35 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/dev/tbar_l.gifbin0 -> 76 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/dev/tbar_r.gifbin0 -> 76 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/images/faq/content-assist.gifbin0 -> 23060 bytes
-rw-r--r--org.eclipse.mylyn.help.ui/doc/integrating.html80
-rw-r--r--org.eclipse.mylyn.help.ui/doc/new-0.3.html711
-rw-r--r--org.eclipse.mylyn.help.ui/doc/new-0.4.html1053
-rw-r--r--org.eclipse.mylyn.help.ui/doc/new.html407
-rw-r--r--org.eclipse.mylyn.help.ui/doc/overview.html69
-rw-r--r--org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TableSorterTest.java35
-rw-r--r--org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskActivityViewTest.java344
-rw-r--r--org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskKeyComparatorTest.java64
-rw-r--r--org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskListManagerTest.java125
-rw-r--r--org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskListNotificationManagerTest.java3
-rw-r--r--org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasklist/tests/TaskTestUtil.java5
-rw-r--r--org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.mylyn.tasks.ui/build.xml70
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/elcl16/expandall.gifbin164 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/elcl16/filter-archive.gifbin350 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/etool16/task-notes.gifbin220 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/etool16/task-repository-notes.gifbin337 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/overlay-synchronizing.gifbin179 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/priority-1.gifbin154 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/priority-2.gifbin133 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/priority-3.gifbin55 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/priority-4.gifbin190 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/priority-5.gifbin199 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/status-conflict.gifbin202 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/status-normal.gifbin55 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/status-server-context.gifbin175 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/eview16/task-activity.gifbin581 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/icons/wizban/banner-repository.gifbin2749 -> 0 bytes
-rw-r--r--org.eclipse.mylyn.tasks.ui/plugin.xml34
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ScheduledTaskListRefreshJob.java6
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/planner/ui/TaskPlannerLabelProvider.java83
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/PlanningPerspectiveFactory.java59
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/SynchronizeReportsAction.java14
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskArchiveFilter.java26
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskCompletionFilter.java42
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListColorsAndFonts.java54
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListImageDescriptor.java95
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListNotificationManager.java130
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListNotificationPopup.java453
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskListPatternFilter.java2
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/AddRepositoryAction.java1
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/ExpandAllAction.java42
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/FilterArchiveContainerAction.java50
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/NewRepositoryTaskAction.java83
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/actions/OpenTaskListElementAction.java10
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityContentProvider.java84
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityLabelProvider.java142
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityView.java580
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskActivityViewSorter.java193
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskKeyComparator.java58
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskListFilteredTree.java81
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskListTableSorter.java90
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskListView.java3
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/views/TaskRepositoryLabelProvider.java10
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AbstractAddExistingTaskWizard.java6
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AbstractRepositoryClientWizard.java8
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AddExistingTaskWizard.java11
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/AddRepositoryWizard.java2
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/EditRepositoryWizard.java6
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/NewQueryWizard.java6
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/NewRepositoryTaskPage.java36
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/SelectRepositoryClientPage.java6
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/SelectRepositoryPage.java28
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/wizards/TaskDataImportWizard.java7
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/util/TaskListExtensionReader.java12
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/util/TaskListSaveManager.java44
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/util/TaskListWriter.java29
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryClient.java (renamed from org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java)12
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractTaskContainer.java100
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/DateRangeActivityDelegate.java259
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/DateRangeContainer.java212
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/ITaskListChangeListener.java42
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/MylarTaskListPlugin.java15
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/TaskArchive.java45
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/TaskRepositoryManager.java38
182 files changed, 31934 insertions, 3491 deletions
diff --git a/org.eclipse.mylyn-feature/feature.xml b/org.eclipse.mylyn-feature/feature.xml
index e936c5343..a95b188f3 100644
--- a/org.eclipse.mylyn-feature/feature.xml
+++ b/org.eclipse.mylyn-feature/feature.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="org.eclipse.mylar_feature"
- label="Mylar Task List (Required)"
- version="0.4.9"
+ label="Mylar IDE Integration"
+ version="0.4.2"
provider-name="Eclipse.org"
plugin="org.eclipse.mylar">
<description url="http://eclipse.org/mylar">
- Mylar Task List, personal task management facilities, and task repository integration support.
+ Mylar UI and support for the Eclipse SDK.
</description>
<license url="http://www.eclipse.org/legal/epl-v10.html">
@@ -214,39 +214,103 @@ litigation.
</url>
<requires>
- <import plugin="org.eclipse.core.runtime" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.ui" version="3.1.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.core.runtime" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.core.resources" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.ui.browser"/>
+ <import plugin="org.eclipse.jdt" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.jdt.core" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui.editors" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.jface.text" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui.workbench.texteditor" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.search" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui.views" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.jdt.debug.ui"/>
+ <import plugin="org.eclipse.jdt.ui" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.team.cvs.ui"/>
+ <import plugin="org.eclipse.debug.ui"/>
+ <import plugin="org.eclipse.jdt.junit"/>
+ <import plugin="org.eclipse.jdt.junit.runtime"/>
+ <import plugin="org.eclipse.pde.junit.runtime"/>
+ <import plugin="org.eclipse.jdt.launching"/>
+ <import plugin="org.eclipse.debug.core"/>
+ <import plugin="org.eclipse.pde.ui" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.pde.core" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui.ide" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ant.ui" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.ui.forms" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.update.ui"/>
+ <import plugin="org.eclipse.update.core"/>
+ <import plugin="org.eclipse.ui.browser"/>
</requires>
<plugin
id="org.eclipse.mylar.doc"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2"
unpack="false"/>
<plugin
- id="org.eclipse.mylar"
+ id="org.eclipse.mylar.java"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2"
unpack="false"/>
<plugin
- id="org.eclipse.mylar.core"
+ id="org.eclipse.mylar.ui"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.xml"
+ download-size="0"
+ install-size="0"
+ version="0.4.2"
unpack="false"/>
<plugin
id="org.eclipse.mylar.tasklist"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.ide"
+ download-size="0"
+ install-size="0"
+ version="0.4.2"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.monitor"
+ download-size="0"
+ install-size="0"
+ version="0.4.2"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.hypertext"
+ download-size="0"
+ install-size="0"
+ version="0.4.2"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.core"
+ download-size="0"
+ install-size="0"
+ version="0.4.2"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar"
+ download-size="0"
+ install-size="0"
+ version="0.4.2"
unpack="false"/>
</feature>
diff --git a/org.eclipse.mylyn.bugzilla-feature/build.properties b/org.eclipse.mylyn.bugzilla-feature/build.properties
index 69b877f71..4e728a03d 100644
--- a/org.eclipse.mylyn.bugzilla-feature/build.properties
+++ b/org.eclipse.mylyn.bugzilla-feature/build.properties
@@ -16,4 +16,3 @@ src.includes = epl-v10.html,\
feature.xml,\
license.html,\
about.html
-jre.compilation.profile = J2SE-1.5
diff --git a/org.eclipse.mylyn.bugzilla-feature/feature.xml b/org.eclipse.mylyn.bugzilla-feature/feature.xml
index 87a83fb55..2147b6f37 100644
--- a/org.eclipse.mylyn.bugzilla-feature/feature.xml
+++ b/org.eclipse.mylyn.bugzilla-feature/feature.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="org.eclipse.mylar.bugzilla_feature"
- label="Mylar Connector: Bugzilla"
- version="0.4.9"
+ label="Mylar Bugzilla Client"
+ version="0.4.2.1"
provider-name="Eclipse.org"
- plugin="org.eclipse.mylar">
+ plugin="org.eclipse.mylar.bugzilla.core">
<description>
Bugzilla client integrated with Eclipse and Mylar, can be used standalone.
@@ -210,51 +210,58 @@ litigation.
</license>
<url>
- <update label="Mylar for Eclipse 3.1" url="http://download.eclipse.org/technology/mylar/update-site/e3.1"/>
+ <update label="Mylar Bugzilla Client" url="http://download.eclipse.org/technology/mylar/update-site/e3.2"/>
</url>
<requires>
- <import feature="org.eclipse.mylar_feature" version="0.4.9" match="greaterOrEqual"/>
- <import plugin="org.eclipse.ui" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.core.runtime" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.core.resources" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.compare" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.search" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.help" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.help.ui" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.core.runtime" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.ui.ide" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.update.core"/>
- <import plugin="org.eclipse.update.ui"/>
<import plugin="org.eclipse.ui.views" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.ui.forms"/>
<import plugin="org.eclipse.jface.text" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.team.ui"/>
- <import plugin="org.eclipse.team.cvs.ui"/>
<import plugin="org.eclipse.ui.workbench.texteditor" version="0.0.0" match="greaterOrEqual"/>
<import plugin="org.eclipse.ui.editors" version="0.0.0" match="greaterOrEqual"/>
- <import plugin="org.eclipse.team.core"/>
- <import plugin="org.eclipse.team.cvs.core"/>
- <import plugin="org.eclipse.mylar.core"/>
- <import plugin="org.eclipse.mylar.tasklist"/>
+ <import plugin="org.eclipse.pde.ui" version="0.0.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.compare" version="0.0.0" match="greaterOrEqual"/>
</requires>
<plugin
id="org.eclipse.mylar.bugzilla.core"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2.1"
unpack="false"/>
<plugin
id="org.eclipse.mylar.bugzilla.ui"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2.1"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.core"
+ download-size="0"
+ install-size="0"
+ version="0.4.2.1"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylar.tasklist"
+ download-size="0"
+ install-size="0"
+ version="0.4.2.1"
unpack="false"/>
<plugin
id="org.eclipse.mylar.bugs"
download-size="0"
install-size="0"
- version="0.4.9"
+ version="0.4.2.1"
unpack="false"/>
</feature>
diff --git a/org.eclipse.mylyn.bugzilla.core/.classpath b/org.eclipse.mylyn.bugzilla.core/.classpath
new file mode 100644
index 000000000..fd8d0f145
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins">
+ <accessrules>
+ <accessrule kind="accessible" pattern="**/internal/**"/>
+ <accessrule kind="nonaccessible" pattern="**/System"/>
+ </accessrules>
+ </classpathentry>
+ <classpathentry kind="lib" path="lib/commons-httpclient-3.0.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.mylyn.bugzilla.core/.settings/org.eclipse.ltk.core.refactoring.prefs b/org.eclipse.mylyn.bugzilla.core/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 000000000..bbebc5a04
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Fri Jun 02 15:30:24 PDT 2006
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=true
diff --git a/org.eclipse.mylyn.bugzilla.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.bugzilla.core/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..38545f58f
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Mylar Bugzilla Client Plug-in
+Bundle-SymbolicName: org.eclipse.mylar.bugzilla.core; singleton:=true
+Bundle-Version: 0.5.3
+Bundle-Activator: org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.mylar.tasklist
+Eclipse-AutoStart: true
+Bundle-Vendor: Eclipse.org
+Bundle-ClassPath: bugzilla-core.jar,
+ lib/commons-logging.jar,
+ lib/commons-codec-1.3.jar,
+ lib/commons-httpclient-3.0.jar
+Export-Package: org.apache.commons.httpclient,
+ org.eclipse.mylar.internal.bugzilla.core
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/org.eclipse.mylyn.bugzilla.core/about.html b/org.eclipse.mylyn.bugzilla.core/about.html
new file mode 100644
index 000000000..1aeb16b5f
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/about.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html>
+<head>
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>May 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.core/build.properties b/org.eclipse.mylyn.bugzilla.core/build.properties
new file mode 100644
index 000000000..c4bc1a8a8
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/build.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2003 - 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
+###############################################################################
+bin.includes = META-INF/,\
+ about.html,\
+ bugzilla-core.jar,\
+ lib/
+src.includes = META-INF/,\
+ src/,\
+ about.html,\
+ lib/
+jars.compile.order = bugzilla-core.jar
+source.bugzilla-core.jar = src/
+output.bugzilla-core.jar = bin/
+jre.compilation.profile = J2SE-1.5
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/AbstractReportFactory.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/AbstractReportFactory.java
new file mode 100644
index 000000000..c578009f1
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/AbstractReportFactory.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.security.auth.login.LoginException;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * @author Rob Elves
+ */
+public class AbstractReportFactory {
+
+ private static final int COM_TIME_OUT = 15000;
+
+ private static final String CONTENT_TYPE_TEXT_HTML = "text/html";
+
+ private static final String CONTENT_TYPE_APP_RDF_XML = "application/rdf+xml";
+
+ private static final String CONTENT_TYPE_APP_XML = "application/xml";
+
+ private static final String CONTENT_TYPE_TEXT_XML = "text/xml";
+
+ public static final int RETURN_ALL_HITS = -1;
+
+ private BufferedReader in = null;
+
+ private boolean clean = false;
+
+ protected void collectResults(URL url, Proxy proxySettings, String characterEncoding, DefaultHandler contentHandler)
+ throws IOException, LoginException, KeyManagementException, NoSuchAlgorithmException {
+ URLConnection cntx = BugzillaPlugin.getUrlConnection(url, proxySettings);
+ if (cntx == null || !(cntx instanceof HttpURLConnection)) {
+ throw new IOException("Could not form URLConnection.");
+ }
+
+ HttpURLConnection connection = (HttpURLConnection) cntx;
+ connection.setConnectTimeout(COM_TIME_OUT);
+ connection.setReadTimeout(COM_TIME_OUT);
+ connection.connect();
+ int responseCode = connection.getResponseCode();
+ if (responseCode != HttpURLConnection.HTTP_OK) {
+ String msg;
+ if (responseCode == -1 || responseCode == HttpURLConnection.HTTP_FORBIDDEN)
+ msg = "Repository does not seem to be a valid Bugzilla server: " + url.toExternalForm();
+ else
+ msg = "HTTP Error " + responseCode + " (" + connection.getResponseMessage()
+ + ") while querying Bugzilla server: " + url.toExternalForm();
+
+ throw new IOException(msg);
+ }
+
+ if (characterEncoding != null) {
+ in = new BufferedReader(new InputStreamReader(connection.getInputStream(), characterEncoding));
+ } else {
+ in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+ }
+
+
+
+ if(clean) {
+ StringBuffer result = XmlCleaner.clean(in);
+ StringReader strReader = new StringReader(result.toString());
+ in = new BufferedReader(strReader);
+ }
+
+ if (connection.getContentType().contains(CONTENT_TYPE_APP_RDF_XML)
+ || connection.getContentType().contains(CONTENT_TYPE_APP_XML)
+ || connection.getContentType().contains(CONTENT_TYPE_TEXT_XML)) {
+
+ try {
+ final XMLReader reader = XMLReaderFactory.createXMLReader();
+ reader.setContentHandler(contentHandler);
+ reader.setErrorHandler(new ErrorHandler() {
+
+ public void error(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+
+ public void warning(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+ });
+ reader.parse(new InputSource(in));
+ } catch (SAXException e) {
+ if (e.getMessage().equals(IBugzillaConstants.ERROR_INVALID_USERNAME_OR_PASSWORD)) {
+ throw new LoginException(e.getMessage());
+ } else {
+ throw new IOException(e.getMessage());
+ }
+ }
+ } else if (connection.getContentType().contains(CONTENT_TYPE_TEXT_HTML)) {
+ in.mark(10);
+ BugzillaRepositoryUtil.parseHtmlError(in);
+ in.reset();
+ String message = "";
+ String newLine = in.readLine();
+ while (newLine != null) {
+ message += newLine;
+ newLine = in.readLine();
+ }
+ throw new UnrecognizedBugzillaError(message);
+
+ } else {
+ throw new IOException("Unrecognized content type: " + connection.getContentType());
+ }
+ }
+
+ public class UnrecognizedBugzillaError extends IOException {
+ private static final long serialVersionUID = 8419167415822022988L;
+
+ public UnrecognizedBugzillaError(String message) {
+ super(message);
+ }
+ }
+
+ protected void setClean(boolean clean) {
+ this.clean = clean;
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttachmentHandler.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttachmentHandler.java
new file mode 100644
index 000000000..240278945
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttachmentHandler.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.multipart.FilePart;
+import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
+import org.apache.commons.httpclient.methods.multipart.Part;
+import org.apache.commons.httpclient.methods.multipart.PartBase;
+import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylar.internal.tasklist.LocalAttachment;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask;
+import org.eclipse.mylar.provisional.tasklist.IAttachmentHandler;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+
+/**
+ * @author Mik Kersten
+ * @author Rob Elves
+ */
+public class BugzillaAttachmentHandler implements IAttachmentHandler {
+
+ public static final String POST_ARGS_ATTACHMENT_DOWNLOAD = "/attachment.cgi?id=";
+
+ public static final String POST_ARGS_ATTACHMENT_UPLOAD = "/attachment.cgi";// ?action=insert";//&bugid=";
+
+ private static final String VALUE_CONTENTTYPEMETHOD_MANUAL = "manual";
+
+ private static final String VALUE_ISPATCH = "1";
+
+ private static final String VALUE_ACTION_INSERT = "insert";
+
+ private static final String ATTRIBUTE_CONTENTTYPEENTRY = "contenttypeentry";
+
+ private static final String ATTRIBUTE_CONTENTTYPEMETHOD = "contenttypemethod";
+
+ private static final String ATTRIBUTE_ISPATCH = "ispatch";
+
+ private static final String ATTRIBUTE_DATA = "data";
+
+ private static final String ATTRIBUTE_COMMENT = "comment";
+
+ private static final String ATTRIBUTE_DESCRIPTION = "description";
+
+ private static final String ATTRIBUTE_BUGID = "bugid";
+
+ private static final String ATTRIBUTE_BUGZILLA_PASSWORD = "Bugzilla_password";
+
+ private static final String ATTRIBUTE_BUGZILLA_LOGIN = "Bugzilla_login";
+
+ private static final String ATTRIBUTE_ACTION = "action";
+
+ public void downloadAttachment(TaskRepository repository, AbstractRepositoryTask task, int attachmentId, File file, Proxy proxySettings) throws CoreException {
+ try {
+ downloadAttachment(repository.getUrl(), repository.getUserName(), repository.getPassword(), proxySettings, attachmentId, file, true);
+ } catch (Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID, 0, "could not download", e));
+ }
+ }
+
+ public void uploadAttachment(TaskRepository repository, AbstractRepositoryTask task, String comment, String description, File file, String contentType, boolean isPatch, Proxy proxySettings) throws CoreException {
+ try {
+ uploadAttachment(repository.getUrl(), repository.getUserName(), repository.getPassword(), AbstractRepositoryTask.getTaskIdAsInt(task.getHandleIdentifier()), comment, description, file, contentType, isPatch, proxySettings);
+ } catch (Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID, 0, "could not download", e));
+ }
+ }
+
+ private boolean uploadAttachment(String repositoryUrl, String userName, String password, int bugReportID,
+ String comment, String description, File sourceFile, String contentType, boolean isPatch, Proxy proxySettings)
+ throws IOException {
+
+ // Note: The following debug code requires http commons-logging and
+ // commons-logging-api jars
+ // System.setProperty("org.apache.commons.logging.Log",
+ // "org.apache.commons.logging.impl.SimpleLog");
+ // System.setProperty("org.apache.commons.logging.simplelog.showdatetime",
+ // "true");
+ // System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire",
+ // "debug");
+ // System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient",
+ // "debug");
+
+ boolean uploadResult = true;
+
+ HttpClient client = new HttpClient();
+ if (proxySettings != null && proxySettings.address() instanceof InetSocketAddress) {
+ InetSocketAddress address = (InetSocketAddress)proxySettings.address();
+ client.getHostConfiguration().setProxy(address.getHostName(), address.getPort());
+ }
+
+ PostMethod postMethod = new PostMethod(repositoryUrl + POST_ARGS_ATTACHMENT_UPLOAD);
+
+ // My understanding is that this option causes the client to first check
+ // with the server to see if it will in fact recieve the post before
+ // actually sending the contents.
+ postMethod.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true);
+
+ try {
+ List<PartBase> parts = new ArrayList<PartBase>();
+ parts.add(new StringPart(ATTRIBUTE_ACTION, VALUE_ACTION_INSERT));
+ parts.add(new StringPart(ATTRIBUTE_BUGZILLA_LOGIN, userName));
+ parts.add(new StringPart(ATTRIBUTE_BUGZILLA_PASSWORD, password));
+ parts.add(new StringPart(ATTRIBUTE_BUGID, String.valueOf(bugReportID)));
+ parts.add(new StringPart(ATTRIBUTE_DESCRIPTION, description));
+ parts.add(new StringPart(ATTRIBUTE_COMMENT, comment));
+ parts.add(new FilePart(ATTRIBUTE_DATA, sourceFile));
+
+ if (isPatch) {
+ parts.add(new StringPart(ATTRIBUTE_ISPATCH, VALUE_ISPATCH));
+ } else {
+ parts.add(new StringPart(ATTRIBUTE_CONTENTTYPEMETHOD, VALUE_CONTENTTYPEMETHOD_MANUAL));
+ parts.add(new StringPart(ATTRIBUTE_CONTENTTYPEENTRY, contentType));
+ }
+
+ postMethod.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[1]), postMethod.getParams()));
+
+ client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
+ int status = client.executeMethod(postMethod);
+ if (status == HttpStatus.SC_OK) {
+ InputStreamReader reader = new InputStreamReader(postMethod.getResponseBodyAsStream(), postMethod
+ .getResponseCharSet());
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String newLine;
+ while ((newLine = bufferedReader.readLine()) != null) {
+ if (newLine.indexOf("Invalid Username Or Password") >= 0) {
+ throw new IOException(
+ "Invalid Username Or Password - Check credentials in Task Repositories view.");
+ }
+ // TODO: test for no comment and no description etc.
+ }
+ } else {
+ // MylarStatusHandler.log(HttpStatus.getStatusText(status),
+ // BugzillaRepositoryUtil.class);
+ uploadResult = false;
+ }
+ // } catch (HttpException e) {
+ // MylarStatusHandler.log("Attachment upload failed\n" +
+ // e.getMessage(), BugzillaRepositoryUtil.class);
+ // uploadResult = false;
+ } finally {
+ postMethod.releaseConnection();
+ }
+
+ return uploadResult;
+ }
+
+
+ public boolean uploadAttachment(LocalAttachment attachment, String uname, String password, Proxy proxySettings) throws IOException {
+
+ File file = new File(attachment.getFilePath());
+ if (!file.exists() || file.length() <= 0) {
+ return false;
+ }
+
+ return uploadAttachment(attachment.getReport().getRepositoryUrl(), uname, password, attachment.getReport().getId(),
+ attachment.getComment(), attachment.getDescription(), file,
+ attachment.getContentType(), attachment.isPatch(), proxySettings);
+ }
+
+ private boolean downloadAttachment(String repositoryUrl, String userName, String password,
+ Proxy proxySettings, int id, File destinationFile, boolean overwrite) throws IOException,
+ GeneralSecurityException {
+ BufferedInputStream in = null;
+ FileOutputStream outStream = null;
+ try {
+ String url = repositoryUrl + POST_ARGS_ATTACHMENT_DOWNLOAD + id;
+ url = BugzillaRepositoryUtil.addCredentials(url, userName, password);
+ URL downloadUrl = new URL(url);
+ URLConnection connection = BugzillaPlugin.getUrlConnection(downloadUrl, proxySettings);
+ if (connection != null) {
+ InputStream input = connection.getInputStream();
+ outStream = new FileOutputStream(destinationFile);
+ copyByteStream(input, outStream);
+ return true;
+
+ }
+ } finally {
+ try {
+ if (in != null)
+ in.close();
+ if (outStream != null)
+ outStream.close();
+ } catch (IOException e) {
+ BugzillaPlugin.log(new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID, IStatus.ERROR,
+ "Problem closing the stream", e));
+ }
+ }
+ return false;
+ }
+
+ private void copyByteStream(InputStream in, OutputStream out) throws IOException {
+ if (in != null && out != null) {
+ BufferedInputStream inBuffered = new BufferedInputStream(in);
+
+ int bufferSize = 1000;
+ byte[] buffer = new byte[bufferSize];
+
+ int readCount;
+
+ BufferedOutputStream fout = new BufferedOutputStream(out);
+
+ while ((readCount = inBuffered.read(buffer)) != -1) {
+ if (readCount < bufferSize) {
+ fout.write(buffer, 0, readCount);
+ } else {
+ fout.write(buffer);
+ }
+ }
+ fout.flush();
+ fout.close();
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttributeFactory.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttributeFactory.java
new file mode 100644
index 000000000..62b15e9d7
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttributeFactory.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import org.eclipse.mylar.internal.tasklist.AbstractAttributeFactory;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttribute;
+
+public class BugzillaAttributeFactory extends AbstractAttributeFactory {
+
+ private static final long serialVersionUID = 5087501781682994759L;
+
+ @Override
+ public String mapCommonAttributeKey(String key) {
+ if (key == null) {
+ return key;
+ } else if (key.equals(RepositoryTaskAttribute.COMMENT_DATE)) {
+ return BugzillaReportElement.BUG_WHEN.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.USER_OWNER)) {
+ return BugzillaReportElement.WHO.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.USER_CC)) {
+ return BugzillaReportElement.CC.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.COMMENT_TEXT)) {
+ return BugzillaReportElement.THETEXT.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.DATE_CREATION)) {
+ return BugzillaReportElement.CREATION_TS.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.DESCRIPTION)) {
+ return BugzillaReportElement.DESC.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.ATTACHMENT_ID)) {
+ return BugzillaReportElement.ATTACHID.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.ATTACHMENT_TYPE)) {
+ return BugzillaReportElement.TYPE.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.ATTACHMENT_CTYPE)) {
+ return BugzillaReportElement.CTYPE.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.USER_ASSIGNED)) {
+ return BugzillaReportElement.ASSIGNED_TO.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.RESOLUTION)) {
+ return BugzillaReportElement.RESOLUTION.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.STATUS)) {
+ return BugzillaReportElement.BUG_STATUS.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.DATE_MODIFIED)) {
+ return BugzillaReportElement.DELTA_TS.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.USER_REPORTER)) {
+ return BugzillaReportElement.REPORTER.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.SUMMARY)) {
+ return BugzillaReportElement.SHORT_DESC.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.PRODUCT)) {
+ return BugzillaReportElement.PRODUCT.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.DATE_CREATION)) {
+ return BugzillaReportElement.CREATION_TS.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.KEYWORDS)) {
+ return BugzillaReportElement.KEYWORDS.getKeyString();
+ } else if (key.equals(RepositoryTaskAttribute.ATTACHMENT_DATE)) {
+ return BugzillaReportElement.DATE.getKeyString();
+ }
+ return key;
+ }
+
+ @Override
+ public boolean getIsHidden(String key) {
+ try {
+ return BugzillaReportElement.valueOf(key.trim().toUpperCase()).isHidden();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public String getName(String key) {
+ try {
+ return BugzillaReportElement.valueOf(key.trim().toUpperCase()).toString();
+ } catch (IllegalArgumentException e) {
+ return "<unknown>";
+ }
+ }
+
+ @Override
+ public boolean isReadOnly(String key) {
+ try {
+ return BugzillaReportElement.valueOf(key.trim().toUpperCase()).isReadOnly();
+ } catch (IllegalArgumentException e) {
+ return true;
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaPlugin.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaPlugin.java
new file mode 100644
index 000000000..bdaab80ad
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaPlugin.java
@@ -0,0 +1,331 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The main plugin class to be used in the desktop.
+ *
+ * @author Mik Kersten (added support for multiple repositories)
+ */
+public class BugzillaPlugin extends Plugin {
+
+ public static final String REPOSITORY_KIND = "bugzilla";
+
+ public static final String ENCODING_UTF_8 = "UTF-8";
+
+ public static final String PLUGIN_ID = "org.eclipse.mylar.bugzilla";
+
+ /** Singleton instance of the plug-in */
+ private static BugzillaPlugin plugin;
+
+ // /** The file that contains all of the bugzilla favorites */
+ // private FavoritesFile favoritesFile;
+
+ /** Product configuration for the current server */
+ private static Map<String, RepositoryConfiguration> repositoryConfigurations = new HashMap<String, RepositoryConfiguration>();
+
+ public BugzillaPlugin() {
+ super();
+ }
+
+ /**
+ * Get the singleton instance for the plugin
+ *
+ * @return The instance of the plugin
+ */
+ public static BugzillaPlugin getDefault() {
+ return plugin;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+
+ // readFavoritesFile();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ // /**
+ // * Get the favorites file contatining the favorites
+ // *
+ // * @return The FavoritesFile
+ // */
+ // public FavoritesFile getFavorites() {
+ // return favoritesFile;
+ // }
+
+ // /**
+ // * // * Get the name of the bugzilla server // * // *
+ // *
+ // * @return A string containing the prefered name of the bugzilla server //
+ // */
+ // // public String getServerName() {
+ // // return
+ // //
+ // plugin.getPreferenceStore().getString(IBugzillaConstants.BUGZILLA_SERVER);
+ // // }
+ // public boolean isServerCompatability218() {
+ // return
+ // IBugzillaConstants.SERVER_218.equals(getPreferenceStore().getString(IBugzillaConstants.SERVER_VERSION))
+ // || IBugzillaConstants.SERVER_220.equals(getPreferenceStore().getString(
+ // IBugzillaConstants.SERVER_VERSION));
+ // }
+ //
+ // public boolean isServerCompatability220() {
+ // return
+ // IBugzillaConstants.SERVER_220.equals(getPreferenceStore().getString(IBugzillaConstants.SERVER_VERSION));
+ // }
+
+ public static RepositoryConfiguration getRepositoryConfiguration(String repositoryUrl, Proxy proxySettings, String userName, String password, String encoding) throws IOException, KeyManagementException, LoginException, NoSuchAlgorithmException {
+ if (!repositoryConfigurations.containsKey(repositoryUrl)) {
+ repositoryConfigurations.put(repositoryUrl, RepositoryConfigurationFactory.getInstance()
+ .getConfiguration(repositoryUrl, proxySettings, userName, password, encoding));
+ }
+ return repositoryConfigurations.get(repositoryUrl);
+ }
+
+ // public RepositoryConfiguration getProductConfiguration(String serverUrl)
+ // {
+ // if (!repositoryConfigurations.containsKey(serverUrl)) {
+ // try {
+ // repositoryConfigurations.put(serverUrl,
+ // RepositoryConfigurationFactory.getInstance().getConfiguration(
+ // serverUrl));
+ // } catch (IOException e) {
+ // MessageDialog.openInformation(null, "Retrieval of Bugzilla
+ // Configuration",
+ // "Bugzilla configuration retrieval failed.");
+ // }
+ // }
+ //
+ // return repositoryConfigurations.get(serverUrl);
+ // }
+
+ // protected void setProductConfiguration(String serverUrl,
+ // RepositoryConfiguration repositoryConfiguration) {
+ // repositoryConfigurations.put(serverUrl, repositoryConfiguration);
+ // // this.productConfiguration = productConfiguration;
+ // }
+
+ // private void readFavoritesFile() {
+ // IPath favoritesPath = getFavoritesFile();
+ //
+ // try {
+ // favoritesFile = new FavoritesFile(favoritesPath.toFile());
+ // } catch (Exception e) {
+ // logAndShowExceptionDetailsDialog(e, "occurred while restoring saved
+ // Bugzilla favorites.",
+ // "Bugzilla Favorites Error");
+ // }
+ // }
+
+ // /**
+ // * Returns the path to the file cacheing the query favorites.
+ // */
+ // private IPath getFavoritesFile() {
+ // IPath stateLocation =
+ // Platform.getStateLocation(BugzillaPlugin.getDefault().getBundle());
+ // IPath configFile = stateLocation.append("favorites");
+ // return configFile;
+ // }
+
+ // /**
+ // * Reads cached product configuration and stores it in the
+ // * <code>productConfiguration</code> field.
+ // *
+ // * TODO remove this?
+ // */
+ // private void readCachedProductConfiguration(String serverUrl) {
+ // IPath configFile = getProductConfigurationCachePath(serverUrl);
+ //
+ // try {
+ // productConfigurations.put(serverUrl,
+ // ServerConfigurationFactory.getInstance().readConfiguration(
+ // configFile.toFile()));
+ // } catch (IOException ex) {
+ // try {
+ // log(ex);
+ // productConfigurations.put(serverUrl,
+ // ServerConfigurationFactory.getInstance().getConfiguration(
+ // serverUrl));
+ // } catch (IOException e) {
+ // log(e);
+ // MessageDialog
+ // .openInformation(
+ // null,
+ // "Bugzilla product attributes check",
+ // "An error occurred while restoring saved Bugzilla product attributes:
+ // \n\n"
+ // + ex.getMessage()
+ // + "\n\nUpdating them from the server also caused an error:\n\n"
+ // + e.getMessage()
+ // + "\n\nCheck the server URL in Bugzila preferences.\n"
+ // + "Offline submission of new bugs will be disabled until valid product
+ // attributes have been loaded.");
+ // }
+ // }
+ // }
+
+ /**
+ * Returns the path to the file cacheing the product configuration.
+ */
+ protected IPath getProductConfigurationCachePath(String serverUrl) {
+ IPath stateLocation = Platform.getStateLocation(BugzillaPlugin.getDefault().getBundle());
+ IPath configFile = stateLocation.append("productConfig." + serverUrl.replace('/', '-'));
+ return configFile;
+ }
+
+ /**
+ * Convenience method for logging statuses to the plugin log
+ *
+ * @param status
+ * the status to log
+ */
+ public static void log(IStatus status) {
+ getDefault().getLog().log(status);
+ }
+
+ /**
+ * Convenience method for logging exceptions to the plugin log
+ *
+ * @param e
+ * the exception to log
+ */
+ public static void log(Exception e) {
+ log(new Status(Status.ERROR, BugzillaPlugin.PLUGIN_ID, 0, e.getMessage(), e));
+ }
+
+ /**
+ * Returns the path to the file caching bug reports created while offline.
+ */
+ protected IPath getCachedBugReportPath() {
+ IPath stateLocation = Platform.getStateLocation(BugzillaPlugin.getDefault().getBundle());
+ IPath bugFile = stateLocation.append("bugReports");
+ return bugFile;
+ }
+
+ /**
+ * @param url
+ * @param proxy
+ * can be null
+ */
+ public static URLConnection getUrlConnection(URL url, Proxy proxy) throws IOException, NoSuchAlgorithmException,
+ KeyManagementException {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+
+ javax.net.ssl.TrustManager[] tm = new javax.net.ssl.TrustManager[] { new TrustAll() };
+ ctx.init(null, tm, null);
+ HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
+
+ if (proxy == null) {
+ proxy = Proxy.NO_PROXY;
+ }
+ URLConnection connection = url.openConnection(proxy);
+ return connection;
+ }
+
+ // public IStatus logAndShowExceptionDetailsDialog(Exception e, String
+ // message, String title) {
+ // MultiStatus status = new MultiStatus(BugzillaPlugin.PLUGIN_ID,
+ // IStatus.ERROR, e.getClass().toString() + " "
+ // + message + "\n\n" + "Click Details or see log for more information.",
+ // e);
+ // Status s = new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID,
+ // IStatus.ERROR, e.getClass().toString()
+ // + ": ", e);
+ // status.add(s);
+ // String error = (e.getMessage() == null) ? e.getClass().toString() :
+ // e.getMessage();
+ // s = new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID, IStatus.ERROR,
+ // error, e);
+ // status.add(s);
+ // log(status);
+ // ErrorDialog.openError(null, title, null, status);
+ // return status;
+ // }
+
+ // public boolean refreshOnStartUpEnabled() {
+ // return getPreferenceStore().getBoolean(IBugzillaConstants.REFRESH_QUERY);
+ // }
+
+ // private void setDefaultQueryOptions() {
+ // // get the preferences store for the bugzilla preferences
+ // IPreferenceStore prefs = getPreferenceStore();
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_STATUS, BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_STATUS_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUSE_STATUS_PRESELECTED,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_PRESELECTED_STATUS_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_RESOLUTION,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_RESOLUTION_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_SEVERITY,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_SEVERITY_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_PRIORITY,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_PRIORITY_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_HARDWARE,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_HARDWARE_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_OS, BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_OS_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_PRODUCT,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_PRODUCT_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_COMPONENT,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_COMPONENT_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_VERSION,
+ // BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_VERSION_VALUES));
+ //
+ // prefs.setDefault(IBugzillaConstants.VALUES_TARGET, BugzillaRepositoryUtil
+ // .queryOptionsToString(IBugzillaConstants.DEFAULT_TARGET_VALUES));
+ // }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportElement.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportElement.java
new file mode 100644
index 000000000..4c871f9f5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportElement.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+/**
+ * Bugzilla XML element enum. Each enum has the attribute name
+ * and associated xml element tag name.
+ *
+ * @author Rob Elves
+ */
+public enum BugzillaReportElement {
+ // Format: ENUM ( "pretty name", "xml key", <hidden: true/false>, <readonly: true/false>)
+ // Hidden elements are not automatically displayed in ui
+ ASSIGNED_TO ("Assigned to:", "assigned_to", false, true),
+ ATTACHID ("attachid", "attachid"),
+ ATTACHMENT ("attachment", "attachment"),
+ BLOCKED ("Bug blocks:", "blocked"),
+ BUG ("bug","bug", true),
+ BUG_FILE_LOC ("URL:", "bug_file_loc", true),
+ BUG_ID ("Bug:", "bug_id", true),
+ BUG_SEVERITY ("Severity:", "bug_severity", false),
+ BUG_STATUS ("Status:", "bug_status", false, true),
+ BUG_WHEN ("bug_when", "bug_when", true, true),
+ BUGZILLA ("bugzilla", "bugzilla", true),
+ CC ("CC:", "cc", true, true),
+ CCLIST_ACCESSIBLE ("cclist_accessible", "cclist_accessible", true),
+ CLASSIFICATION ("Classification:", "classification", true),
+ CLASSIFICATION_ID ("Classification ID:", "classification_id", true),
+ COMPONENT ("Component:", "component", false),
+ CREATION_TS ("Creation date:", "creation_ts", true),
+ CTYPE ("Content Type", "ctype"),
+ DATA ("data", "data"),
+ DATE ("Date", "date"),
+ DELTA_TS ("Last Modification", "delta_ts", true),
+ DEPENDSON ("Bug depends on:", "dependson"),
+ DESC ("desc", "desc"),
+ EVERCONFIRMED ("everconfirmed", "everconfirmed", true),
+ FILENAME ("filename", "filename"),
+ IS_OBSOLETE ("Obsolete", "isobsolete", true),
+ KEYWORDS ("Keywords:", "keywords", true),
+ LONG_DESC ("Description:", "long_desc"),
+ LONGDESCLENGTH ("Number of comments", "longdesclength", true),
+ NEWCC ("Add CC:", "newcc", true),
+ OP_SYS ("OS:", "op_sys", false),
+ PRIORITY ("Priority:", "priority", false),
+ PRODUCT ("Product:", "product", false),
+ REP_PLATFORM ("Platform:", "rep_platform", false),
+ REPORTER ("Reporter:", "reporter", false, true),
+ REPORTER_ACCESSIBLE ("reporter_accessible", "reporter_accessible", true),
+ RESOLUTION ("Resolution:", "resolution", false, true), // Exiting bug field, new cc
+ SHORT_DESC ("Summary:", "short_desc", true),
+ TARGET_MILESTONE ("Target milestone:", "target_milestone", false),
+ THETEXT ("thetext", "thetext"),
+ TYPE ("type", "type"),
+ UNKNOWN ("UNKNOWN", "UNKNOWN"),
+ VERSION ("Version:", "version", false),
+ VOTES ("Votes:", "votes", false, true),
+ WHO ("who", "who"),
+ QA_CONTACT("QA Contact", "qa_contact", false, false),
+ ADDSELFCC ("Add self to CC", "addselfcc", true, false),
+ // Used by search engine
+ LI ("used by search engine", "li", true),
+ ID ("used by search engine", "id", true),
+ SHORT_SHORT_DESC ("used by search engine", "short_short_desc", false),
+ SEQ ("used by search engine", "seq", false),
+ RESULT ("used by search engine", "result", false),
+ RDF ("used by search engine", "rdf", false),
+ INSTALLATION ("used by search engine", "installation", false),
+ BUGS ("used by search engine", "bugs", false);
+
+ private final boolean isHidden;
+
+ private final boolean isReadOnly;
+
+ private final String keyString;
+
+ private final String prettyName;
+
+ BugzillaReportElement(String prettyName, String fieldName) {
+ this(prettyName, fieldName, false, false);
+ }
+
+ BugzillaReportElement(String prettyName, String fieldName, boolean hidden) {
+ this(prettyName, fieldName, hidden, false);
+ }
+
+ BugzillaReportElement(String prettyName, String fieldName, boolean hidden, boolean readonly) {
+ this.prettyName = prettyName;
+ this.keyString = fieldName;
+ this.isHidden = hidden;
+ this.isReadOnly = readonly;
+ }
+
+ public String getKeyString() {
+ return keyString;
+ }
+
+ public boolean isHidden() {
+ return isHidden;
+ }
+
+ public boolean isReadOnly() {
+ return isReadOnly;
+ }
+
+ public String toString() {
+ return prettyName;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportSubmitForm.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportSubmitForm.java
new file mode 100644
index 000000000..7d20659c0
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaReportSubmitForm.java
@@ -0,0 +1,622 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylar.internal.tasklist.LocalAttachment;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.internal.tasklist.RepositoryOperation;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttribute;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer;
+import org.eclipse.mylar.internal.tasklist.util.HtmlTag;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer.Token;
+
+/**
+ *
+ * @author Shawn Minto
+ * @author Mik Kersten (hardening of prototype)
+ * @author Rob Elves
+ *
+ * Class to handle the positing of a bug
+ */
+public class BugzillaReportSubmitForm {
+
+ private static final String KEY_ID = "id";
+
+ private static final String VAL_TRUE = "true";
+
+ private static final String KEY_REMOVECC = "removecc";
+
+ private static final String KEY_CC = "cc";
+
+ private static final String POST_CONTENT_TYPE = "application/x-www-form-urlencoded";
+
+ private static final String REQUEST_PROPERTY_CONTENT_TYPE = "Content-Type";
+
+ private static final String REQUEST_PROPERTY_CONTENT_LENGTH = "Content-Length";
+
+ private static final String METHOD_POST = "POST";
+
+ private static final String KEY_BUGZILLA_PASSWORD = "Bugzilla_password";
+
+ private static final String KEY_BUGZILLA_LOGIN = "Bugzilla_login";
+
+ private static final String POST_BUG_CGI = "post_bug.cgi";
+
+ private static final String PROCESS_BUG_CGI = "process_bug.cgi";
+
+ public static final int WRAP_LENGTH = 90;
+
+ private static final String VAL_PROCESS_BUG = "process_bug";
+
+ private static final String KEY_FORM_NAME = "form_name";
+
+ private static final String VAL_NONE = "none";
+
+ private static final String KEY_KNOB = "knob";
+
+ private static final String KEY_COMMENT = "comment";
+
+ private static final String KEY_SHORT_DESC = "short_desc";
+
+ public static final String FORM_POSTFIX_218 = " Submitted";
+
+ public static final String FORM_POSTFIX_216 = " posted";
+
+ public static final String FORM_PREFIX_BUG_218 = "Bug ";
+
+ public static final String FORM_PREFIX_BUG_220 = "Issue ";
+
+ private BugzillaAttachmentHandler attachmentHandler = new BugzillaAttachmentHandler();
+
+ /** The fields that are to be changed/maintained */
+ private Map<String, String> fields = new HashMap<String, String>();
+
+ private URL postUrl;
+
+ private Proxy proxySettings = Proxy.NO_PROXY;
+
+ private String charset;
+
+ /** The prefix for how to find the bug number from the return */
+ private String prefix;
+
+ private String prefix2;
+
+ /** The postfix for how to find the bug number from the return */
+ private String postfix;
+
+ /** An alternate postfix for how to find the bug number from the return */
+ private String postfix2;
+
+ private String error = null;
+
+ /** The local attachment to attach to this report, null if none */
+ private LocalAttachment attachment = null;
+
+
+ public BugzillaReportSubmitForm(String charEncoding) {
+ charset = charEncoding;
+ }
+
+ public static BugzillaReportSubmitForm makeNewBugPost(String repositoryUrl, String userName, String password,
+ Proxy proxySettings, String characterEncoding, NewBugzillaReport model, boolean wrapDescription)
+ throws UnsupportedEncodingException {
+
+ BugzillaReportSubmitForm form;
+
+ if (characterEncoding != null) {
+ form = new BugzillaReportSubmitForm(characterEncoding);
+ } else {
+ form = new BugzillaReportSubmitForm(BugzillaPlugin.ENCODING_UTF_8);
+ }
+
+ form.setPrefix(BugzillaReportSubmitForm.FORM_PREFIX_BUG_218);
+ form.setPrefix2(BugzillaReportSubmitForm.FORM_PREFIX_BUG_220);
+
+ form.setPostfix(BugzillaReportSubmitForm.FORM_POSTFIX_216);
+ form.setPostfix2(BugzillaReportSubmitForm.FORM_POSTFIX_218);
+
+ setConnectionsSettings(form, repositoryUrl, userName, password, proxySettings, POST_BUG_CGI);
+
+ // go through all of the attributes and add them to
+ // the bug post
+ Iterator<RepositoryTaskAttribute> itr = model.getAttributes().iterator();
+ while (itr.hasNext()) {
+ RepositoryTaskAttribute a = itr.next();
+ if (a != null && a.getID() != null && a.getID().compareTo("") != 0) {
+ String value = null;
+ value = a.getValue();
+ if (value == null)
+ continue;
+ form.add(a.getID(), value);
+ }
+ }
+
+ // form.add(KEY_BUG_FILE_LOC, "");
+
+ // specify the product
+ form.add(BugzillaReportElement.PRODUCT.getKeyString(), model.getProduct());
+
+ // add the summary to the bug post
+ form.add(BugzillaReportElement.SHORT_DESC.getKeyString(), model.getSummary());
+
+ String formattedDescription = formatTextToLineWrap(model.getDescription(), wrapDescription);
+ model.setDescription(formattedDescription);
+
+ if (model.getDescription().length() != 0) {
+ // add the new comment to the bug post if there
+ // is some text in
+ // it
+ form.add(KEY_COMMENT, model.getDescription());
+ }
+ return form;
+ }
+
+ /**
+ * TODO: refactor common stuff with new bug post
+ *
+ * @param removeCC
+ * @param characterEncoding
+ * TODO
+ *
+ * @throws UnsupportedEncodingException
+ */
+ public static BugzillaReportSubmitForm makeExistingBugPost(RepositoryTaskData bug, String repositoryUrl,
+ String userName, String password, Proxy proxySettings, Set<String> removeCC, String characterEncoding)
+ throws UnsupportedEncodingException {
+
+ BugzillaReportSubmitForm bugReportPostHandler;
+
+ if (characterEncoding != null) {
+ bugReportPostHandler = new BugzillaReportSubmitForm(characterEncoding);
+ } else {
+ bugReportPostHandler = new BugzillaReportSubmitForm(BugzillaPlugin.ENCODING_UTF_8);
+ }
+
+ //setDefaultCCValue(bug, userName);
+ setConnectionsSettings(bugReportPostHandler, repositoryUrl, userName, password, proxySettings, PROCESS_BUG_CGI);
+
+ // go through all of the attributes and add them to the bug post
+ for (Iterator<RepositoryTaskAttribute> it = bug.getAttributes().iterator(); it.hasNext();) {
+ RepositoryTaskAttribute a = it.next();
+ if (a.getID().equals(BugzillaReportElement.CC.getKeyString())
+ || a.getID().equals(BugzillaReportElement.REPORTER.getKeyString())
+ || a.getID().equals(BugzillaReportElement.ASSIGNED_TO.getKeyString())
+ || a.getID().equals(BugzillaReportElement.CREATION_TS.getKeyString())) {
+ continue;
+ }
+ if (a != null && a.getID() != null && a.getID().compareTo("") != 0 && !a.isHidden()) {
+ String value = a.getValue();
+ // System.err.println(a.getID()+" "+a.getValue());
+ // add the attribute to the bug post
+ bugReportPostHandler.add(a.getID(), value != null ? value : "");
+ } else if (a != null && a.getID() != null && a.getID().compareTo("") != 0 && a.isHidden()) {
+ // we have a hidden attribute and we should send it back.
+ // System.err.println(a.getID()+" "+a.getValue());
+ bugReportPostHandler.add(a.getID(), a.getValue());
+ }
+ }
+
+ // when posting the bug id is encoded in a hidden field named 'id'
+ bugReportPostHandler.add(KEY_ID, bug.getAttributeValue(BugzillaReportElement.BUG_ID.getKeyString()));
+
+ // add the operation to the bug post
+ RepositoryOperation o = bug.getSelectedOperation();
+ if (o == null)
+ bugReportPostHandler.add(KEY_KNOB, VAL_NONE);
+ else {
+ bugReportPostHandler.add(KEY_KNOB, o.getKnobName());
+ if (o.hasOptions()) {
+ String sel = o.getOptionValue(o.getOptionSelection());
+ bugReportPostHandler.add(o.getOptionName(), sel);
+ } else if (o.isInput()) {
+ String sel = o.getInputValue();
+ bugReportPostHandler.add(o.getInputName(), sel);
+ }
+ }
+ bugReportPostHandler.add(KEY_FORM_NAME, VAL_PROCESS_BUG);
+
+ if (bug.getAttribute(BugzillaReportElement.SHORT_DESC.getKeyString()) != null) {
+ bugReportPostHandler.add(KEY_SHORT_DESC, bug.getAttribute(BugzillaReportElement.SHORT_DESC.getKeyString()).getValue());
+ }
+
+ if (bug.getNewComment().length() != 0) {
+ bugReportPostHandler.add(KEY_COMMENT, bug.getNewComment());
+ }
+
+ if (removeCC != null && removeCC.size() > 0) {
+ String[] s = new String[removeCC.size()];
+ bugReportPostHandler.add(KEY_CC, toCommaSeparatedList(removeCC.toArray(s)));
+ bugReportPostHandler.add(KEY_REMOVECC, VAL_TRUE);
+ }
+
+ bugReportPostHandler.attachment = bug.getNewAttachment();
+
+ return bugReportPostHandler;
+ }
+
+ private static String toCommaSeparatedList(String[] strings) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < strings.length; i++) {
+ buffer.append(strings[i]);
+ if (i != strings.length - 1) {
+ buffer.append(",");
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Add a value to be posted to the bug
+ *
+ * @param key
+ * The key for the value to be added
+ * @param value
+ * The value to be added
+ * @throws UnsupportedEncodingException
+ */
+ private void add(String key, String value) throws UnsupportedEncodingException {
+ // try {
+ fields.put(key, URLEncoder.encode(value == null ? "" : value, charset));
+ // BugzillaPlugin.ENCODING_UTF_8
+ // } catch (UnsupportedEncodingException e) {
+ // // ignore
+ // }
+ }
+
+ /**
+ * Post the bug to the bugzilla server
+ *
+ * @return The result of the responses
+ * @throws BugzillaException
+ * @throws PossibleBugzillaFailureException
+ */
+ public String submitReportToRepository() throws BugzillaException, LoginException, PossibleBugzillaFailureException {
+ BufferedOutputStream out = null;
+ BufferedReader in = null;
+ String result = null;
+ try {
+ // connect to the bugzilla server
+ URLConnection cntx = BugzillaPlugin.getUrlConnection(postUrl, proxySettings);
+ if (cntx == null || !(cntx instanceof HttpURLConnection))
+ return null;
+
+ HttpURLConnection postConnection = (HttpURLConnection) cntx;
+
+ // set the connection method
+ postConnection.setRequestMethod(METHOD_POST);
+ String contentTypeString = POST_CONTENT_TYPE;
+ if (charset != null) {
+ contentTypeString += ";charset=" + charset;
+ }
+ postConnection.setRequestProperty(REQUEST_PROPERTY_CONTENT_TYPE, contentTypeString);
+ // get the url for the update with all of the changed values
+
+ byte[] body = getPostBody().getBytes();
+ postConnection.setRequestProperty(REQUEST_PROPERTY_CONTENT_LENGTH, String.valueOf(body.length));
+
+ // allow outgoing streams and open a stream to post to
+ postConnection.setDoOutput(true);
+
+ out = new BufferedOutputStream(postConnection.getOutputStream());
+
+ // write the data and close the stream
+ out.write(body);
+ out.flush();
+
+ int responseCode = postConnection.getResponseCode();
+ if (responseCode != HttpURLConnection.HTTP_OK && responseCode != HttpURLConnection.HTTP_CREATED) {
+ throw new BugzillaException("Server returned HTTP error: " + responseCode + " - "
+ + postConnection.getResponseMessage());
+ }
+
+ // open a stream to receive response from bugzilla
+ in = new BufferedReader(new InputStreamReader(postConnection.getInputStream()));
+
+
+ String aString = in.readLine();
+
+ // Used to debug reponse from bugzilla server
+ // while (aString != null) {
+ // System.err.println(aString);
+ // aString = in.readLine();
+ // }
+
+ boolean possibleFailure = true;
+ error = "";
+
+ while (aString != null) {
+ error += aString == null ? "" : aString + "\n";
+
+ // check if we have run into an error
+
+ if (result == null
+ && (aString.toLowerCase().indexOf("check e-mail") != -1 || aString.toLowerCase().indexOf(
+ "error") != -1)) {
+ throw new LoginException("Bugzilla login problem.");
+ } else if (aString.indexOf("Invalid Username Or Password") != -1) {
+ throw new LoginException("Invalid Username or Password.");
+ } else if (aString.toLowerCase().matches(".*bug\\s+processed.*") // TODO:
+ // make
+ // this
+ // configurable
+ || aString.toLowerCase().matches(".*defect\\s+processed.*")) {
+ possibleFailure = false;
+ }
+ // // get the bug number if it is required
+ if (prefix != null && prefix2 != null && postfix != null && postfix2 != null && result == null) {
+ int startIndex = -1;
+ int startIndexPrefix = aString.toLowerCase().indexOf(prefix.toLowerCase());
+ int startIndexPrefix2 = aString.toLowerCase().indexOf(prefix2.toLowerCase());
+
+ if (startIndexPrefix != -1 || startIndexPrefix2 != -1) {
+ if (startIndexPrefix != -1) {
+ startIndex = startIndexPrefix + prefix.length();
+ } else {
+ startIndex = startIndexPrefix2 + prefix2.length();
+ }
+ int stopIndex = aString.toLowerCase().indexOf(postfix.toLowerCase(), startIndex);
+ if (stopIndex == -1)
+ stopIndex = aString.toLowerCase().indexOf(postfix2.toLowerCase(), startIndex);
+ if (stopIndex > -1) {
+ result = (aString.substring(startIndex, stopIndex)).trim();
+ possibleFailure = false;
+ }
+ }
+ }
+ aString = in.readLine();
+ }
+
+ if ((result == null || result.compareTo("") == 0)
+ && (prefix != null && prefix2 == null && postfix != null && postfix2 != null)) {
+ throw new PossibleBugzillaFailureException("Could not find bug number for new bug.");
+ } else if (possibleFailure) {
+ throw new PossibleBugzillaFailureException(
+ "Bug report may not have been submitted. Bugzilla message was: ");
+ }
+
+ // set the error to null if we dont think that there was one
+ error = null;
+
+ } catch (IOException e) {
+ throw new BugzillaException("An exception occurred while submitting the bug: " + e.getMessage(), e);
+ } catch (KeyManagementException e) {
+ throw new BugzillaException("Could not POST form. Communications error: " + e.getMessage(), e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new BugzillaException("Could not POST form. Communications error: " + e.getMessage(), e);
+ } finally {
+ try {
+ if (in != null)
+ in.close();
+ if (out != null)
+ out.close();
+
+ } catch (IOException e) {
+ BugzillaPlugin.log(new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID, IStatus.ERROR,
+ "Problem posting the bug", e));
+ }
+
+ try {
+ // upload the attachment if any
+ if (attachment != null) {
+ if (attachment.getDescription() == null || attachment.getDescription().equals("")) {
+ throw new BugzillaException("Attachment must have a description");
+ }
+
+ String uname = URLDecoder.decode(fields.get(KEY_BUGZILLA_LOGIN), this.charset);
+ String password = URLDecoder.decode(fields.get(KEY_BUGZILLA_PASSWORD), this.charset);
+ if (!attachmentHandler.uploadAttachment(attachment, uname, password, proxySettings)) {
+ throw new BugzillaException("Could not upload attachment.");
+ }
+
+ }
+ } catch (IOException e) {
+ throw new BugzillaException("Could not upload attachment. Communications error: " + e.getMessage(), e);
+ }
+
+ }
+ // return the bug number
+ return result;
+ }
+
+ /**
+ * Get the url that contains the attributes to be posted
+ *
+ * @return The url for posting
+ */
+ private String getPostBody() {
+ String postBody = "";
+
+ // go through all of the attributes and add them to the body of the post
+ Iterator<Map.Entry<String, String>> anIterator = fields.entrySet().iterator();
+ while (anIterator.hasNext()) {
+ Map.Entry<String, String> entry = anIterator.next();
+ postBody = postBody + entry.getKey() + "=" + entry.getValue();
+ if (anIterator.hasNext())
+ postBody = postBody + "&";
+ }
+ return postBody;
+ }
+
+ private void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ private void setPostfix(String postfix) {
+ this.postfix = postfix;
+ }
+
+ private void setPostfix2(String postfix) {
+ this.postfix2 = postfix;
+ }
+
+ public String getError() {
+ return parseError();
+ }
+
+ /**
+ * remove all of the hyperlinks and erroneous info
+ *
+ * @return
+ */
+ private String parseError() {
+ String newError = "";
+ try {
+ HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(new StringReader(error), null);
+ for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
+ if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == HtmlTag.Type.A) {
+
+ } else if (token.getType() == Token.TAG
+ && ((HtmlTag) (token.getValue())).getTagType() == HtmlTag.Type.FORM) {
+ for (Token token2 = tokenizer.nextToken(); token2.getType() != Token.EOF; token2 = tokenizer
+ .nextToken()) {
+ if (token2.getType() == Token.TAG) {
+ HtmlTag tag = (HtmlTag) token2.getValue();
+ if (tag.getTagType() == HtmlTag.Type.FORM && tag.isEndTag())
+ break;
+
+ }
+ }
+ } else {
+ newError += token.getWhitespace().toString() + token.getValue();
+ }
+ }
+ } catch (Exception e) {
+ newError = error;
+ }
+ return newError;
+ }
+
+ private void setPrefix2(String prefix2) {
+ this.prefix2 = prefix2;
+ }
+
+ // private void setCharset(String charset) {
+ // this.charset = charset;
+ // }
+
+ private static void setConnectionsSettings(BugzillaReportSubmitForm form, String repositoryUrl, String userName,
+ String password, Proxy proxySettings, String formName) throws UnsupportedEncodingException {
+
+ String baseURL = repositoryUrl;
+
+ if (!baseURL.endsWith("/"))
+ baseURL += "/";
+ try {
+ form.postUrl = new URL(baseURL + formName);
+ if (proxySettings != null) {
+ form.proxySettings = proxySettings;
+ }
+ } catch (MalformedURLException e) {
+ // we should be ok here
+ }
+
+ // add the login information to the bug post
+ form.add(KEY_BUGZILLA_LOGIN, userName);
+ form.add(KEY_BUGZILLA_PASSWORD, password);
+ }
+
+// /**
+// * Sets the cc field to the user's address if a cc has not been specified to
+// * ensure that commenters are on the cc list. TODO: Review this mechanism
+// *
+// * @author Wesley Coelho
+// */
+// private static void setDefaultCCValue(BugzillaReport bug, String userName) {
+// // RepositoryTaskAttribute newCCattr =
+// // bug.getAttributeForKnobName(KEY_NEWCC);
+// RepositoryTaskAttribute owner = bug.getAttribute(BugzillaReportElement.ASSIGNED_TO);
+//
+// // Don't add the cc if the user is the bug owner
+// if (userName == null || (owner != null && owner.getValue().indexOf(userName) != -1)) {
+// // MylarStatusHandler.log("Could not determine CC value for
+// // repository: " + repository, null);
+// return;
+// }
+// // Don't add cc if already there
+// RepositoryTaskAttribute ccAttribute = bug.getAttribute(BugzillaReportElement.CC);
+// if (ccAttribute != null && ccAttribute.getValues().contains(userName)) {
+// return;
+// }
+// RepositoryTaskAttribute newCCattr = bug.getAttribute(BugzillaReportElement.NEWCC);
+// if (newCCattr == null) {
+// newCCattr = new RepositoryTaskAttribute(BugzillaReportElement.NEWCC);
+// bug.addAttribute(BugzillaReportElement.NEWCC, newCCattr);
+// }
+// // Add the user to the cc list
+// newCCattr.setValue(userName);
+// }
+
+ /**
+ * Break text up into lines of about 80 characters so that it is displayed
+ * properly in bugzilla
+ */
+ private static String formatTextToLineWrap(String origText, boolean hardWrap) {
+ // BugzillaServerVersion bugzillaServerVersion =
+ // IBugzillaConstants.BugzillaServerVersion.fromString(repository
+ // .getVersion());
+ // if (bugzillaServerVersion != null &&
+ // bugzillaServerVersion.compareTo(BugzillaServerVersion.SERVER_220) >=
+ // 0) {
+ // return origText;
+ if (!hardWrap) {
+ return origText;
+ } else {
+ String[] textArray = new String[(origText.length() / WRAP_LENGTH + 1) * 2];
+ for (int i = 0; i < textArray.length; i++)
+ textArray[i] = null;
+ int j = 0;
+ while (true) {
+ int spaceIndex = origText.indexOf(" ", WRAP_LENGTH - 5);
+ if (spaceIndex == origText.length() || spaceIndex == -1) {
+ textArray[j] = origText;
+ break;
+ }
+ textArray[j] = origText.substring(0, spaceIndex);
+ origText = origText.substring(spaceIndex + 1, origText.length());
+ j++;
+ }
+
+ String newText = "";
+
+ for (int i = 0; i < textArray.length; i++) {
+ if (textArray[i] == null)
+ break;
+ newText += textArray[i] + "\n";
+ }
+ return newText;
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaRepositoryUtil.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaRepositoryUtil.java
new file mode 100644
index 000000000..65b339372
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaRepositoryUtil.java
@@ -0,0 +1,682 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants.BUGZILLA_OPERATION;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants.BUGZILLA_REPORT_STATUS;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants.BUGZILLA_RESOLUTION;
+import org.eclipse.mylar.internal.tasklist.RepositoryOperation;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttribute;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer;
+import org.eclipse.mylar.internal.tasklist.util.HtmlTag;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer.Token;
+
+/**
+ * @author Mik Kersten (some rewriting)
+ * @author Rob Elves
+ */
+public class BugzillaRepositoryUtil {
+
+ private static final String ATTR_CHARSET = "charset";
+
+ private static final String OPERATION_INPUT_ASSIGNED_TO = "assigned_to";
+
+ private static final String OPERATION_INPUT_DUP_ID = "dup_id";
+
+ private static final String OPERATION_OPTION_RESOLUTION = "resolution";
+
+ private static final String OPERATION_LABEL_CLOSE = "Mark bug as CLOSED";
+
+ private static final String OPERATION_LABEL_VERIFY = "Mark bug as VERIFIED";
+
+ private static final String OPERATION_LABEL_REOPEN = "Reopen bug";
+
+ private static final String OPERATION_LABEL_REASSIGN_DEFAULT = "Reassign bug to default assignee of selected component";
+
+ private static final String OPERATION_LABEL_REASSIGN = "Reassign bug to";
+
+ private static final String OPERATION_LABEL_DUPLICATE = "Resolve bug, mark it as duplicate of bug #";
+
+ private static final String OPERATION_LABEL_RESOLVE = "Resolve bug, changing resolution to";
+
+ private static final String OPERATION_LABEL_ACCEPT = "Accept bug (change status to ASSIGNED)";
+
+ private static final String BUG_STATUS_NEW = "NEW";
+
+ private static final String POST_ARGS_PASSWORD = "&Bugzilla_password=";
+
+ public static final String POST_ARGS_SHOW_BUG = "/show_bug.cgi?id=";// ctype=xml&
+
+ private static final String POST_ARGS_LOGIN = "GoAheadAndLogIn=1&Bugzilla_login=";
+
+ private static final BugzillaAttributeFactory attributeFactory = new BugzillaAttributeFactory();
+
+ public static RepositoryTaskData getBug(String repositoryUrl, String userName, String password, Proxy proxySettings,
+ String characterEncoding, int id) throws IOException, MalformedURLException, LoginException,
+ GeneralSecurityException {
+
+
+ RepositoryTaskData bugReport = new RepositoryTaskData(new BugzillaAttributeFactory(), BugzillaPlugin.REPOSITORY_KIND, repositoryUrl, id);
+ setupExistingBugAttributes(repositoryUrl, bugReport);
+
+ RepositoryReportFactory reportFactory = RepositoryReportFactory.getInstance();
+ reportFactory.populateReport(bugReport, repositoryUrl, proxySettings, userName, password, characterEncoding);
+ updateBugAttributeOptions(repositoryUrl, proxySettings, userName, password, bugReport, characterEncoding);
+ addValidOperations(bugReport, userName);
+
+ return bugReport;
+ }
+
+ public static String addCredentials(String url, String userName, String password)
+ throws UnsupportedEncodingException {
+ if (userName != null && password != null) {
+ // if (repository.hasCredentials()) {
+ url += "&" + POST_ARGS_LOGIN + URLEncoder.encode(userName, BugzillaPlugin.ENCODING_UTF_8)
+ + POST_ARGS_PASSWORD + URLEncoder.encode(password, BugzillaPlugin.ENCODING_UTF_8);
+ }
+ return url;
+ }
+
+ /**
+ * Get the list of products
+ * @param proxySettings TODO
+ * @param encoding
+ * TODO
+ *
+ * @return The list of valid products a bug can be logged against
+ * @throws IOException
+ * LoginException Exception
+ */
+ public static List<String> getProductList(String repositoryUrl, Proxy proxySettings, String userName, String password, String encoding)
+ throws IOException, LoginException, Exception {
+
+ return BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName, password, encoding)
+ .getProducts();
+
+ // BugzillaQueryPageParser parser = new
+ // BugzillaQueryPageParser(repository, new NullProgressMonitor());
+ // if (!parser.wasSuccessful()) {
+ // throw new RuntimeException("Couldn't get products");
+ // } else {
+ // return Arrays.asList(parser.getProductValues());
+ // }
+
+ }
+
+ // TODO: move to repository connector?
+ public static void validateCredentials(String repositoryUrl, String userid, String password) throws IOException,
+ LoginException {
+
+ String url = repositoryUrl + "/index.cgi?" + POST_ARGS_LOGIN
+ + URLEncoder.encode(userid, BugzillaPlugin.ENCODING_UTF_8) + POST_ARGS_PASSWORD
+ + URLEncoder.encode(password, BugzillaPlugin.ENCODING_UTF_8);
+
+ URL serverURL = new URL(url);
+ URLConnection connection = serverURL.openConnection();
+ BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+ parseHtmlError(in);
+ }
+
+ /**
+ * Utility method for determining what potential error has occurred from a
+ * bugzilla html reponse page
+ */
+ public static void parseHtmlError(BufferedReader in) throws IOException, LoginException {
+ HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(in, null);
+
+ boolean isTitle = false;
+ String title = "";
+
+ try {
+
+ for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
+
+ if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == HtmlTag.Type.TITLE
+ && !((HtmlTag) (token.getValue())).isEndTag()) {
+ isTitle = true;
+ continue;
+ }
+
+ if (isTitle) {
+ // get all of the data in the title tag
+ if (token.getType() != Token.TAG) {
+ title += ((StringBuffer) token.getValue()).toString().toLowerCase() + " ";
+ continue;
+ } else if (token.getType() == Token.TAG
+ && ((HtmlTag) token.getValue()).getTagType() == HtmlTag.Type.TITLE
+ && ((HtmlTag) token.getValue()).isEndTag()) {
+
+ if (title.indexOf("login") != -1
+ || (title.indexOf("invalid") != -1 && title.indexOf("password") != -1)
+ || title.indexOf("check e-mail") != -1) {
+ throw new LoginException(IBugzillaConstants.ERROR_INVALID_USERNAME_OR_PASSWORD);
+ }
+ return;
+ }
+ }
+ }
+ } catch (ParseException e) {
+ throw new IOException("Unable to parse result from repository:\n" + e.getMessage());
+ }
+ }
+
+ /**
+ * Adds bug attributes to new bug model and sets defaults
+ * @param proxySettings TODO
+ * @param characterEncoding
+ * TODO
+ *
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws LoginException
+ * @throws KeyManagementException
+ */
+ public static void setupNewBugAttributes(String repositoryUrl, Proxy proxySettings, String userName,
+ String password, NewBugzillaReport newReport, String characterEncoding) throws IOException, KeyManagementException, LoginException, NoSuchAlgorithmException {
+
+ newReport.removeAllAttributes();
+
+ RepositoryTaskAttribute a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.PRODUCT);
+ List<String> optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings,
+ userName, password, characterEncoding).getProducts();
+ Collections.sort(optionValues);
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ a.setValue(newReport.getProduct());
+ newReport.addAttribute(BugzillaReportElement.PRODUCT.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.BUG_STATUS);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getStatusValues();
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ a.setValue(BUG_STATUS_NEW);
+ newReport.addAttribute(BugzillaReportElement.BUG_STATUS.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.VERSION);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getVersions(newReport.getProduct());
+ Collections.sort(optionValues);
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ if (optionValues != null && optionValues.size() > 0) {
+ a.setValue(optionValues.get(optionValues.size() - 1));
+ }
+ newReport.addAttribute(BugzillaReportElement.VERSION.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.COMPONENT);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getComponents(newReport.getProduct());
+ Collections.sort(optionValues);
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ newReport.addAttribute(BugzillaReportElement.COMPONENT.getKeyString(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.REP_PLATFORM);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getPlatforms();
+ Collections.sort(optionValues);
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ newReport.addAttribute(BugzillaReportElement.REP_PLATFORM.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.OP_SYS);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getOSs();
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ newReport.addAttribute(BugzillaReportElement.OP_SYS.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.PRIORITY);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getPriorities();
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ a.setValue(optionValues.get((optionValues.size() / 2)));
+ newReport.addAttribute(BugzillaReportElement.PRIORITY.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.BUG_SEVERITY);
+ optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings, userName,
+ password, characterEncoding).getSeverities();
+ for (String option : optionValues) {
+ a.addOptionValue(option, option);
+ }
+ a.setValue(optionValues.get((optionValues.size() / 2)));
+ newReport.addAttribute(BugzillaReportElement.BUG_SEVERITY.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ // a = new
+ // RepositoryTaskAttribute(BugzillaReportElement.TARGET_MILESTONE);
+ // optionValues =
+ // BugzillaPlugin.getDefault().getProductConfiguration(serverUrl).getTargetMilestones(
+ // newReport.getProduct());
+ // for (String option : optionValues) {
+ // a.addOptionValue(option, option);
+ // }
+ // if(optionValues.size() > 0) {
+ // // new bug posts will fail if target_milestone element is included
+ // // and there are no milestones on the server
+ // newReport.addAttribute(BugzillaReportElement.TARGET_MILESTONE, a);
+ // }
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.ASSIGNED_TO);
+ a.setValue("");
+ newReport.addAttribute(BugzillaReportElement.ASSIGNED_TO.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ a = BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.BUG_FILE_LOC);
+ a.setValue("http://");
+ a.setHidden(false);
+ newReport.addAttribute(BugzillaReportElement.BUG_FILE_LOC.getKeyString(), a);
+ // attributes.put(a.getName(), a);
+
+ // newReport.attributes = attributes;
+ }
+
+ public static void setupExistingBugAttributes(String serverUrl, RepositoryTaskData existingReport) {
+ // ordered list of elements as they appear in UI
+ // and additional elements that may not appear in the incoming xml
+ // stream but need to be present for bug submission
+ BugzillaReportElement[] reportElements = { BugzillaReportElement.BUG_STATUS, BugzillaReportElement.RESOLUTION,
+ BugzillaReportElement.BUG_ID, BugzillaReportElement.REP_PLATFORM, BugzillaReportElement.PRODUCT,
+ BugzillaReportElement.OP_SYS, BugzillaReportElement.COMPONENT, BugzillaReportElement.VERSION,
+ BugzillaReportElement.PRIORITY, BugzillaReportElement.BUG_SEVERITY, BugzillaReportElement.ASSIGNED_TO,
+ BugzillaReportElement.TARGET_MILESTONE, BugzillaReportElement.REPORTER,
+ BugzillaReportElement.DEPENDSON, BugzillaReportElement.BLOCKED, BugzillaReportElement.BUG_FILE_LOC,
+ BugzillaReportElement.NEWCC, BugzillaReportElement.KEYWORDS };
+
+ for (BugzillaReportElement element : reportElements) {
+ RepositoryTaskAttribute reportAttribute = BugzillaRepositoryUtil.makeNewAttribute(element);
+ existingReport.addAttribute(element.getKeyString(), reportAttribute);
+ }
+ }
+
+ private static void updateBugAttributeOptions(String repositoryUrl, Proxy proxySettings, String userName,
+ String password, RepositoryTaskData existingReport, String characterEncoding) throws IOException, KeyManagementException, LoginException, NoSuchAlgorithmException {
+ String product = existingReport.getAttributeValue(BugzillaReportElement.PRODUCT.getKeyString());
+ for (RepositoryTaskAttribute attribute : existingReport.getAttributes()) {
+ BugzillaReportElement element = BugzillaReportElement.valueOf(attribute.getID().trim().toUpperCase());
+ attribute.clearOptions();
+ List<String> optionValues = BugzillaPlugin.getRepositoryConfiguration(repositoryUrl, proxySettings,
+ userName, password, characterEncoding).getOptionValues(element, product);
+ if (element != BugzillaReportElement.OP_SYS && element != BugzillaReportElement.BUG_SEVERITY
+ && element != BugzillaReportElement.PRIORITY && element != BugzillaReportElement.BUG_STATUS) {
+ Collections.sort(optionValues);
+ }
+ if (element == BugzillaReportElement.TARGET_MILESTONE && optionValues.isEmpty()) {
+ existingReport.removeAttribute(BugzillaReportElement.TARGET_MILESTONE);
+ continue;
+ }
+ for (String option : optionValues) {
+ attribute.addOptionValue(option, option);
+ }
+ }
+
+ }
+
+ public static void addValidOperations(RepositoryTaskData bugReport, String userName) {
+ BUGZILLA_REPORT_STATUS status = BUGZILLA_REPORT_STATUS.valueOf(bugReport.getStatus());
+ switch (status) {
+ case UNCONFIRMED:
+ case REOPENED:
+ case NEW:
+ addOperation(bugReport, BUGZILLA_OPERATION.none, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.accept, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.resolve, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.duplicate, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reassign, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reassignbycomponent, userName);
+ break;
+ case ASSIGNED:
+ addOperation(bugReport, BUGZILLA_OPERATION.none, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.resolve, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.duplicate, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reassign, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reassignbycomponent, userName);
+ break;
+ case RESOLVED:
+ addOperation(bugReport, BUGZILLA_OPERATION.none, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reopen, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.verify, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.close, userName);
+ break;
+ case CLOSED:
+ addOperation(bugReport, BUGZILLA_OPERATION.none, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reopen, userName);
+ break;
+ case VERIFIED:
+ addOperation(bugReport, BUGZILLA_OPERATION.none, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.reopen, userName);
+ addOperation(bugReport, BUGZILLA_OPERATION.close, userName);
+ }
+ }
+
+ public static void addOperation(RepositoryTaskData bugReport, BUGZILLA_OPERATION opcode, String userName) {
+ RepositoryOperation newOperation = null;
+ switch (opcode) {
+ case none:
+ newOperation = new RepositoryOperation(opcode.toString(), "Leave as " + bugReport.getStatus() + " "
+ + bugReport.getResolution());
+ newOperation.setChecked(true);
+ break;
+ case accept:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_ACCEPT);
+ break;
+ case resolve:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_RESOLVE);
+ newOperation.setUpOptions(OPERATION_OPTION_RESOLUTION);
+ for (BUGZILLA_RESOLUTION resolution : BUGZILLA_RESOLUTION.values()) {
+ newOperation.addOption(resolution.toString(), resolution.toString());
+ }
+ break;
+ case duplicate:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_DUPLICATE);
+ newOperation.setInputName(OPERATION_INPUT_DUP_ID);
+ newOperation.setInputValue("");
+ break;
+ case reassign:
+ String localUser = userName;
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_REASSIGN);
+ newOperation.setInputName(OPERATION_INPUT_ASSIGNED_TO);
+ newOperation.setInputValue(localUser);
+ break;
+ case reassignbycomponent:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_REASSIGN_DEFAULT);
+ break;
+ case reopen:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_REOPEN);
+ break;
+ case verify:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_VERIFY);
+ break;
+ case close:
+ newOperation = new RepositoryOperation(opcode.toString(), OPERATION_LABEL_CLOSE);
+ break;
+ default:
+ break;
+ // MylarStatusHandler.log("Unknown bugzilla operation code recieved",
+ // BugzillaRepositoryUtil.class);
+ }
+ if (newOperation != null) {
+ bugReport.addOperation(newOperation);
+ }
+ }
+
+ public static String getBugUrl(String repositoryUrl, int id, String userName, String password) {
+
+ String url = repositoryUrl + POST_ARGS_SHOW_BUG + id;
+ try {
+ url = addCredentials(url, userName, password);
+ } catch (UnsupportedEncodingException e) {
+ return "";
+ }
+ return url;
+ }
+
+ public static String getBugUrlWithoutLogin(String repositoryUrl, int id) {
+ String url = repositoryUrl + POST_ARGS_SHOW_BUG + id;
+ return url;
+ }
+
+ public static String getCharsetFromString(String string) {
+ int charsetStartIndex = string.indexOf(ATTR_CHARSET);
+ if (charsetStartIndex != -1) {
+ int charsetEndIndex = string.indexOf("\"", charsetStartIndex); // TODO:
+ // could
+ // be
+ // space
+ // after?
+ if (charsetEndIndex == -1) {
+ charsetEndIndex = string.length();
+ }
+ String charsetString = string.substring(charsetStartIndex + 8, charsetEndIndex);
+ if (Charset.availableCharsets().containsKey(charsetString)) {
+ return charsetString;
+ }
+ }
+ return null;
+ }
+
+ protected static RepositoryTaskAttribute makeNewAttribute(org.eclipse.mylar.internal.bugzilla.core.BugzillaReportElement tag) {
+ return attributeFactory.createAttribute(tag.getKeyString());
+ }
+
+
+}
+
+// public static String decodeStringFromCharset(String string, String
+// charset) throws UnsupportedEncodingException {
+// String decoded = string;
+// if (charset != null && string != null &&
+// Charset.availableCharsets().containsKey(charset)) {
+// decoded = new String(string.getBytes(), charset);
+// }
+// return decoded;
+// }
+
+// public synchronized static BugzillaRepositoryUtil getInstance() {
+// if (instance == null) {
+// // if the instance hasn't been created yet, create one
+// instance = new
+// BugzillaRepositoryUtil(BugzillaPlugin.getDefault().getServerName());
+// }
+//
+// if
+// (!BugzillaRepositoryUtil.bugzillaUrl.equals(BugzillaPlugin.getDefault().getServerName()))
+// {
+// BugzillaRepositoryUtil.bugzillaUrl =
+// BugzillaPlugin.getDefault().getServerName();
+// }
+// return INSTANCE;
+// }
+// /**
+// * Test method.
+// */
+// public static void main(String[] args) throws Exception {
+// instance = new
+// BugzillaRepositoryUtil(BugzillaPlugin.getDefault().getServerName() +
+// "/long_list.cgi?buglist=");
+// BugReport bug = instance.getBug(16161);
+// System.out.println("Bug " + bug.getId() + ": " + bug.getSummary());
+// for (Iterator<Attribute> it = bug.getAttributes().iterator(); it.hasNext();)
+// {
+// Attribute attribute = it.next();
+// System.out.println(attribute.getName() + ": " + attribute.getValue());
+// }
+// System.out.println(bug.getDescription());
+// for (Iterator<Comment> it = bug.getComments().iterator(); it.hasNext();) {
+// Comment comment = it.next();
+// System.out
+// .println(comment.getAuthorName() + "<" + comment.getAuthor() + "> (" +
+// comment.getCreated() + ")");
+// System.out.print(comment.getText());
+// System.out.println();
+// }
+// }
+// /** URL of the Bugzilla server */
+// private static String bugzillaUrl;
+// private static BugzillaRepositoryUtil INSTANCE = new
+// BugzillaRepositoryUtil();
+// public static List<String> getValidKeywords(String repositoryURL) {
+// return
+// BugzillaPlugin.getDefault().getProductConfiguration(repositoryURL).getKeywords();
+// }
+// /**
+// * Get the attribute values for a new bug
+// *
+// * @param nbm
+// * A reference to a NewBugModel to store all of the data
+// * @throws Exception
+// */
+// public static void setupNewBugAttributes(String serverUrl, NewBugModel
+// nbm, boolean getProd) throws Exception {
+// BufferedReader in = null;
+// try {
+// // create a new input stream for getting the bug
+// String prodname = URLEncoder.encode(nbm.getProduct(),
+// BugzillaPlugin.ENCODING_UTF_8);
+//
+// TaskRepository repository =
+// MylarTaskListPlugin.getRepositoryManager().getRepository(
+// BugzillaPlugin.REPOSITORY_KIND, serverUrl);
+//
+// if (repository == null) {
+// throw new LoginException("Repository configuration error.");
+// }
+// if (repository.getUserName() == null ||
+// repository.getUserName().trim().equals("")
+// || repository.getPassword() == null) {
+// throw new LoginException("Login credentials missing.");
+// }
+//
+// String url = repository.getUrl() + "/enter_bug.cgi";
+//
+// // use the proper url if we dont know the product yet
+// if (!getProd)
+// url += "?product=" + prodname + "&";
+// else
+// url += "?";
+//
+// url += POST_ARGS_LOGIN + URLEncoder.encode(repository.getUserName(),
+// BugzillaPlugin.ENCODING_UTF_8)
+// + POST_ARGS_PASSWORD + URLEncoder.encode(repository.getPassword(),
+// BugzillaPlugin.ENCODING_UTF_8);
+//
+// URL bugUrl = new URL(url);
+// URLConnection cntx =
+// BugzillaPlugin.getDefault().getUrlConnection(bugUrl);
+// if (cntx != null) {
+// InputStream input = cntx.getInputStream();
+// if (input != null) {
+// in = new BufferedReader(new InputStreamReader(input));
+//
+// new NewBugParser(in).parseBugAttributes(nbm, getProd);
+// }
+// }
+//
+// } catch (Exception e) {
+//
+// if (e instanceof KeyManagementException || e instanceof
+// NoSuchAlgorithmException
+// || e instanceof IOException) {
+// if (MessageDialog.openQuestion(null, "Bugzilla Connect Error",
+// "Unable to connect to Bugzilla server.\n"
+// + "Bug report will be created offline and saved for submission later."))
+// {
+// nbm.setConnected(false);
+// setupBugAttributes(serverUrl, nbm);
+// } else
+// throw new Exception("Bug report will not be created.");
+// } else
+// throw e;
+// } finally {
+// try {
+// if (in != null)
+// in.close();
+// } catch (IOException e) {
+// BugzillaPlugin.log(new Status(IStatus.ERROR,
+// IBugzillaConstants.PLUGIN_ID, IStatus.ERROR,
+// "Problem closing the stream", e));
+// }
+// }
+// }
+// public static boolean downloadAttachment(TaskRepository repository, int
+// id, File destinationFile, boolean overwrite)
+// throws IOException {
+// BufferedReader in = null;
+// try {
+// String url = repository.getUrl() + POST_ARGS_ATTACHMENT_DOWNLOAD + id;
+// if (repository.hasCredentials()) {
+// url += "&" + POST_ARGS_LOGIN
+// + URLEncoder.encode(repository.getUserName(),
+// BugzillaPlugin.ENCODING_UTF_8)
+// + POST_ARGS_PASSWORD
+// + URLEncoder.encode(repository.getPassword(),
+// BugzillaPlugin.ENCODING_UTF_8);
+// }
+// URL downloadUrl = new URL(url);
+// URLConnection connection =
+// BugzillaPlugin.getDefault().getUrlConnection(downloadUrl);
+// if (connection != null) {
+// InputStream input = connection.getInputStream();
+// if (input != null) {
+// in = new BufferedReader(new InputStreamReader(input));
+// if (destinationFile.exists() && !overwrite) {
+// return false;
+// }
+// destinationFile.createNewFile();
+// OutputStreamWriter outputStream = new OutputStreamWriter(new
+// FileOutputStream(destinationFile));
+// BufferedWriter out = new BufferedWriter(outputStream);
+// char[] buf = new char[1024];
+// int len;
+// while ((len = in.read(buf)) > 0) {
+// out.write(buf, 0, len);
+// }
+// in.close();
+// out.close();
+// return true;
+// }
+// }
+// } catch (MalformedURLException e) {
+// throw e;
+// } catch (IOException e) {
+// throw e;
+// } catch (Exception e) {
+// BugzillaPlugin.log(new Status(IStatus.ERROR,
+// IBugzillaConstants.PLUGIN_ID, IStatus.ERROR,
+// "Problem retrieving attachment", e));
+// return false;
+// } finally {
+// try {
+// if (in != null)
+// in.close();
+// } catch (IOException e) {
+// BugzillaPlugin.log(new Status(IStatus.ERROR,
+// IBugzillaConstants.PLUGIN_ID, IStatus.ERROR,
+// "Problem closing the stream", e));
+// }
+// }
+// return false;
+// } \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskData.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskData.java
new file mode 100644
index 000000000..d7ecbac02
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskData.java
@@ -0,0 +1,284 @@
+///*******************************************************************************
+// * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+// * All rights reserved. This program and the accompanying materials
+// * are made available under the terms of the Eclipse Public License v1.0
+// * which accompanies this distribution, and is available at
+// * http://www.eclipse.org/legal/epl-v10.html
+// *
+// * Contributors:
+// * University Of British Columbia - initial API and implementation
+// *******************************************************************************/
+//package org.eclipse.mylar.internal.bugzilla.core;
+//
+//import java.io.Serializable;
+//import java.text.ParseException;
+//import java.text.SimpleDateFormat;
+//import java.util.ArrayList;
+//import java.util.Date;
+//import java.util.Iterator;
+//import java.util.List;
+//import java.util.StringTokenizer;
+//import java.util.TimeZone;
+//
+//import org.eclipse.mylar.internal.tasklist.AbstractRepositoryTaskData;
+//import org.eclipse.mylar.internal.tasklist.RepositoryOperation;
+//import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttribute;
+//import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttributeFactory;
+//
+///**
+// * @author Mik Kersten
+// * @author Rob Elves
+// */
+//public class BugzillaTaskData extends AbstractRepositoryTaskData implements Serializable {
+
+// private static final long serialVersionUID = 310066248657960823L;
+//
+// public static final String VAL_STATUS_VERIFIED = "VERIFIED";
+//
+// public static final String VAL_STATUS_CLOSED = "CLOSED";
+//
+// public static final String VAL_STATUS_RESOLVED = "RESOLVED";
+//
+// public static final String VAL_STATUS_NEW = "NEW";
+//
+// /** Parser for dates in the report */
+// private static SimpleDateFormat delta_ts_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//
+// private static SimpleDateFormat creation_ts_format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+//
+// /** The bugs valid keywords */
+// protected List<String> validKeywords;
+//
+// /** The repositoryOperations that can be done on the report */
+// protected List<RepositoryOperation> repositoryOperations = new ArrayList<RepositoryOperation>();
+//
+// private static final RepositoryTaskAttributeFactory attributeFactory = new BugzillaAttributeFactory();
+//
+// /** The operation that was selected to do to the bug */
+// protected RepositoryOperation selectedOperation = null;
+//
+// /** Whether or not this bug report is saved offline. */
+// protected boolean savedOffline = false;
+//
+// protected boolean hasChanges = false;
+//
+// protected String charset = null;
+//
+// public BugzillaTaskData(int id, String repositoryURL) {
+// super(id, repositoryURL);
+// }
+//
+// /**
+// * TODO: move?
+// */
+// public static boolean isResolvedStatus(String status) {
+// if (status != null) {
+// return status.equals(VAL_STATUS_RESOLVED) || status.equals(VAL_STATUS_CLOSED)
+// || status.equals(VAL_STATUS_VERIFIED);
+// } else {
+// return false;
+// }
+// }
+//
+// public void addCC(String email) {
+// addAttributeValue(BugzillaReportElement.CC.getKeyString(), email);
+// }
+//
+// /**
+// * Add an operation to the bug
+// *
+// * @param o
+// * The operation to add
+// */
+// public void addOperation(RepositoryOperation o) {
+// repositoryOperations.add(o);
+// }
+//
+// /**
+// * Get the set of addresses in the CC list
+// *
+// * @return A <code>Set</code> of addresses in the CC list
+// */
+// public List<String> getCC() {
+// return getAttributeValues(BugzillaReportElement.CC.getKeyString());
+// }
+//
+// /**
+// * Get the date that the bug was created
+// *
+// * @return The bugs creation date
+// */
+// public Date getCreated() {
+// if (created == null) {
+// String dateString = getAttributeValue(BugzillaReportElement.CREATION_TS.getKeyString());
+// try {
+// created = creation_ts_format.parse(dateString);
+// } catch (ParseException e) {
+// // ignore
+// }
+// }
+// return created;
+// }
+//
+// /**
+// * Get the keywords for the bug
+// *
+// * @return The keywords for the bug
+// */
+// public List<String> getKeywords() {
+//
+// // get the selected keywords for the bug
+// StringTokenizer st = new StringTokenizer(getAttributeValue(BugzillaReportElement.KEYWORDS.getKeyString()), ",", false);
+// List<String> keywords = new ArrayList<String>();
+// while (st.hasMoreTokens()) {
+// String s = st.nextToken().trim();
+// keywords.add(s);
+// }
+//
+// return keywords;
+// }
+//
+// public String getLabel() {
+// return getId() + ": " + getAttributeValue(BugzillaReportElement.SHORT_DESC.getKeyString());
+// }
+//
+// public Date getLastModified(TimeZone timeZone) {
+// if (lastModified == null) {
+// String dateString = getAttributeValue(BugzillaReportElement.DELTA_TS.getKeyString());
+// try {
+// if(timeZone != null) {
+// delta_ts_format.setTimeZone(timeZone);
+// } else {
+// delta_ts_format.setTimeZone(TimeZone.getDefault());
+// }
+// lastModified = delta_ts_format.parse(dateString);
+// } catch (ParseException e) {
+// // ignore
+// }
+// }
+// return lastModified;
+// }
+//
+// /**
+// * Get an operation from the bug based on its display name
+// *
+// * @param displayText
+// * The display text for the operation
+// * @return The operation that has the display text
+// */
+// public RepositoryOperation getOperation(String displayText) {
+// Iterator<RepositoryOperation> itr = repositoryOperations.iterator();
+// while (itr.hasNext()) {
+// RepositoryOperation o = itr.next();
+// String opName = o.getOperationName();
+// opName = opName.replaceAll("</.*>", "");
+// opName = opName.replaceAll("<.*>", "");
+// if (opName.equals(displayText))
+// return o;
+// }
+// return null;
+// }
+//
+// /**
+// * Get all of the repositoryOperations that can be done to the bug
+// *
+// * @return The repositoryOperations that can be done to the bug
+// */
+// public List<RepositoryOperation> getOperations() {
+// return repositoryOperations;
+// }
+//
+// /**
+// * Get the person who reported the bug
+// *
+// * @return The person who reported the bug
+// */
+// public String getReporter() {
+// return getAttributeValue(BugzillaReportElement.REPORTER.getKeyString());
+// }
+//
+// /**
+// * Get the resolution of the bug
+// *
+// * @return The resolution of the bug
+// */
+// public String getResolution() {
+// return getAttributeValue(BugzillaReportElement.RESOLUTION.getKeyString());
+// }
+//
+// /**
+// * Get the status of the bug
+// *
+// * @return The bugs status
+// */
+// public String getStatus() {
+// return getAttributeValue(BugzillaReportElement.BUG_STATUS.getKeyString());
+// }
+//
+// /**
+// * Get the summary for the bug
+// *
+// * @return The bugs summary
+// */
+// public String getSummary() {
+// return getAttributeValue(BugzillaReportElement.SHORT_DESC.getKeyString());
+// }
+//
+// public void setSummary(String summary) {
+// setAttributeValue(BugzillaReportElement.SHORT_DESC.getKeyString(), summary);
+// }
+//
+// public String getProduct() {
+// return getAttributeValue(BugzillaReportElement.PRODUCT.getKeyString());
+// }
+//
+// public boolean isLocallyCreated() {
+// return false;
+// }
+//
+// public boolean isResolved() {
+// RepositoryTaskAttribute status = getAttribute(BugzillaReportElement.BUG_STATUS.getKeyString());
+// return status != null && isResolvedStatus(status.getValue());
+// }
+//
+// public boolean isSavedOffline() {
+// return savedOffline;
+// }
+//
+// /**
+// * Remove an address from the bugs CC list
+// *
+// * @param email
+// * the address to be removed from the CC list
+// * @return <code>true</code> if the email is in the set and it was removed
+// */
+// public void removeCC(String email) {
+// removeAttributeValue(BugzillaReportElement.CC.getKeyString(), email);
+// }
+//
+// public void setDescription(String description) {
+// // ignore, used by NewBugReport
+// // this.description = decodeStringFromCharset(description);
+// }
+//
+// public void setKeywords(List<String> keywords) {
+// this.validKeywords = keywords;
+// }
+//
+// public void setOfflineState(boolean newOfflineState) {
+// savedOffline = newOfflineState;
+// }
+//
+// public void setSelectedOperation(RepositoryOperation o) {
+// selectedOperation = o;
+// }
+//
+// public RepositoryOperation getSelectedOperation() {
+// return selectedOperation;
+// }
+//
+// @Override
+// public RepositoryTaskAttributeFactory getAttributeFactory() {
+// return attributeFactory;
+// }
+//}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/IBugzillaConstants.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/IBugzillaConstants.java
new file mode 100644
index 000000000..50a5b6011
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/IBugzillaConstants.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.core;
+
+/**
+ * @author Mik Kersten (hardening of prototype
+ */
+public interface IBugzillaConstants {
+
+ // Error response from bugzilla server upon bug request
+ static final String ERROR_INVALID_BUG_ID = "InvalidBugId";
+
+ static final String ERROR_INVALID_USERNAME_OR_PASSWORD = "Invalid Username Or Password";
+
+ static final String MOST_RECENT_QUERY = "org.eclipse.mylar.bugzilla.query.last";
+
+ static final String SERVER_VERSION = "org.eclipse.mylar.bugzilla.server.version";
+
+// static final String SERVER_220 = "2.20";
+// static final String SERVER_218 = "2.18";
+
+ /** Used by search engine */
+ public static final int RETURN_ALL_HITS = -1;
+
+ public static final String CONTENT_TYPE_RDF = "&ctype=rdf";
+
+ /** Supported bugzilla repository versions */
+ static public enum BugzillaServerVersion {
+ SERVER_218, SERVER_220, SERVER_222;
+
+ @Override
+ public String toString() {
+ switch (this) {
+ case SERVER_222:
+ return "2.22";
+ case SERVER_220:
+ return "2.20";
+ case SERVER_218:
+ return "2.18";
+ default:
+ return "null";
+ }
+ }
+
+ /** returns null if version string unknown* */
+ static public BugzillaServerVersion fromString(String version) {
+ if (version.equals(SERVER_222.toString()))
+ return SERVER_222;
+ if (version.equals(SERVER_220.toString()))
+ return SERVER_220;
+ if (version.equals(SERVER_218.toString()))
+ return SERVER_218;
+ return null;
+ }
+ }
+
+ // static final String IS_216 = "BUGZILLA_IS_216";
+ // static final String IS_218 = "BUGZILLA_IS_218";
+ // static final String IS_220 = "BUGZILLA_IS_220";
+
+ static final String REFRESH_QUERY = "org.eclipse.mylar.bugzilla.query.refresh";
+
+ static final String MAX_RESULTS = "org.eclipse.mylar.bugzilla.search.results.max";
+
+ // names for the resources used to hold the different attributes of a bug
+ static final String VALUES_STATUS = "org.eclipse.mylar.bugzilla.values.status";
+
+ static final String VALUSE_STATUS_PRESELECTED = "org.eclipse.mylar.bugzilla.values.status.preselected";
+
+ static final String VALUES_RESOLUTION = "org.eclipse.mylar.bugzilla.values.resolution";
+
+ static final String VALUES_SEVERITY = "org.eclipse.mylar.bugzilla.values.severity";
+
+ static final String VALUES_PRIORITY = "org.eclipse.mylar.bugzilla.values.priority";
+
+ static final String VALUES_HARDWARE = "org.eclipse.mylar.bugzilla.values.hardware";
+
+ static final String VALUES_OS = "org.eclipse.mylar.bugzilla.values.os";
+
+ static final String VALUES_PRODUCT = "org.eclipse.mylar.bugzilla.values.product";
+
+ static final String VALUES_COMPONENT = "org.eclipse.mylar.bugzilla.values.component";
+
+ static final String VALUES_VERSION = "org.eclipse.mylar.bugzilla.values.version";
+
+ static final String VALUES_TARGET = "org.eclipse.mylar.bugzilla.values.target";
+
+ static final String ECLIPSE_BUGZILLA_URL = "https://bugs.eclipse.org/bugs";
+
+ static final String TEST_BUGZILLA_216_URL = "http://mylar.eclipse.org/bugs216";
+
+ static final String TEST_BUGZILLA_218_URL = "http://mylar.eclipse.org/bugs218";
+
+ static final String TEST_BUGZILLA_220_URL = "http://mylar.eclipse.org/bugs220";
+
+ static final String TEST_BUGZILLA_2201_URL = "http://mylar.eclipse.org/bugs2201";
+
+ static final String TEST_BUGZILLA_222_URL = "http://mylar.eclipse.org/bugs222";
+
+ // Default values for keys
+
+ static final String[] DEFAULT_STATUS_VALUES = { "Unconfirmed", "New", "Assigned", "Reopened", "Resolved",
+ "Verified", "Closed" };
+
+ static final String[] DEFAULT_PRESELECTED_STATUS_VALUES = { "New", "Assigned", "Reopened" };
+
+ // static final String[] DEFAULT_RESOLUTION_VALUES = { "Fixed", "Invalid",
+ // "Wontfix", "Later", "Remind", "Duplicate",
+ // "Worksforme", "Moved" };
+
+ static final String[] DEFAULT_SEVERITY_VALUES = { "blocker", "critical", "major", "normal", "minor", "trivial",
+ "enhancement" };
+
+ static final String[] DEFAULT_PRIORITY_VALUES = { "P1", "P2", "P3", "P4", "P5" };
+
+ static final String[] DEFAULT_HARDWARE_VALUES = { "All", "Macintosh", "PC", "Power PC", "Sun", "Other" };
+
+ static final String[] DEFAULT_OS_VALUES = { "All", "AIX Motif", "Windows 95", "Windows 98", "Windows CE",
+ "Windows ME", "Windows 2000", "Windows NT", "Windows XP", "Windows All", "MacOS X", "Linux", "Linux-GTK",
+ "Linux-Motif", "HP-UX", "Neutrino", "QNX-Photon", "Solaris", "Unix All", "other" };
+
+ static final String[] DEFAULT_PRODUCT_VALUES = {};
+
+ static final String[] DEFAULT_COMPONENT_VALUES = {};
+
+ static final String[] DEFAULT_VERSION_VALUES = {};
+
+ static final String[] DEFAULT_TARGET_VALUES = {};
+
+ public static final String TITLE_MESSAGE_DIALOG = "Mylar Bugzilla Connector";
+
+ public static final String TITLE_NEW_BUG = "New Bugzilla Report";
+
+ public static final String MESSAGE_LOGIN_FAILURE = "Bugzilla login information or repository version incorrect";
+
+ public static final String INVALID_2201_ATTRIBUTE_IGNORED = "EclipsebugsBugzilla2.20.1";
+
+ public static final String VALUE_STATUS_RESOLVED = "RESOLVED";
+
+ public static final String VALUE_STATUS_NEW = "NEW";
+
+ public static final String VALUE_STATUS_CLOSED = "CLOSED";
+
+ public static final String VALUE_STATUS_ASSIGNED = "ASSIGNED";
+
+ public static final String VALUE_RESOLUTION_LATER = "LATER";
+
+ public static enum BUGZILLA_OPERATION {
+ none, accept, resolve, duplicate, reassign, reassignbycomponent, reopen, verify, close;
+ }
+
+ public static enum BUGZILLA_REPORT_STATUS {
+ UNCONFIRMED, NEW, ASSIGNED, REOPENED, RESOLVED, VERIFIED, CLOSED;
+ }
+
+ public static enum BUGZILLA_REPORT_SEVERITY {
+ UNCONFIRMED, NEW, ASSIGNED, REOPENED, RESOLVED, VERIFIED, CLOSED;
+ }
+
+ public static enum BUGZILLA_RESOLUTION {
+ FIXED, INVALID, WONTFIX, LATER, REMIND, WORKSFORME;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/KeywordParser.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/KeywordParser.java
new file mode 100644
index 000000000..32469c701
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/KeywordParser.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer;
+import org.eclipse.mylar.internal.tasklist.util.HtmlTag;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer.Token;
+
+/**
+ * Parses Bugzilla keywords page to determine keywords valid in this
+ * installation
+ *
+ * @author Shawn Minto
+ */
+public class KeywordParser {
+ /** Tokenizer used on the stream */
+ private static HtmlStreamTokenizer tokenizer;
+
+ /**
+ * Constructor.
+ *
+ * @param in
+ * The input stream for the keywords page.
+ */
+ public KeywordParser(Reader in) {
+ tokenizer = new HtmlStreamTokenizer(in, null);
+ }
+
+ public String getEncoding() {
+ return "";
+ }
+
+ /**
+ * Parse the keyword page for the valid products that a bug can be logged
+ * for
+ *
+ * @return A list of the keywordds that we can enter bugs for
+ * @throws IOException
+ * @throws ParseException
+ */
+ public List<String> getKeywords() throws IOException, ParseException, LoginException {
+ ArrayList<String> keywords = new ArrayList<String>();
+
+ boolean isTitle = false;
+ boolean possibleBadLogin = false;
+ String title = "";
+
+ for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
+
+ // make sure that bugzilla doesn't want us to login
+ if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == HtmlTag.Type.TITLE
+ && !((HtmlTag) (token.getValue())).isEndTag()) {
+ isTitle = true;
+ continue;
+ }
+
+ if (isTitle) {
+ // get all of the data from inside of the title tag
+ if (token.getType() != Token.TAG) {
+ title += ((StringBuffer) token.getValue()).toString().toLowerCase() + " ";
+ continue;
+ } else if (token.getType() == Token.TAG
+ && ((HtmlTag) token.getValue()).getTagType() == HtmlTag.Type.TITLE
+ && ((HtmlTag) token.getValue()).isEndTag()) {
+ // check if we may have a problem with login by looking at
+ // the title of the page
+ if ((title.indexOf("login") != -1
+ || (title.indexOf("invalid") != -1 && title.indexOf("password") != -1)
+ || title.indexOf("check e-mail") != -1 || title.indexOf("error") != -1))
+ possibleBadLogin = true;
+ isTitle = false;
+ title = "";
+ }
+ continue;
+ }
+
+ if (token.getType() == Token.TAG) {
+ HtmlTag tag = (HtmlTag) token.getValue();
+ if (tag.getTagType() == HtmlTag.Type.TR && !tag.isEndTag()) {
+ token = tokenizer.nextToken();
+ if (token.getType() != Token.EOF && token.getType() == Token.TAG) {
+ tag = (HtmlTag) token.getValue();
+ if (tag.getTagType() != HtmlTag.Type.TH)
+ continue;
+ else {
+ if (tag.getAttribute("align") == null
+ || !"left".equalsIgnoreCase(tag.getAttribute("align")))
+ parseKeywords(keywords);
+
+ }
+ }
+ continue;
+ }
+ }
+ }
+
+ // if we don't have any keywords and suspect that there was a login
+ // problem, assume we had a login problem
+ if (keywords == null && possibleBadLogin)
+ throw new LoginException(IBugzillaConstants.MESSAGE_LOGIN_FAILURE);
+ return keywords;
+ }
+
+ /**
+ * Parse the keywords that we can enter bugs for
+ *
+ * @param keywords
+ * The list of keywords to add this new product to
+ * @return
+ */
+ private void parseKeywords(List<String> keywords) throws IOException, ParseException {
+ StringBuffer sb = new StringBuffer();
+
+ for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
+ if (token.getType() == Token.TAG) {
+ HtmlTag tag = (HtmlTag) token.getValue();
+ if (tag.getTagType() == HtmlTag.Type.TH
+ && (tag.isEndTag() || !"left".equalsIgnoreCase(tag.getAttribute("align"))))
+ break;
+ } else if (token.getType() == Token.TEXT)
+ sb.append(token.toString());
+ }
+
+ String prod = HtmlStreamTokenizer.unescape(sb).toString();
+ if (prod.endsWith(":"))
+ prod = prod.substring(0, prod.length() - 1);
+ keywords.add(prod);
+
+ for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
+ if (token.getType() == Token.TAG) {
+ HtmlTag tag = (HtmlTag) token.getValue();
+ if (tag.getTagType() == HtmlTag.Type.TR && tag.isEndTag())
+ break;
+
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/NewBugzillaReport.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/NewBugzillaReport.java
new file mode 100644
index 000000000..a8d9b6fef
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/NewBugzillaReport.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+
+
+/**
+ * This class is used to store data about the new bug that is being created
+ * while the wizard is being used
+ *
+ * @author Eric Booth
+ * @author Rob Elves
+ */
+public class NewBugzillaReport extends RepositoryTaskData implements Serializable {
+
+ /** Automatically generated serialVersionUID */
+ private static final long serialVersionUID = 3977859587934335283L;
+
+ /** Whether the attributes have been parsed yet or not */
+ protected boolean hasParsedAttributes = false;
+
+ /** Whether the products have been parsed yet or not */
+ protected boolean hasParsedProducts = false;
+
+ /** The product that the bug is for */
+ protected String product;
+
+ /** The summary for the bug */
+ protected String summary = "";
+
+ /** The description for the bug */
+ protected String description = "";
+
+ /**
+ * Flag to indicate status of connection to Bugzilla server to identify
+ * whether ProductConfiguration should be used instead
+ */
+ protected boolean connected = true;
+
+ /** Whether or not this bug report is saved offline. */
+ protected boolean savedOffline = false;
+
+ /**
+ * Creates a new <code>NewBugModel</code>. The id chosen for this bug is
+ * based on the id of the last <code>NewBugModel</code> that was created.
+ */
+ public NewBugzillaReport(String repositoryURL, int offlineId) {
+ super(new BugzillaAttributeFactory(), BugzillaPlugin.REPOSITORY_KIND, repositoryURL, offlineId);
+ }
+
+ public String getLabel() {
+ return "New Bug #" + getId();
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String newDescription) {
+ description = newDescription;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public void setSummary(String newSummary) {
+ summary = newSummary;
+ }
+
+ /**
+ * @return The product that the bug is for.
+ */
+ public String getProduct() {
+ return product;
+ }
+
+ /**
+ * Sets the product that the bug is for.
+ *
+ * @param product
+ * The product.
+ */
+ public void setProduct(String product) {
+ this.product = product;
+ }
+
+ /**
+ * @return Flag to indicate status of connection to Bugzilla server (to
+ * identify whether ProductConfiguration should be used instead)
+ */
+ public boolean isConnected() {
+ return connected;
+ }
+
+ /**
+ * Sets the value of the flag to indicate status of connection to Bugzilla
+ * server (to identify whether ProductConfiguration should be used instead)
+ *
+ * @param newConnectionStatus
+ * <code>true</code> if the bug is connected.
+ */
+ public void setConnected(boolean newConnectionStatus) {
+ connected = newConnectionStatus;
+ }
+
+ /**
+ * @return Returns whether the attributes have been parsed yet or not.
+ */
+ public boolean hasParsedAttributes() {
+ return hasParsedAttributes;
+ }
+
+ /**
+ * Sets whether the attributes have been parsed yet or not.
+ *
+ * @param hasParsedAttributes
+ * <code>true</code> if the attributes have been parsed.
+ */
+ public void setParsedAttributesStatus(boolean hasParsedAttributes) {
+ this.hasParsedAttributes = hasParsedAttributes;
+ }
+
+ /**
+ * @return Returns whether the products have been parsed yet or not.
+ */
+ public boolean hasParsedProducts() {
+ return hasParsedProducts;
+ }
+
+ /**
+ * Sets whether the products have been parsed yet or not.
+ *
+ * @param hasParsedProducts
+ * <code>true</code> if the products have been parsed.
+ */
+ public void setParsedProductsStatus(boolean hasParsedProducts) {
+ this.hasParsedProducts = hasParsedProducts;
+ }
+
+ public boolean isSavedOffline() {
+ return savedOffline;
+ }
+
+ public boolean isLocallyCreated() {
+ return true;
+ }
+
+// public void setOfflineState(boolean newOfflineState) {
+// savedOffline = newOfflineState;
+// }
+
+ public boolean hasChanges() {
+ return true;
+ }
+
+ /** returns null */
+ public Date getCreated() {
+ return null;
+ }
+
+ public Date getLastModified() {
+ return null;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfiguration.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfiguration.java
new file mode 100644
index 000000000..5f39b7e51
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfiguration.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class describing the configuration of products and components for a given
+ * Bugzilla installation.
+ *
+ * @author Rob Elves
+ */
+public class RepositoryConfiguration {
+
+ private static final String VERSION_UNKNOWN = "unknown";
+
+ private Map<String, ProductEntry> products = new HashMap<String, ProductEntry>();
+
+ private List<String> platforms = new ArrayList<String>();
+
+ private List<String> operatingSystems = new ArrayList<String>();
+
+ private List<String> priorities = new ArrayList<String>();
+
+ private List<String> severities = new ArrayList<String>();
+
+ private List<String> bugStatus = new ArrayList<String>();
+
+ private List<String> openStatusValues = new ArrayList<String>();
+
+ private List<String> resolutionValues = new ArrayList<String>();
+
+ private List<String> keywords = new ArrayList<String>();
+
+ // master lists
+
+ private List<String> versions = new ArrayList<String>();
+
+ private List<String> components = new ArrayList<String>();
+
+ private List<String> milestones = new ArrayList<String>();
+
+ private String version = VERSION_UNKNOWN;
+
+ public RepositoryConfiguration() {
+ super();
+ }
+
+ public void addStatus(String status) {
+ bugStatus.add(status);
+ }
+
+ public List<String> getStatusValues() {
+ return bugStatus;
+ }
+
+ public void addResolution(String res) {
+ resolutionValues.add(res);
+ }
+
+ public List<String> getResolutions() {
+ return resolutionValues;
+ }
+
+ /**
+ * Adds a product to the configuration.
+ */
+ public void addProduct(String name) {
+ if (!products.containsKey(name)) {
+ ProductEntry product = new ProductEntry(name);
+ products.put(name, product);
+ }
+ }
+
+ /**
+ * Returns an array of names of current products.
+ */
+ public List<String> getProducts() {
+ ArrayList<String> productList = new ArrayList<String>(products.keySet());
+ Collections.sort(productList);
+ return productList;
+ }
+
+ /**
+ * Returns an array of names of component that exist for a given product or
+ * <code>null</code> if the product does not exist.
+ */
+ public List<String> getComponents(String product) {
+ ProductEntry entry = products.get(product);
+ if (entry != null) {
+ return entry.getComponents();
+ } else
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns an array of names of versions that exist for a given product or
+ * <code>null</code> if the product does not exist.
+ */
+ public List<String> getVersions(String product) {
+ ProductEntry entry = products.get(product);
+ if (entry != null) {
+ return entry.getVersions();
+ } else
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns an array of names of valid severity values.
+ */
+ public List<String> getSeverities() {
+ return severities;
+ }
+
+ /**
+ * Returns an array of names of valid OS values.
+ */
+ public List<String> getOSs() {
+ return operatingSystems;
+ }
+
+ public void addOS(String os) {
+ operatingSystems.add(os);
+ }
+
+ /**
+ * Returns an array of names of valid platform values.
+ */
+ public List<String> getPlatforms() {
+ return platforms;
+ }
+
+ /**
+ * Returns an array of names of valid platform values.
+ */
+ public List<String> getPriorities() {
+ return priorities;
+ }
+
+ /**
+ * Adds a component to the given product.
+ */
+ public void addComponent(String product, String component) {
+ if (!components.contains(component))
+ components.add(component);
+ ProductEntry entry = products.get(product);
+ if (entry == null) {
+ entry = new ProductEntry(product);
+ products.put(product, entry);
+ }
+ entry.addComponent(component);
+ }
+
+ // /**
+ // * Adds a list of components to the given product.
+ // */
+ // public void addComponents(String product, List<String> components) {
+ // ProductEntry entry = products.get(product);
+ // if (entry == null) {
+ // entry = new ProductEntry(product);
+ // products.put(product, entry);
+ // }
+ // for (String component : components) {
+ // entry.addComponent(component);
+ // }
+ // }
+ // /**
+ // * Adds a list of components to the given product.
+ // */
+ // public void addComponents(String product, List<String> components) {
+ // ProductEntry entry = products.get(product);
+ // if (entry == null) {
+ // entry = new ProductEntry(product);
+ // products.put(product, entry);
+ // }
+ // for (String component : components) {
+ // entry.addComponent(component);
+ // }
+ // }
+
+ public void addVersion(String product, String version) {
+ if (!versions.contains(version))
+ versions.add(version);
+ ProductEntry entry = products.get(product);
+ if (entry == null) {
+ entry = new ProductEntry(product);
+ products.put(product, entry);
+ }
+ entry.addVersion(version);
+ }
+
+ // /**
+ // * Adds a list of components to the given product.
+ // */
+ // public void addVersions(String product, List<String> versions) {
+ // ProductEntry entry = products.get(product);
+ // if (entry == null) {
+ // entry = new ProductEntry(product);
+ // products.put(product, entry);
+ // }
+ // for (String version : versions) {
+ // entry.addVersion(version);
+ // }
+ // }
+
+ public void addKeyword(String keyword) {
+ keywords.add(keyword);
+ }
+
+ public List<String> getKeywords() {
+ return keywords;
+ }
+
+ public void addPlatform(String platform) {
+ platforms.add(platform);
+ }
+
+ public void addPriority(String priority) {
+ priorities.add(priority);
+ }
+
+ public void addSeverity(String severity) {
+ severities.add(severity);
+
+ }
+
+ public void setInstallVersion(String version) {
+ this.version = version;
+ }
+
+ public String getInstallVersion() {
+ return version;
+ }
+
+ public void addTargetMilestone(String product, String target) {
+ if (!milestones.contains(target))
+ milestones.add(target);
+ ProductEntry entry = products.get(product);
+ if (entry == null) {
+ entry = new ProductEntry(product);
+ products.put(product, entry);
+ }
+
+ entry.addTargetMilestone(target);
+
+ }
+
+ public List<String> getTargetMilestones(String product) {
+ ProductEntry entry = products.get(product);
+ if (entry != null) {
+ return entry.getTargetMilestones();
+ } else
+ return Collections.emptyList();
+ }
+
+ /**
+ * Container for product information: name, components.
+ */
+ private static class ProductEntry {
+
+ String productName;
+
+ List<String> components = new ArrayList<String>();
+
+ List<String> versions = new ArrayList<String>();
+
+ List<String> milestones = new ArrayList<String>();
+
+ ProductEntry(String name) {
+ this.productName = name;
+ }
+
+ List<String> getComponents() {
+ return components;
+ }
+
+ void addComponent(String componentName) {
+ if (!components.contains(componentName)) {
+ components.add(componentName);
+ }
+ }
+
+ List<String> getVersions() {
+ return versions;
+ }
+
+ void addVersion(String name) {
+ if (!versions.contains(name)) {
+ versions.add(name);
+ }
+ }
+
+ List<String> getTargetMilestones() {
+ return milestones;
+ }
+
+ void addTargetMilestone(String target) {
+ milestones.add(target);
+ }
+ }
+
+ public List<String> getOpenStatusValues() {
+ return openStatusValues;
+ }
+
+ public void addOpenStatusValue(String value) {
+ openStatusValues.add(value);
+ }
+
+ public List<String> getComponents() {
+ return components;
+ }
+
+ public List<String> getTargetMilestones() {
+ return milestones;
+ }
+
+ public List<String> getVersions() {
+ return versions;
+ }
+
+ /*
+ * Intermediate step until configuration is made generic.
+ */
+ public List<String> getOptionValues(BugzillaReportElement element, String product) {
+ switch (element) {
+ case PRODUCT:
+ return getProducts();
+ case TARGET_MILESTONE:
+ // return getTargetMilestones();
+ return getTargetMilestones(product);
+ case BUG_STATUS:
+ return getStatusValues();
+ case VERSION:
+ // return getVersions();
+ return getVersions(product);
+ case COMPONENT:
+ // return getComponents();
+ return getComponents(product);
+ case REP_PLATFORM:
+ return getPlatforms();
+ case OP_SYS:
+ return getOSs();
+ case PRIORITY:
+ return getPriorities();
+ case BUG_SEVERITY:
+ return getSeverities();
+ case KEYWORDS:
+ return getKeywords();
+ case RESOLUTION:
+ return getResolutions();
+ default:
+ return new ArrayList<String>();
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfigurationFactory.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfigurationFactory.java
new file mode 100644
index 000000000..c172fe997
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryConfigurationFactory.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.security.auth.login.LoginException;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Reads bugzilla product configuration from config.cgi on server in RDF format.
+ *
+ * @author Rob Elves
+ */
+public class RepositoryConfigurationFactory extends AbstractReportFactory {
+
+ private static final String CONFIG_RDF_URL = "/config.cgi?ctype=rdf";
+
+ private static RepositoryConfigurationFactory instance;
+
+ private RepositoryConfigurationFactory() {
+ // no initial setup needed
+ }
+
+ public static RepositoryConfigurationFactory getInstance() {
+ if (instance == null) {
+ instance = new RepositoryConfigurationFactory();
+ }
+ instance.setClean(true);
+ return instance;
+ }
+
+ public RepositoryConfiguration getConfiguration(String repositoryUrl, Proxy proxySettings, String userName,
+ String password, String encoding) throws IOException, KeyManagementException, LoginException,
+ NoSuchAlgorithmException {
+ String configUrlStr = repositoryUrl + CONFIG_RDF_URL;
+ configUrlStr = BugzillaRepositoryUtil.addCredentials(configUrlStr, userName, password);
+ URL url = new URL(configUrlStr);
+ SaxConfigurationContentHandler contentHandler = new SaxConfigurationContentHandler();
+ collectResults(url, proxySettings, encoding, contentHandler);
+ return contentHandler.getConfiguration();
+
+ }
+
+ // public RepositoryConfiguration getConfiguration(String server) throws
+ // IOException {
+ // URL serverURL = new URL(server + CONFIG_RDF_URL);
+ // BugzillaRepositoryUtil.addCredentials(repository, serverURL)
+ // URLConnection c = serverURL.openConnection();
+ // BufferedReader in = new BufferedReader(new
+ // InputStreamReader(c.getInputStream()));
+ //
+ // SaxConfigurationContentHandler contentHandler = new
+ // SaxConfigurationContentHandler();
+ //
+ // try {
+ // StringBuffer result = XmlCleaner.clean(in);
+ // StringReader strReader = new StringReader(result.toString());
+ // XMLReader reader = XMLReaderFactory.createXMLReader();
+ // reader.setErrorHandler(new SaxErrorHandler());
+ // reader.setContentHandler(contentHandler);
+ // reader.parse(new InputSource(strReader));
+ // } catch (SAXException e) {
+ // throw new IOException("Unable to read server configuration.");
+ // }
+ // return contentHandler.getConfiguration();
+ //
+ // }
+
+ class SaxErrorHandler implements ErrorHandler {
+
+ public void error(SAXParseException exception) throws SAXException {
+ throw exception;
+ // MylarStatusHandler.fail(exception, "ServerConfigurationFactory: "
+ // + exception.getLocalizedMessage(), false);
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXException {
+ throw exception;
+ // MylarStatusHandler.fail(exception, "ServerConfigurationFactory: "
+ // + exception.getLocalizedMessage(), false);
+ }
+
+ public void warning(SAXParseException exception) throws SAXException {
+ // ignore
+ }
+
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryReportFactory.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryReportFactory.java
new file mode 100644
index 000000000..d318c8ad0
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/RepositoryReportFactory.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+
+/**
+ * Reads bug reports from repository.
+ *
+ * @author Rob Elves
+ */
+public class RepositoryReportFactory extends AbstractReportFactory {
+
+ private static RepositoryReportFactory instance;
+
+ private static BugzillaAttributeFactory bugzillaAttributeFactory = new BugzillaAttributeFactory();
+
+ private static final String SHOW_BUG_CGI_XML = "/show_bug.cgi?ctype=xml&id=";
+
+ private RepositoryReportFactory() {
+ // no initial setup needed
+ }
+
+ public static RepositoryReportFactory getInstance() {
+ if (instance == null) {
+ instance = new RepositoryReportFactory();
+ }
+ return instance;
+ }
+
+ public void populateReport(RepositoryTaskData bugReport, String repositoryUrl, Proxy proxySettings, String userName,
+ String password, String characterEncoding) throws LoginException, KeyManagementException,
+ NoSuchAlgorithmException, IOException {
+
+ SaxBugReportContentHandler contentHandler = new SaxBugReportContentHandler(bugzillaAttributeFactory, bugReport);
+
+ String xmlBugReportUrl = repositoryUrl + SHOW_BUG_CGI_XML + bugReport.getId();
+ xmlBugReportUrl = BugzillaRepositoryUtil.addCredentials(xmlBugReportUrl, userName, password);
+ URL serverURL = new URL(xmlBugReportUrl);
+
+ collectResults(serverURL, proxySettings, characterEncoding, contentHandler);
+
+ if (contentHandler.errorOccurred()) {
+ throw new IOException(contentHandler.getErrorMessage());
+ }
+
+ }
+
+// public class BugzillaReportParseException extends IOException {
+// private static final long serialVersionUID = 1609566799047500866L;
+//
+// public BugzillaReportParseException(String message) {
+// super(message);
+// }
+// }
+}
+
+// URLConnection connection =
+// BugzillaPlugin.getDefault().getUrlConnection(serverURL, proxySettings);
+// if (connection == null || !(connection instanceof HttpURLConnection)) {
+// return;
+// }
+//
+// // String contentEncoding = connection.getContentEncoding();
+// // if (contentEncoding != null) {
+// // String charsetFromContentType =
+// // BugzillaRepositoryUtil.getCharsetFromString(contentEncoding);
+// // if (charsetFromContentType != null) {
+// // bugReport.setCharset(charsetFromContentType);
+// // }
+// // } else {
+// // bugReport.setCharset(BugzillaPlugin.ENCODING_UTF_8);
+// // }
+//
+// try {
+//
+// if (characterEncoding != null) {
+// in = new BufferedReader(new InputStreamReader(connection.getInputStream(),
+// characterEncoding));
+// } else {
+// in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+// }
+//
+// XMLReader reader = XMLReaderFactory.createXMLReader();
+// reader.setContentHandler(contentHandler);
+// reader.setErrorHandler(new SaxErrorHandler());
+// reader.parse(new InputSource(in));
+//
+// if (contentHandler.errorOccurred()) {
+// throw new BugzillaReportParseException(contentHandler.getErrorMessage());
+// }
+//
+// } catch (SAXException e) {
+// if
+// (e.getMessage().equals(IBugzillaConstants.ERROR_INVALID_USERNAME_OR_PASSWORD))
+// {
+// throw new LoginException(e.getMessage());
+// } else {
+// throw new IOException(e.getMessage());
+// }
+// } finally {
+// try {
+// if (in != null)
+// in.close();
+// } catch (IOException e) {
+// BugzillaPlugin.log(new Status(IStatus.ERROR, BugzillaPlugin.PLUGIN_ID,
+// IStatus.ERROR,
+// "Problem closing the stream", e));
+// }
+// }
+
+// class SaxErrorHandler implements ErrorHandler {
+//
+// public void error(SAXParseException exception) throws SAXException {
+// throw exception;
+// // MylarStatusHandler.fail(exception, "Mylar:
+// // RepositoryReportFactory Sax parser error", false);
+// // System.err.println("Error: " + exception.getLineNumber() + "\n" +
+// // exception.getLocalizedMessage());
+//
+// }
+//
+// public void fatalError(SAXParseException exception) throws SAXException {
+// // System.err.println("Fatal Error: " + exception.getLineNumber() +
+// // "\n" + exception.getLocalizedMessage());
+// // TODO: Need to determine actual error from html
+// throw new
+// SAXException(IBugzillaConstants.ERROR_INVALID_USERNAME_OR_PASSWORD);
+// }
+//
+// public void warning(SAXParseException exception) throws SAXException {
+// // System.err.println("Warning: " + exception.getLineNumber() + "\n"
+// // + exception.getLocalizedMessage());
+// }
+//
+// }
+// \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxBugReportContentHandler.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxBugReportContentHandler.java
new file mode 100644
index 000000000..354681314
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxBugReportContentHandler.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mylar.internal.tasklist.AbstractAttributeFactory;
+import org.eclipse.mylar.internal.tasklist.Comment;
+import org.eclipse.mylar.internal.tasklist.RepositoryAttachment;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttribute;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Parser for xml bugzilla reports.
+ *
+ * @author Rob Elves
+ */
+public class SaxBugReportContentHandler extends DefaultHandler {
+
+ private static final String COMMENT_ATTACHMENT_STRING = "Created an attachment (id=";
+
+ private StringBuffer characters;
+
+ private Comment comment;
+
+ private final Map<Integer, Comment> attachIdToComment = new HashMap<Integer, Comment>();
+
+ private int commentNum = 0;
+
+ private RepositoryAttachment attachment;
+
+ private RepositoryTaskData report;
+
+ private String errorMessage = null;
+
+ private AbstractAttributeFactory attributeFactory;
+
+ public SaxBugReportContentHandler(AbstractAttributeFactory factory, RepositoryTaskData rpt) {
+ this.attributeFactory = factory;
+ this.report = rpt;
+ }
+
+ public boolean errorOccurred() {
+ return errorMessage != null;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public RepositoryTaskData getReport() {
+ return report;
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ characters.append(ch, start, length);
+// if (monitor.isCanceled()) {
+// throw new OperationCanceledException("Search cancelled");
+// }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ characters = new StringBuffer();
+ BugzillaReportElement tag = BugzillaReportElement.UNKNOWN;
+ try {
+ tag = BugzillaReportElement.valueOf(localName.trim().toUpperCase());
+ } catch (RuntimeException e) {
+ if (e instanceof IllegalArgumentException) {
+ // ignore unrecognized tags
+ return;
+ }
+ throw e;
+ }
+ switch (tag) {
+ case BUGZILLA:
+ // Note: here we can get the bugzilla version if necessary
+ break;
+ case BUG:
+ if (attributes != null && (attributes.getValue("error") != null)) {
+ errorMessage = attributes.getValue("error");
+ }
+ break;
+ case LONG_DESC:
+ comment = new Comment(attributeFactory, report, commentNum++);
+ break;
+ case ATTACHMENT:
+ attachment = new RepositoryAttachment(attributeFactory);
+ if (attributes != null && (attributes.getValue(BugzillaReportElement.IS_OBSOLETE.getKeyString()) != null)) {
+ attachment.addAttribute(BugzillaReportElement.IS_OBSOLETE.getKeyString(), attributeFactory.createAttribute(BugzillaReportElement.IS_OBSOLETE.getKeyString()));
+ }
+ break;
+ }
+
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+
+ String parsedText = HtmlStreamTokenizer.unescape(characters.toString());
+
+ BugzillaReportElement tag = BugzillaReportElement.UNKNOWN;
+ try {
+ tag = BugzillaReportElement.valueOf(localName.trim().toUpperCase());
+ } catch (RuntimeException e) {
+ if (e instanceof IllegalArgumentException) {
+ // ignore unrecognized tags
+ return;
+ }
+ throw e;
+ }
+ switch (tag) {
+ case BUG_ID: {
+ try {
+ if (report.getId() != Integer.parseInt(parsedText)) {
+ errorMessage = "Requested report number does not match returned report number.";
+ }
+ } catch (NumberFormatException e) {
+ errorMessage = "Bug id from server did not match requested id.";
+ }
+
+ RepositoryTaskAttribute attr = report.getAttribute(tag.getKeyString());
+ if (attr == null) {
+ attr = attributeFactory.createAttribute(tag.getKeyString());
+ report.addAttribute(tag.getKeyString(), attr);
+ }
+ attr.setValue(parsedText);
+ break;
+ }
+
+ // Comment attributes
+ case WHO:
+ case BUG_WHEN:
+ if (comment != null) {
+ RepositoryTaskAttribute attr = attributeFactory.createAttribute(tag.getKeyString());
+ attr.setValue(parsedText);
+ comment.addAttribute(tag.getKeyString(), attr);
+ }
+ break;
+ case THETEXT:
+ if (comment != null) {
+ RepositoryTaskAttribute attr = attributeFactory.createAttribute(tag.getKeyString());
+ attr.setValue(parsedText);
+ comment.addAttribute(tag.getKeyString(), attr);
+
+ // Check for attachment
+ parseAttachment(comment, parsedText);
+ }
+ break;
+ case LONG_DESC:
+ if (comment != null) {
+ report.addComment(comment);
+ }
+ break;
+
+ // Attachment attributes
+ case ATTACHID:
+ case DATE:
+ case DESC:
+ case FILENAME:
+ case CTYPE:
+ case TYPE:
+ if (attachment != null) {
+ RepositoryTaskAttribute attr = attributeFactory.createAttribute(tag.getKeyString());
+ attr.setValue(parsedText);
+ attachment.addAttribute(tag.getKeyString(), attr);
+ }
+ break;
+ case DATA:
+ // TODO: Need to figure out under what circumstanceswhen attachments
+ // are inline and
+ // what to do with them.
+ break;
+ case ATTACHMENT:
+ if (attachment != null) {
+ report.addAttachment(attachment);
+ }
+ break;
+
+ // IGNORED ELEMENTS
+ case REPORTER_ACCESSIBLE:
+ case CLASSIFICATION_ID:
+ case CLASSIFICATION:
+ case CCLIST_ACCESSIBLE:
+ case EVERCONFIRMED:
+ case BUGZILLA:
+ break;
+ case BUG:
+ // Reached end of bug. Need to set LONGDESCLENGTH to number of
+ // comments
+ RepositoryTaskAttribute numCommentsAttribute = report
+ .getAttribute(BugzillaReportElement.LONGDESCLENGTH.getKeyString());
+ if (numCommentsAttribute == null) {
+ numCommentsAttribute = attributeFactory.createAttribute(BugzillaReportElement.LONGDESCLENGTH.getKeyString());
+ numCommentsAttribute.setValue("" + report.getComments().size());
+ report.addAttribute(BugzillaReportElement.LONGDESCLENGTH.getKeyString(), numCommentsAttribute);
+ } else {
+ numCommentsAttribute.setValue("" + report.getComments().size());
+ }
+
+ // Set the creator name on all attachments
+ for (RepositoryAttachment attachment: report.getAttachments()) {
+ Comment comment = (Comment)attachIdToComment.get(attachment.getId());
+ if(comment != null) {
+ attachment.setCreator(comment.getAuthor());
+ }
+ }
+ break;
+
+ // All others added as report attribute
+ default:
+ RepositoryTaskAttribute attribute = report.getAttribute(tag.getKeyString());
+ if (attribute == null) {
+ attribute = attributeFactory.createAttribute(tag.getKeyString());
+ attribute.setValue(parsedText);
+ report.addAttribute(tag.getKeyString(), attribute);
+ } else {
+ attribute.addValue(parsedText);
+ }
+ break;
+ }
+
+ }
+
+ /** determines attachment id from comment */
+ private void parseAttachment(Comment comment, String commentText) {
+
+ int attachmentID = -1;
+
+ if (commentText.startsWith(COMMENT_ATTACHMENT_STRING)) {
+ try {
+ int endIndex = commentText.indexOf(")");
+ if (endIndex > 0 && endIndex < commentText.length()) {
+ attachmentID = Integer
+ .parseInt(commentText.substring(COMMENT_ATTACHMENT_STRING.length(), endIndex));
+ comment.setHasAttachment(true);
+ comment.setAttachmentId(attachmentID);
+ attachIdToComment.put(attachmentID, comment);
+ }
+ } catch (NumberFormatException e) {
+ return;
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxConfigurationContentHandler.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxConfigurationContentHandler.java
new file mode 100644
index 000000000..7729a5af5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/SaxConfigurationContentHandler.java
@@ -0,0 +1,399 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Quick config rdf parser.
+ *
+ * <pre>
+ * config.cgi?ctype=rdf
+ * </pre>
+ *
+ * Populates a <link>ProductConfiguration</link> data structure.
+ *
+ * @author Rob Elves
+ */
+public class SaxConfigurationContentHandler extends DefaultHandler {
+
+ private static final String ELEMENT_RESOLUTION = "resolution";
+
+ private static final String ELEMENT_STATUS_OPEN = "status_open";
+
+ private static final String ELEMENT_TARGET_MILESTONE = "target_milestone";
+
+ private static final String ELEMENT_TARGET_MILESTONES = "target_milestones";
+
+ private static final String ELEMENT_INSTALL_VERSION = "install_version";
+
+ private static final String ATTRIBUTE_RDF_ABOUT = "rdf:about";
+
+ private static final String ATTRIBUTE_RESOURCE = "resource";
+
+ private static final String ELEMENT_VERSION = "version";
+
+ private static final String ELEMENT_VERSIONS = "versions";
+
+ private static final String ELEMENT_COMPONENT = "component";
+
+ private static final String ELEMENT_COMPONENTS = "components";
+
+ private static final String ELEMENT_NAME = "name";
+
+ private static final String ELEMENT_PRODUCTS = "products";
+
+ private static final String ELEMENT_SEVERITY = "severity";
+
+ private static final String ELEMENT_PRIORITY = "priority";
+
+ private static final String ELEMENT_KEYWORD = "keyword";
+
+ private static final String ELEMENT_OP_SYS = "op_sys";
+
+ private static final String ELEMENT_PLATFORM = "platform";
+
+ private static final String ELEMENT_LI = "li";
+
+ private static final String ELEMENT_STATUS = "status";
+
+ private static final int EXPECTING_ROOT = 0;
+
+ private static final int IN_INSTALL_VERSION = 1 << 1;
+
+ private static final int IN_STATUS = 1 << 2;
+
+ private static final int IN_PLATFORM = 1 << 3;
+
+ private static final int IN_OP_SYS = 1 << 4;
+
+ private static final int IN_PRIORITY = 1 << 5;
+
+ private static final int IN_SEVERITY = 1 << 6;
+
+ private static final int IN_PRODUCTS = 1 << 7;
+
+ private static final int IN_COMPONENTS = 1 << 8;
+
+ private static final int IN_VERSIONS = 1 << 9;
+
+ private static final int IN_LI = 1 << 10;
+
+ private static final int IN_LI_LI = 1 << 11;
+
+ private static final int IN_NAME = 1 << 12;
+
+ private static final int IN_COMPONENT = 1 << 13;
+
+ private static final int IN_VERSION = 1 << 14;
+
+ private static final int IN_TARGET_MILESTONES = 1 << 15;
+
+ private static final int IN_TARGET_MILESTONE = 1 << 16;
+
+ private static final int IN_STATUS_OPEN = 1 << 17;
+
+ private static final int IN_RESOLUTION = 1 << 18;
+
+ private static final int IN_KEYWORD = 1 << 19;
+
+ private int state = EXPECTING_ROOT;
+
+ private String currentProduct;
+
+ private String about;
+
+ private RepositoryConfiguration configuration = new RepositoryConfiguration();
+
+ private Map<String, List<String>> components = new HashMap<String, List<String>>();
+
+ private Map<String, List<String>> versions = new HashMap<String, List<String>>();
+
+ private Map<String, List<String>> milestones = new HashMap<String, List<String>>();
+
+ private Map<String, String> componentNames = new HashMap<String, String>();
+
+ private Map<String, String> versionNames = new HashMap<String, String>();
+
+ private Map<String, String> milestoneNames = new HashMap<String, String>();
+
+ public RepositoryConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ switch (state) {
+
+ case IN_PRODUCTS | IN_LI | IN_NAME:
+ configuration.addProduct(String.copyValueOf(ch, start, length));
+ currentProduct = String.copyValueOf(ch, start, length);
+ break;
+ case IN_COMPONENTS | IN_LI | IN_COMPONENT | IN_NAME:
+ if (about != null) {
+ String name = String.copyValueOf(ch, start, length);
+ componentNames.put(about, name);
+ // System.err.println("Component: "+about+" ---> "+name);
+ }
+ break;
+ case IN_VERSIONS | IN_LI | IN_VERSION | IN_NAME:
+ if (about != null) {
+ String name = String.copyValueOf(ch, start, length);
+ versionNames.put(about, name);
+ // System.err.println("Version: "+about+" ---> "+name);
+ }
+ break;
+ case IN_TARGET_MILESTONES | IN_LI | IN_TARGET_MILESTONE | IN_NAME:
+ if (about != null) {
+ String name = String.copyValueOf(ch, start, length);
+ milestoneNames.put(about, name);
+ // System.err.println("Version: "+about+" ---> "+name);
+ }
+ break;
+ case IN_PLATFORM | IN_LI:
+ configuration.addPlatform(String.copyValueOf(ch, start, length));
+ break;
+ case IN_OP_SYS | IN_LI:
+ configuration.addOS(String.copyValueOf(ch, start, length));
+ break;
+ case IN_PRIORITY | IN_LI:
+ configuration.addPriority(String.copyValueOf(ch, start, length));
+ break;
+ case IN_SEVERITY | IN_LI:
+ configuration.addSeverity(String.copyValueOf(ch, start, length));
+ break;
+ case IN_INSTALL_VERSION:
+ configuration.setInstallVersion(String.copyValueOf(ch, start, length));
+ break;
+ case IN_STATUS | IN_LI:
+ configuration.addStatus(String.copyValueOf(ch, start, length));
+ break;
+ case IN_RESOLUTION | IN_LI:
+ configuration.addResolution(String.copyValueOf(ch, start, length));
+ break;
+ case IN_KEYWORD | IN_LI:
+ configuration.addKeyword(String.copyValueOf(ch, start, length));
+ break;
+ case IN_STATUS_OPEN | IN_LI:
+ configuration.addOpenStatusValue(String.copyValueOf(ch, start, length));
+ break;
+ }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+
+ if (localName.equals(ELEMENT_STATUS)) {
+ state = state | IN_STATUS;
+ } else if (localName.equals(ELEMENT_LI) && ((state & IN_LI) == IN_LI)) {
+ state = state | IN_LI_LI;
+ parseResource(attributes);
+ } else if (localName.equals(ELEMENT_LI) && ((state & IN_LI) != IN_LI)) {
+ state = state | IN_LI;
+ } else if (localName.equals(ELEMENT_PLATFORM)) {
+ state = state | IN_PLATFORM;
+ } else if (localName.equals(ELEMENT_OP_SYS)) {
+ state = state | IN_OP_SYS;
+ } else if (localName.equals(ELEMENT_PRIORITY)) {
+ state = state | IN_PRIORITY;
+ } else if (localName.equals(ELEMENT_SEVERITY)) {
+ state = state | IN_SEVERITY;
+ } else if (localName.equals(ELEMENT_PRODUCTS)) {
+ state = state | IN_PRODUCTS;
+ } else if (localName.equals(ELEMENT_OP_SYS)) {
+ state = state | IN_OP_SYS;
+ } else if (localName.equals(ELEMENT_NAME)) {
+ state = state | IN_NAME;
+ } else if (localName.equals(ELEMENT_COMPONENTS)) {
+ state = state | IN_COMPONENTS;
+ } else if (localName.equals(ELEMENT_COMPONENT)) {
+ state = state | IN_COMPONENT;
+ parseResource(attributes);
+ } else if (localName.equals(ELEMENT_VERSIONS)) {
+ state = state | IN_VERSIONS;
+ } else if (localName.equals(ELEMENT_VERSION)) {
+ state = state | IN_VERSION;
+ parseResource(attributes);
+ } else if (localName.equals(ELEMENT_INSTALL_VERSION)) {
+ state = state | IN_INSTALL_VERSION;
+ } else if (localName.equals(ELEMENT_TARGET_MILESTONES)) {
+ state = state | IN_TARGET_MILESTONES;
+ } else if (localName.equals(ELEMENT_TARGET_MILESTONE)) {
+ state = state | IN_TARGET_MILESTONE;
+ parseResource(attributes);
+ } else if (localName.equals(ELEMENT_STATUS_OPEN)) {
+ state = state | IN_STATUS_OPEN;
+ } else if (localName.equals(ELEMENT_RESOLUTION)) {
+ state = state | IN_RESOLUTION;
+ } else if (localName.equals(ELEMENT_KEYWORD)) {
+ state = state | IN_KEYWORD;
+ }
+
+ }
+
+ private void parseResource(Attributes attributes) {
+
+ switch (state) {
+ case IN_PRODUCTS | IN_LI | IN_COMPONENTS | IN_LI_LI:
+ if (attributes != null) {
+ String compURI = attributes.getValue(ATTRIBUTE_RESOURCE);
+ if (compURI != null) {
+
+ List<String> compURIs = components.get(currentProduct);
+ if (compURIs == null) {
+ compURIs = new ArrayList<String>();
+ components.put(currentProduct, compURIs);
+ }
+ compURIs.add(compURI);
+
+ }
+ }
+ break;
+ case IN_PRODUCTS | IN_LI | IN_VERSIONS | IN_LI_LI:
+ if (attributes != null) {
+ String resourceURI = attributes.getValue(ATTRIBUTE_RESOURCE);
+ if (resourceURI != null) {
+ List<String> versionUris = versions.get(currentProduct);
+ if (versionUris == null) {
+ versionUris = new ArrayList<String>();
+ versions.put(currentProduct, versionUris);
+ }
+ versionUris.add(resourceURI);
+ }
+ }
+ break;
+ case IN_PRODUCTS | IN_LI | IN_TARGET_MILESTONES | IN_LI_LI:
+ if (attributes != null) {
+ String resourceURI = attributes.getValue(ATTRIBUTE_RESOURCE);
+ if (resourceURI != null) {
+ List<String> milestoneUris = milestones.get(currentProduct);
+ if (milestoneUris == null) {
+ milestoneUris = new ArrayList<String>();
+ milestones.put(currentProduct, milestoneUris);
+ }
+ milestoneUris.add(resourceURI);
+ }
+ }
+ break;
+ case IN_COMPONENTS | IN_LI | IN_COMPONENT:
+ if (attributes != null) {
+ about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
+ }
+ break;
+ case IN_VERSIONS | IN_LI | IN_VERSION:
+ if (attributes != null) {
+ about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
+ }
+ break;
+
+ case IN_TARGET_MILESTONES | IN_LI | IN_TARGET_MILESTONE:
+ if (attributes != null) {
+ about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
+ }
+ break;
+
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+
+ // KEEP: && ((state & IN_LI) == IN_LI)
+
+ if (localName.equals(ELEMENT_STATUS)) {
+ state = state & ~IN_STATUS;
+ } else if (localName.equals(ELEMENT_LI) && ((state & IN_LI_LI) == IN_LI_LI)) {
+ state = state & ~IN_LI_LI;
+ } else if (localName.equals(ELEMENT_LI) && ((state & IN_LI_LI) != IN_LI_LI)) {
+ state = state & ~IN_LI;
+ } else if (localName.equals(ELEMENT_PLATFORM)) {
+ state = state & ~IN_PLATFORM;
+ } else if (localName.equals(ELEMENT_OP_SYS)) {
+ state = state & ~IN_OP_SYS;
+ } else if (localName.equals(ELEMENT_PRIORITY)) {
+ state = state & ~IN_PRIORITY;
+ } else if (localName.equals(ELEMENT_SEVERITY)) {
+ state = state & ~IN_SEVERITY;
+ } else if (localName.equals(ELEMENT_PRODUCTS)) {
+ state = state & ~IN_PRODUCTS;
+ } else if (localName.equals(ELEMENT_OP_SYS)) {
+ state = state & ~IN_OP_SYS;
+ } else if (localName.equals(ELEMENT_NAME)) {
+ state = state & ~IN_NAME;
+ } else if (localName.equals(ELEMENT_COMPONENTS)) {
+ state = state & ~IN_COMPONENTS;
+ } else if (localName.equals(ELEMENT_COMPONENT)) {
+ state = state & ~IN_COMPONENT;
+ } else if (localName.equals(ELEMENT_VERSION)) {
+ state = state & ~IN_VERSION;
+ } else if (localName.equals(ELEMENT_VERSIONS)) {
+ state = state & ~IN_VERSIONS;
+ } else if (localName.equals(ELEMENT_INSTALL_VERSION)) {
+ state = state & ~IN_INSTALL_VERSION;
+ } else if (localName.equals(ELEMENT_TARGET_MILESTONE)) {
+ state = state & ~IN_TARGET_MILESTONE;
+ } else if (localName.equals(ELEMENT_TARGET_MILESTONES)) {
+ state = state & ~IN_TARGET_MILESTONES;
+ } else if (localName.equals(ELEMENT_STATUS_OPEN)) {
+ state = state & ~IN_STATUS_OPEN;
+ } else if (localName.equals(ELEMENT_RESOLUTION)) {
+ state = state & ~IN_RESOLUTION;
+ } else if (localName.equals(ELEMENT_KEYWORD)) {
+ state = state & ~IN_KEYWORD;
+ }
+
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+
+ for (String product : components.keySet()) {
+ List<String> componentURIs = components.get(product);
+ for (String uri : componentURIs) {
+ String realName = componentNames.get(uri);
+ if (realName != null) {
+ configuration.addComponent(product, realName);
+ }
+ }
+ }
+
+ for (String product : versions.keySet()) {
+ List<String> versionURIs = versions.get(product);
+ for (String uri : versionURIs) {
+ String realName = versionNames.get(uri);
+ if (realName != null) {
+ configuration.addVersion(product, realName);
+ }
+ }
+
+ }
+
+ for (String product : milestones.keySet()) {
+ List<String> milestoneURIs = milestones.get(product);
+ for (String uri : milestoneURIs) {
+ String realName = milestoneNames.get(uri);
+ if (realName != null) {
+ configuration.addTargetMilestone(product, realName);
+ }
+ }
+
+ }
+ super.endDocument();
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/XmlCleaner.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/XmlCleaner.java
new file mode 100644
index 000000000..764b37e54
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/XmlCleaner.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.core;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.text.ParseException;
+
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer;
+import org.eclipse.mylar.internal.tasklist.util.HtmlTag;
+import org.eclipse.mylar.internal.tasklist.util.HtmlStreamTokenizer.Token;
+
+/**
+ * This is in place to escape & characters within the resource and rdf:about
+ * attributes. Currently the values are not escaped which causes sax parser
+ * errors. This bug has been filed and can be found here:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=264785
+ *
+ * @author Rob Elves
+ */
+public class XmlCleaner {
+
+ public static StringBuffer clean(Reader in) {
+
+ HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(in, null);
+ StringBuffer content = new StringBuffer();
+
+ // Hack since HtmlStreamTokenizer not familiar with xml tag.
+ content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ try {
+ for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
+
+ if (token.getType() == Token.TAG) {
+ HtmlTag tag = (HtmlTag) token.getValue();
+ if (tag.getAttribute("resource") != null) {
+ String resourceID = tag.getAttribute("resource");
+ tag.setAttribute("resource", resourceID.replace("&", "&amp;"));
+ }
+ if (tag.getAttribute("rdf:about") != null) {
+ String resourceID = tag.getAttribute("rdf:about");
+ tag.setAttribute("rdf:about", resourceID.replace("&", "&amp;"));
+ }
+ }
+ if (!token.toString().startsWith("<?xml")) {
+ content.append(token.toString());
+ }
+ }
+ } catch (IOException e) {
+
+ } catch (ParseException e) {
+
+ }
+ return content;
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/.classpath b/org.eclipse.mylyn.bugzilla.tests/.classpath
new file mode 100644
index 000000000..472ee29b1
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.mylyn.bugzilla.tests/META-INF/MANIFEST.MF b/org.eclipse.mylyn.bugzilla.tests/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..3ba5d1f32
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,24 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Bugzilla Tests Plug-in
+Bundle-SymbolicName: org.eclipse.mylar.bugzilla.tests
+Bundle-Version: 0.0.0
+Bundle-Activator: org.eclipse.mylar.bugzilla.tests.BugzillaTestPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.junit,
+ org.eclipse.ui.ide,
+ org.eclipse.ui.views,
+ org.eclipse.ui.editors,
+ org.eclipse.ui.workbench.texteditor,
+ org.eclipse.mylar.bugzilla.core,
+ org.eclipse.mylar.bugzilla.ui,
+ org.eclipse.mylar.tasklist,
+ org.eclipse.mylar.core.tests,
+ org.eclipse.jface.text
+Eclipse-AutoStart: true
+Bundle-Vendor: Eclipse.org
+Bundle-ClassPath: bugzilla-test.jar
+Export-Package: org.eclipse.mylar.bugzilla.tests
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/AllBugzillaTests.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/AllBugzillaTests.java
new file mode 100644
index 000000000..ca53c0f7c
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/AllBugzillaTests.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.bugzilla.tests;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * @author Mik Kersten
+ */
+public class AllBugzillaTests {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite("Test for org.eclipse.mylar.bugzilla.tests");
+ // $JUnit-BEGIN$
+ suite.addTestSuite(BugzillaConfigurationTest.class);
+ suite.addTestSuite(BugzillaTaskHyperlinkDetectorTest.class);
+ suite.addTestSuite(ReportAttachmentTest.class);
+ suite.addTestSuite(BugzillaSearchEngineTest.class);
+ suite.addTestSuite(Bugzilla220ParserTest.class);
+ suite.addTestSuite(BugzillaRepositoryConnectorTest.class);
+ suite.addTestSuite(EncodingTest.class);
+ suite.addTestSuite(NewBugWizardTest.class);
+ suite.addTestSuite(RegularExpressionMatchTest.class);
+ // suite.addTestSuite(BugzillaNewBugParserTestCDT.class);
+ // suite.addTestSuite(BugzillaNewBugParserTestEquinox.class);
+ // suite.addTestSuite(BugzillaNewBugParserTestGMT.class);
+ // suite.addTestSuite(BugzillaNewBugParserTestPlatform.class);
+ // suite.addTestSuite(BugzillaNewBugParserTestVE.class);
+ suite.addTestSuite(BugzillaParserTestNoBug.class);
+ suite.addTestSuite(BugzillaProductParserTest.class);
+ // TODO: enable
+ // suite.addTest(new TestSuite(BugzillaParserTest.class));
+ // $JUnit-END$
+ return suite;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/Bugzilla220ParserTest.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/Bugzilla220ParserTest.java
new file mode 100644
index 000000000..41ed3bd79
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/Bugzilla220ParserTest.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.bugzilla.tests;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.core.tests.support.FileTool;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.NewBugModel;
+import org.eclipse.mylar.internal.bugzilla.core.internal.BugParser;
+import org.eclipse.mylar.internal.bugzilla.core.internal.NewBugParser;
+
+/**
+ * @author Mik Kersten
+ * @author Rob Elves
+ */
+public class Bugzilla220ParserTest extends TestCase {
+
+ public static final String TEST_SERVER = IBugzillaConstants.ECLIPSE_BUGZILLA_URL;
+
+ private static final String PRODUCT_MYLAR = "Mylar";
+
+ private static final String PRODUCT_TEST = "TestProduct";
+
+ public void testId220() throws Exception {
+
+ File f = FileTool.getFileInPlugin(BugzillaTestPlugin.getDefault(), new Path(
+ "testdata/pages/test-report-220.html"));
+ Reader in = new FileReader(f);
+
+ BugReport bug = BugParser.parseBug(in, 7, TEST_SERVER, false, null, null, null);
+
+ assertEquals(7, bug.getId());
+ assertEquals("summary", bug.getSummary());
+ assertEquals("7", bug.getAttribute("Bug#").getValue());
+ assertEquals("7", bug.getAttribute("id").getValue());
+ }
+
+ public void testId2201() throws Exception {
+
+ File f = FileTool.getFileInPlugin(BugzillaTestPlugin.getDefault(), new Path(
+ "testdata/pages/test-report-2201.html"));
+ Reader in = new FileReader(f);
+
+ BugReport bug = BugParser.parseBug(in, 125527, TEST_SERVER, false, null, null, null);
+
+ assertEquals(125527, bug.getId());
+ assertEquals("bugzilla refresh incorrect for new reports and newly opened hits", bug.getSummary());
+ assertEquals("125527", bug.getAttribute("Bug#").getValue());
+ assertEquals("125527", bug.getAttribute("id").getValue());
+ }
+
+ public void testNewBugProduct220() throws Exception {
+
+ NewBugModel nbm = new NewBugModel();
+
+ File f = FileTool
+ .getFileInPlugin(BugzillaTestPlugin.getDefault(), new Path("testdata/pages/enter-bug220.html"));
+ Reader in = new FileReader(f);
+
+ new NewBugParser(in).parseBugAttributes(nbm, true);
+ assertEquals(PRODUCT_TEST, nbm.getAttribute("product").getValue());
+ }
+
+ public void testNewBugProduct2201() throws Exception {
+
+ NewBugModel nbm = new NewBugModel();
+
+ File f = FileTool.getFileInPlugin(BugzillaTestPlugin.getDefault(),
+ new Path("testdata/pages/enter-bug2201.html"));
+ Reader in = new FileReader(f);
+
+ new NewBugParser(in).parseBugAttributes(nbm, true);
+ assertEquals(PRODUCT_MYLAR, nbm.getAttribute("product").getValue());
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaConfigurationTest.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaConfigurationTest.java
new file mode 100644
index 000000000..79e7a99b5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaConfigurationTest.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.bugzilla.tests;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.internal.RepositoryConfiguration;
+import org.eclipse.mylar.internal.bugzilla.core.internal.ServerConfigurationFactory;
+
+public class BugzillaConfigurationTest extends TestCase {
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+
+ public void test222RDFProductConfig() throws IOException {
+ ServerConfigurationFactory factory = ServerConfigurationFactory.getInstance();
+ RepositoryConfiguration config = factory.getConfiguration(IBugzillaConstants.TEST_BUGZILLA_222_URL);
+ assertNotNull(config);
+ assertEquals("2.22rc1", config.getInstallVersion());
+ assertEquals(7, config.getStatusValues().size());
+ assertEquals(8, config.getResolutions().size());
+ assertEquals(4, config.getPlatforms().size());
+ assertEquals(5, config.getOSs().size());
+ assertEquals(5, config.getPriorities().size());
+ assertEquals(7, config.getSeverities().size());
+ assertEquals(1, config.getProducts().size());
+ assertEquals(4, config.getOpenStatusValues().size());
+ assertEquals(1, config.getComponents("TestProduct").size());
+ assertEquals(1, config.getVersions("TestProduct").size());
+ assertEquals(1, config.getTargetMilestones("TestProduct").size());
+ }
+
+ public void test2201RDFProductConfig() throws IOException {
+ ServerConfigurationFactory factory = ServerConfigurationFactory.getInstance();
+ RepositoryConfiguration config = factory.getConfiguration(IBugzillaConstants.TEST_BUGZILLA_2201_URL);
+ assertNotNull(config);
+ assertEquals("2.20.1", config.getInstallVersion());
+ assertEquals(7, config.getStatusValues().size());
+ assertEquals(8, config.getResolutions().size());
+ assertEquals(4, config.getPlatforms().size());
+ assertEquals(5, config.getOSs().size());
+ assertEquals(5, config.getPriorities().size());
+ assertEquals(7, config.getSeverities().size());
+ assertEquals(1, config.getProducts().size());
+ assertEquals(4, config.getOpenStatusValues().size());
+ assertEquals(2, config.getComponents("TestProduct").size());
+ assertEquals(1, config.getVersions("TestProduct").size());
+ //assertEquals(1, config.getTargetMilestones("TestProduct").size());
+ }
+
+ public void test220RDFProductConfig() throws IOException {
+ ServerConfigurationFactory factory = ServerConfigurationFactory.getInstance();
+ RepositoryConfiguration config = factory.getConfiguration(IBugzillaConstants.TEST_BUGZILLA_220_URL);
+ assertNotNull(config);
+ assertEquals("2.20", config.getInstallVersion());
+ assertEquals(7, config.getStatusValues().size());
+ assertEquals(8, config.getResolutions().size());
+ assertEquals(4, config.getPlatforms().size());
+ assertEquals(5, config.getOSs().size());
+ assertEquals(5, config.getPriorities().size());
+ assertEquals(7, config.getSeverities().size());
+ assertEquals(2, config.getProducts().size());
+ assertEquals(4, config.getOpenStatusValues().size());
+ assertEquals(2, config.getComponents("TestProduct").size());
+ assertEquals(1, config.getVersions("TestProduct").size());
+ //assertEquals(1, config.getTargetMilestones("TestProduct").size());
+ }
+
+ public void test218RDFProductConfig() throws IOException {
+ ServerConfigurationFactory factory = ServerConfigurationFactory.getInstance();
+ RepositoryConfiguration config = factory.getConfiguration(IBugzillaConstants.TEST_BUGZILLA_218_URL);
+ assertNotNull(config);
+ assertEquals("2.18.5", config.getInstallVersion());
+ assertEquals(7, config.getStatusValues().size());
+ assertEquals(8, config.getResolutions().size());
+ assertEquals(8, config.getPlatforms().size());
+ assertEquals(37, config.getOSs().size());
+ assertEquals(5, config.getPriorities().size());
+ assertEquals(7, config.getSeverities().size());
+ assertEquals(1, config.getProducts().size());
+ assertEquals(4, config.getOpenStatusValues().size());
+ assertEquals(1, config.getComponents("TestProduct").size());
+ assertEquals(1, config.getVersions("TestProduct").size());
+ //assertEquals(1, config.getTargetMilestones("TestProduct").size());
+ }
+
+ public void testEclipseRDFProductConfig() throws IOException {
+ ServerConfigurationFactory factory = ServerConfigurationFactory.getInstance();
+ RepositoryConfiguration config = factory.getConfiguration(IBugzillaConstants.ECLIPSE_BUGZILLA_URL);
+ assertNotNull(config);
+ assertEquals("2.20.1", config.getInstallVersion());
+ assertEquals(7, config.getStatusValues().size());
+ assertEquals(8, config.getResolutions().size());
+ assertEquals(6, config.getPlatforms().size());
+ assertEquals(27, config.getOSs().size());
+ assertEquals(5, config.getPriorities().size());
+ assertEquals(7, config.getSeverities().size());
+ assertEquals(53, config.getProducts().size());
+ assertEquals(4, config.getOpenStatusValues().size());
+ assertEquals(10, config.getComponents("Mylar").size());
+ //assertEquals(10, config.getComponents("Hyades").size());
+ //assertEquals(1, config.getTargetMilestones("TestProduct").size());
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaProductParserTest.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaProductParserTest.java
new file mode 100644
index 000000000..a017900ba
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaProductParserTest.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.bugzilla.tests;
+
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+
+/**
+ * Tests for parsing Product Page for new Bugzilla reports
+ *
+ * @author Mik Kersten
+ * @author Rob Elves
+ */
+public class BugzillaProductParserTest extends TestCase {
+
+ private TaskRepository repository;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND,
+ // new URL(IBugzillaConstants.ECLIPSE_BUGZILLA_URL));
+ // MylarTaskListPlugin.getRepositoryManager().addRepository(repository);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ // MylarTaskListPlugin.getRepositoryManager().removeRepository(repository);
+ }
+
+ public BugzillaProductParserTest(String arg0) {
+ super(arg0);
+ }
+
+ public void test222Products() throws Exception {
+
+ repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_222_URL,
+ IBugzillaConstants.BugzillaServerVersion.SERVER_220.toString());
+
+ List<String> productList = BugzillaRepositoryUtil.getProductList(repository);
+ Iterator<String> itr = productList.iterator();
+ assertTrue(itr.hasNext());
+ assertEquals("TestProduct", "TestProduct", itr.next());
+
+ }
+
+ public void test2201Products() throws Exception {
+
+ repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_2201_URL,
+ IBugzillaConstants.BugzillaServerVersion.SERVER_220.toString());
+
+ List<String> productList = BugzillaRepositoryUtil.getProductList(repository);
+ Iterator<String> itr = productList.iterator();
+ assertTrue(itr.hasNext());
+ assertEquals("TestProduct", "TestProduct", itr.next());
+
+ }
+
+ public void test220Products() throws Exception {
+
+ repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_220_URL,
+ IBugzillaConstants.BugzillaServerVersion.SERVER_220.toString());
+
+ List<String> productList = BugzillaRepositoryUtil.getProductList(repository);
+ assertEquals(2, productList.size());
+ assertTrue(productList.contains("TestProduct"));
+ assertTrue(productList.contains("Widget"));
+
+ }
+
+ public void test218Products() throws Exception {
+
+ repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_218_URL,
+ IBugzillaConstants.BugzillaServerVersion.SERVER_218.toString());
+
+ List<String> productList = BugzillaRepositoryUtil.getProductList(repository);
+ assertEquals(1, productList.size());
+ assertTrue(productList.contains("TestProduct"));
+
+ }
+
+// No longer supporting 216
+// public void test216Products() throws Exception {
+//
+// repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_216_URL,
+// IBugzillaConstants.BugzillaServerVersion.SERVER_216.toString());
+//
+// List<String> productList = BugzillaRepositoryUtil.getProductList(repository);
+// Iterator<String> itr = productList.iterator();
+// assertTrue(itr.hasNext());
+// assertEquals("TestProduct", "TestProduct", itr.next());
+// }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaSearchEngineTest.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaSearchEngineTest.java
new file mode 100644
index 000000000..103d60af4
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaSearchEngineTest.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.bugzilla.tests;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaRepositoryConnector;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaRepositoryQuery;
+import org.eclipse.mylar.provisional.tasklist.AbstractQueryHit;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+
+/**
+ * @author Rob Elves
+ */
+public class BugzillaSearchEngineTest extends TestCase {
+
+ private static final String MAX_HITS = "100";
+ private static final String QUERY_NAME = "Query Page Name";
+ private static final String BUG_DESC_SUBSTRING_SEARCH = "/buglist.cgi?short_desc_type=allwordssubstr&short_desc=";//search-match-test&amp";
+ private static final String SEARCH_DESCRIPTION = "search-match-test";
+ private static final int NUM_EXPECTED_HITS = 2;
+ private static final int NUM_REPOSITORIES = 0;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ MylarTaskListPlugin.getRepositoryManager().clearRepositories();
+ assertEquals(NUM_REPOSITORIES, MylarTaskListPlugin.getRepositoryManager().getRepositories(BugzillaPlugin.REPOSITORY_KIND).size());
+ }
+
+ protected void tearDown() throws Exception {
+ MylarTaskListPlugin.getRepositoryManager().clearRepositories();
+ super.tearDown();
+ }
+
+// public void testSearching216() throws MalformedURLException {
+// TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND,
+// IBugzillaConstants.TEST_BUGZILLA_216_URL, IBugzillaConstants.BugzillaServerVersion.SERVER_216.toString());
+// MylarTaskListPlugin.getRepositoryManager().addRepository(repository);
+// List<AbstractQueryHit> hits = runQuery(IBugzillaConstants.TEST_BUGZILLA_216_URL, SEARCH_DESCRIPTION);
+// assertEquals(NUM_EXPECTED_HITS, hits.size());
+// }
+
+ public void testSearching218() throws MalformedURLException {
+ TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND,
+ IBugzillaConstants.TEST_BUGZILLA_218_URL, IBugzillaConstants.BugzillaServerVersion.SERVER_218.toString());
+ MylarTaskListPlugin.getRepositoryManager().addRepository(repository);
+ assertEquals(NUM_EXPECTED_HITS, runQuery(IBugzillaConstants.TEST_BUGZILLA_218_URL, SEARCH_DESCRIPTION).size());
+ }
+
+ public void testSearching220() throws MalformedURLException {
+ TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND,
+ IBugzillaConstants.TEST_BUGZILLA_220_URL, IBugzillaConstants.BugzillaServerVersion.SERVER_220.toString());
+ MylarTaskListPlugin.getRepositoryManager().addRepository(repository);
+ assertEquals(NUM_EXPECTED_HITS, runQuery(IBugzillaConstants.TEST_BUGZILLA_220_URL, SEARCH_DESCRIPTION).size());
+ }
+
+ public void testSearching2201() throws MalformedURLException {
+ TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND,
+ IBugzillaConstants.TEST_BUGZILLA_2201_URL, IBugzillaConstants.BugzillaServerVersion.SERVER_220.toString());
+ MylarTaskListPlugin.getRepositoryManager().addRepository(repository);
+ assertEquals(NUM_EXPECTED_HITS, runQuery(IBugzillaConstants.TEST_BUGZILLA_2201_URL, SEARCH_DESCRIPTION).size());
+ }
+
+ public void testSearching222() throws MalformedURLException {
+ TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND,
+ IBugzillaConstants.TEST_BUGZILLA_222_URL, IBugzillaConstants.BugzillaServerVersion.SERVER_222.toString());
+ MylarTaskListPlugin.getRepositoryManager().addRepository(repository);
+ List<AbstractQueryHit> hits = runQuery(IBugzillaConstants.TEST_BUGZILLA_222_URL, SEARCH_DESCRIPTION);
+ assertEquals(NUM_EXPECTED_HITS, hits.size());
+ }
+
+ private List<AbstractQueryHit> runQuery(String repositoryURL, String SearchString) {
+ ArrayList<AbstractQueryHit> results = new ArrayList<AbstractQueryHit>();
+ TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(BugzillaPlugin.REPOSITORY_KIND, repositoryURL);
+ assertNotNull(repository);
+
+ final BugzillaRepositoryQuery repositoryQuery = new BugzillaRepositoryQuery(
+ repository.getUrl(),
+ repository.getUrl() + BUG_DESC_SUBSTRING_SEARCH+SearchString,
+ QUERY_NAME,
+ MAX_HITS, MylarTaskListPlugin.getTaskListManager().getTaskList());
+
+ BugzillaRepositoryConnector connector = (BugzillaRepositoryConnector) MylarTaskListPlugin.getRepositoryManager().getRepositoryConnector(BugzillaPlugin.REPOSITORY_KIND);
+ results.addAll(connector.performQuery(repositoryQuery, new NullProgressMonitor(), new MultiStatus(MylarTaskListPlugin.PLUGIN_ID, IStatus.OK, "Query result", null)));
+ return results;
+ }
+
+
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaTaskHyperlinkDetectorTest.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaTaskHyperlinkDetectorTest.java
new file mode 100644
index 000000000..5a529b371
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaTaskHyperlinkDetectorTest.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.bugzilla.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.mylar.internal.bugzilla.ui.BugzillaTaskHyperlinkDetector;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.RepositoryTextViewer;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @author Rob Elves
+ */
+public class BugzillaTaskHyperlinkDetectorTest extends TestCase {
+
+ private String BUG_FORMAT_1 = "bug# 1";
+ private String BUG_FORMAT_1_2 = "bug# 2";
+ private String BUG_FORMAT_2_1 = "bug # 1";
+ private BugzillaTaskHyperlinkDetector detector = new BugzillaTaskHyperlinkDetector();
+ private TaskRepository dummyRepository = new TaskRepository("repository_kind", "repository_url");
+ private RepositoryTextViewer viewer = new RepositoryTextViewer(dummyRepository, new Shell(), SWT.NONE);
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testBeginning() {
+ String testString = BUG_FORMAT_1+" is at the beginning";
+ viewer.setDocument(new Document(testString));
+ Region region = new Region(0, testString.length());
+ IHyperlink[] links = detector.detectHyperlinks(viewer, region, false);
+ assertNotNull(links);
+ assertEquals(1, links.length);
+ assertEquals(testString.indexOf(BUG_FORMAT_1), links[0].getHyperlinkRegion().getOffset());
+ }
+
+ public void testEnd() {
+ String testString = "is ends with bug# 1";
+ viewer.setDocument(new Document(testString));
+ Region region = new Region(testString.indexOf(BUG_FORMAT_1), testString.length());
+ IHyperlink[] links = detector.detectHyperlinks(viewer, region, false);
+ assertNotNull(links);
+ assertEquals(1, links.length);
+ assertEquals(testString.indexOf(BUG_FORMAT_1), links[0].getHyperlinkRegion().getOffset());
+ }
+
+ public void testMiddle() {
+ String testString = "is a "+BUG_FORMAT_1+" in the middle";
+ viewer.setDocument(new Document(testString));
+ Region region = new Region(testString.indexOf(BUG_FORMAT_1), testString.length());
+ IHyperlink[] links = detector.detectHyperlinks(viewer, region, false);
+ assertNotNull(links);
+ assertEquals(1, links.length);
+ assertEquals(testString.indexOf(BUG_FORMAT_1), links[0].getHyperlinkRegion().getOffset());
+ }
+
+ public void testTwoOnSingleLine() {
+ String testString = "is a "+BUG_FORMAT_1+" in the middle and at the end "+BUG_FORMAT_1_2;
+ viewer.setDocument(new Document(testString));
+ Region region = new Region(testString.indexOf(BUG_FORMAT_1_2), testString.length());
+ IHyperlink[] links = detector.detectHyperlinks(viewer, region, false);
+ assertNotNull(links);
+ assertEquals(1, links.length);
+ assertEquals(testString.indexOf(BUG_FORMAT_1_2), links[0].getHyperlinkRegion().getOffset());
+ }
+
+ public void testMultiLine() {
+ String testString = "is a the first line\n this is the second which ends with a bug, "+BUG_FORMAT_1_2;
+ viewer.setDocument(new Document(testString));
+ Region region = new Region(testString.indexOf(BUG_FORMAT_1_2), testString.length());
+ IHyperlink[] links = detector.detectHyperlinks(viewer, region, false);
+ assertNotNull(links);
+ assertEquals(1, links.length);
+ assertEquals(testString.indexOf(BUG_FORMAT_1_2), links[0].getHyperlinkRegion().getOffset());
+ }
+
+ public void testFormat2() {
+ String testString = "is a "+BUG_FORMAT_2_1+" in the middle";
+ viewer.setDocument(new Document(testString));
+ Region region = new Region(testString.indexOf(BUG_FORMAT_2_1), testString.length());
+ IHyperlink[] links = detector.detectHyperlinks(viewer, region, false);
+ assertNotNull(links);
+ assertEquals(1, links.length);
+ assertEquals(testString.indexOf(BUG_FORMAT_2_1), links[0].getHyperlinkRegion().getOffset());
+ }
+
+ // TODO: test other bug formats
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/ReportAttachmentTest.java b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/ReportAttachmentTest.java
new file mode 100644
index 000000000..a1a3e9e1a
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/ReportAttachmentTest.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.bugzilla.tests;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.core.tests.support.FileTool;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.internal.BugParser;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+
+/**
+ * @author Rob Elves
+ */
+public class ReportAttachmentTest extends TestCase {
+
+ public void testExistingBugWithAttachment() throws Exception {
+ File f = FileTool.getFileInPlugin(BugzillaTestPlugin.getDefault(), new Path(
+ "testdata/pages/test-report-222attachment.html"));
+ Reader in = new FileReader(f);
+
+ BugReport bug = BugParser.parseBug(in, 4, IBugzillaConstants.ECLIPSE_BUGZILLA_URL, false, null, null, null);
+
+ assertEquals(4, bug.getId());
+ assertEquals("4", bug.getAttribute("Bug#").getValue());
+ assertEquals("4", bug.getAttribute("id").getValue());
+
+ assertNotNull(bug.getComments());
+ assertEquals(1, bug.getComments().size());
+ assertTrue(bug.getComments().get(0).hasAttachment());
+ assertEquals("Testing upload", bug.getComments().get(0).getAttachmentDescription());
+// System.err.println(bug.getComments().get(0).getText());
+// assertEquals(1, bug.getAttachements().size());
+// assertEquals("Testing upload", bug.getAttachements().get(1));
+ }
+
+ public void testAttachementDownload() throws Exception {
+ URL localURL = null;
+ URL installURL = BugzillaTestPlugin.getDefault().getBundle().getEntry("testdata/contexts/");
+// File destinationFile = FileTool.getFileInPlugin(BugzillaTestPlugin.getDefault(), new Path("testdata/contexts/"));
+ localURL = FileLocator.toFileURL(installURL);
+ File destinationFile = new File(localURL.getPath()+"downloadedContext.xml");
+
+ TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_222_URL);
+ boolean result = BugzillaRepositoryUtil.downloadAttachment(repository, 2, destinationFile, true);
+ assertTrue(result);
+ }
+
+// public void testAttachementUpload() throws Exception {
+// File sourceFile = FileTool.getFileInPlugin(BugzillaTestPlugin.getDefault(), new Path(
+// "testdata/contexts/downloadedContext.xml"));
+// TaskRepository repository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, IBugzillaConstants.TEST_BUGZILLA_222_URL);
+// repository.setAuthenticationCredentials("relves@cs.ubc.ca", "***");
+// boolean result = BugzillaRepositoryUtil.uploadAttachment(repository, 4, "Upload Comment 2", "Upload Description 2", sourceFile, "application/xml", false);
+// assertTrue(result);
+// }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.tests/testdata/contexts/.cvsignore b/org.eclipse.mylyn.bugzilla.tests/testdata/contexts/.cvsignore
new file mode 100644
index 000000000..47269cfbd
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/testdata/contexts/.cvsignore
@@ -0,0 +1 @@
+downloadedContext.xml
diff --git a/org.eclipse.mylyn.bugzilla.tests/testdata/contexts/empty.txt b/org.eclipse.mylyn.bugzilla.tests/testdata/contexts/empty.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/testdata/contexts/empty.txt
diff --git a/org.eclipse.mylyn.bugzilla.tests/testdata/pages/test-report-222attachment.html b/org.eclipse.mylyn.bugzilla.tests/testdata/pages/test-report-222attachment.html
new file mode 100644
index 000000000..6248ce40d
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.tests/testdata/pages/test-report-222attachment.html
@@ -0,0 +1,859 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>Bug 4 - Another Test</title>
+
+
+<link rel="Top" href="http://mylar.eclipse.org/bugs222/">
+
+
+ <link rel="Up" href="buglist.cgi?regetlastlist=1">
+
+ <link rel="First" href="show_bug.cgi?id=1">
+ <link rel="Last" href="show_bug.cgi?id=4">
+
+
+
+ <link rel="Prev" href="show_bug.cgi?id=3">
+
+
+
+
+
+ <link rel="Show" title="Dependency Tree"
+ href="showdependencytree.cgi?id=4">
+ <link rel="Show" title="Dependency Graph"
+ href="showdependencygraph.cgi?id=4">
+
+
+ <link rel="Show" title="Bug Activity"
+ href="show_activity.cgi?id=4">
+
+ <link rel="Show" title="Printer-Friendly Version"
+ href="show_bug.cgi?format=multiple&amp;id=4">
+
+
+
+ <link rel="Saved&nbsp;Searches" title="My Bugs"
+ href="buglist.cgi?bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailreporter1=1&amp;emailtype1=exact&amp;email1=relves%40cs.ubc.ca&amp;field0-0-0=bug_status&amp;type0-0-0=notequals&amp;value0-0-0=UNCONFIRMED&amp;field0-0-1=reporter&amp;type0-0-1=equals&amp;value0-0-1=relves%40cs.ubc.ca">
+
+
+ <link rel="Administration" title="Parameters"
+ href="editparams.cgi"><link rel="Administration" title="Users"
+ href="editusers.cgi"><link rel="Administration" title="Products"
+ href="editproducts.cgi"><link rel="Administration" title="Flag Types"
+ href="editflagtypes.cgi"><link rel="Administration" title="Groups"
+ href="editgroups.cgi"><link rel="Administration" title="Keywords"
+ href="editkeywords.cgi"><link rel="Administration" title="Whining"
+ href="editwhines.cgi"><link rel="Administration" title="Sanity Check"
+ href="sanitycheck.cgi">
+
+
+
+ <script type="text/javascript">
+ <!--
+
+ function initHelp() {}
+ // -->
+ </script>
+
+ <link href="skins/standard/global.css" rel="stylesheet" type="text/css">
+
+ <link href="skins/custom/global.css" rel="stylesheet" type="text/css">
+
+
+
+
+
+ </head>
+
+
+
+ <body onload=""
+ class="mylar-eclipse-org-bugs222 bz_bug bz_status_NEW bz_component_TestComponent bz_bug_4">
+
+
+<div id="banner">
+ <div class="intro"></div>
+
+ <p id="banner-name">
+ <span>This is Bugzilla</span>
+ </p>
+ <p id="banner-version">
+ <a href="http://www.bugzilla.org/"><span>Bugzilla</span></a>
+ <span>Version 2.22rc1</span>
+ </p>
+
+ <div class="outro"></div>
+ </div>
+
+<div id="header">
+ <h1>Bugzilla Bug 4</h1>
+
+ <h2>Another Test</h2>
+
+ <h3>Last modified: 2006-03-10 14:11:48</h3>
+
+</div>
+
+<b>Bug List:</b>
+ (4 of 4)
+
+ <a href="show_bug.cgi?id=1">First</a>
+ <a href="show_bug.cgi?id=4">Last</a>
+
+ <a href="show_bug.cgi?id=3">Prev</a>
+
+ <i><font color="#777777">Next</font></i>
+
+ &nbsp;&nbsp;<a href="buglist.cgi?regetlastlist=1">Show last search results</a>
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="query.cgi">Search page</a>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="enter_bug.cgi">Enter new bug</a>
+
+<hr>
+<script type="text/javascript">
+ <!--
+
+ /* Outputs a link to call replyToComment(); used to reduce HTML output */
+ function addReplyLink(id) {
+ /* XXX this should really be updated to use the DOM Core's
+ * createElement, but finding a container isn't trivial.
+ */
+ document.write('[<a href="#add_comment" onclick="replyToComment(' +
+ id + ');">reply<' + '/a>]');
+ }
+
+ /* Adds the reply text to the `comment' textarea */
+ function replyToComment(id) {
+ /* pre id="comment_name_N" */
+ var text_elem = document.getElementById('comment_text_'+id);
+ var text = getText(text_elem);
+
+ /* make sure we split on all newlines -- IE or Moz use \r and \n
+ * respectively.
+ */
+ text = text.split(/\r|\n/);
+
+ var replytext = "";
+ for (var i=0; i < text.length; i++) {
+ replytext += "> " + text[i] + "\n";
+ }
+
+ replytext = "(In reply to comment #" + id + ")\n" + replytext + "\n";
+
+
+ /* <textarea id="comment"> */
+ var textarea = document.getElementById('comment');
+ textarea.value += replytext;
+
+ textarea.focus();
+ }
+
+ if (typeof Node == 'undefined') {
+ /* MSIE doesn't define Node, so provide a compatibility object */
+ window.Node = {
+ TEXT_NODE: 3,
+ ENTITY_REFERENCE_NODE: 5
+ };
+ }
+
+ /* Concatenates all text from element's childNodes. This is used
+ * instead of innerHTML because we want the actual text (and
+ * innerText is non-standard).
+ */
+ function getText(element) {
+ var child, text = "";
+ for (var i=0; i < element.childNodes.length; i++) {
+ child = element.childNodes[i];
+ var type = child.nodeType;
+ if (type == Node.TEXT_NODE || type == Node.ENTITY_REFERENCE_NODE) {
+ text += child.nodeValue;
+ } else {
+ /* recurse into nodes of other types */
+ text += getText(child);
+ }
+ }
+ return text;
+ }
+
+
+ function updateCommentTagControl(checkbox, form) {
+ if (checkbox.checked) {
+ form.comment.className='bz_private';
+ } else {
+ form.comment.className='';
+ }
+ }
+
+ //-->
+ </script>
+
+<form name="changeform" method="post" action="process_bug.cgi">
+
+ <input type="hidden" name="delta_ts" value="2006-03-10 14:11:48">
+
+ <input type="hidden" name="longdesclength" value="2">
+ <input type="hidden" name="id" value="4">
+
+
+
+ <table>
+
+ <tr>
+ <td valign="top">
+ <table cellspacing="1" cellpadding="1">
+ <tr>
+
+ <td align="right">
+ <b>Bug#:</b>
+ </td>
+ <td>
+ <a href="http://mylar.eclipse.org/bugs222/show_bug.cgi?id=4">4</a>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b><u>P</u>roduct:</b>
+ </td><td>
+ <label for="product" accesskey="p">
+ <select name="product" id="product">
+ <option value="TestProduct" selected>TestProduct
+ </option>
+
+ </select>
+ </label>
+ </td>
+ </tr>
+
+
+
+ <tr>
+ <td align="right">
+ <b>
+ <a href="describecomponents.cgi?product=TestProduct">
+
+ Co<u>m</u>ponent</a>:
+ </b>
+ </td><td>
+ <label for="component" accesskey="m">
+ <select name="component" id="component">
+ <option value="TestComponent" selected>TestComponent
+ </option>
+ </select>
+
+ </label>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b>
+ <a href="page.cgi?id=fields.html#status">Status</a>:
+ </b>
+
+ </td>
+ <td>NEW</td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b>
+ <a href="page.cgi?id=fields.html#resolution">Resolution</a>:
+ </b>
+
+ </td>
+ <td>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b>
+ <a href="page.cgi?id=fields.html#assigned_to">Assigned&nbsp;To</a>:
+ </b>
+
+ </td>
+ <td>Robert Elves &lt;relves&#64;cs.ubc.ca&gt;</td>
+ </tr>
+
+ </table>
+
+ </td>
+ <td valign="top">
+
+ <table cellspacing="1" cellpadding="1">
+
+ <tr>
+ <td align="right">
+ <b><u>H</u>ardware:</b>
+ </td><td>
+ <label for="rep_platform" accesskey="h">
+ <select name="rep_platform" id="rep_platform">
+
+ <option value="All">All
+ </option>
+ <option value="PC" selected>PC
+ </option>
+ <option value="Macintosh">Macintosh
+ </option>
+ <option value="Other">Other
+ </option>
+ </select>
+ </label>
+ </td>
+
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b><u>O</u>S:</b>
+ </td><td>
+ <label for="op_sys" accesskey="o">
+ <select name="op_sys" id="op_sys">
+
+ <option value="All">All
+ </option>
+ <option value="Windows">Windows
+ </option>
+ <option value="Mac OS">Mac OS
+ </option>
+ <option value="Linux">Linux
+ </option>
+ <option value="Other" selected>Other
+ </option>
+ </select>
+
+ </label>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b>Version:</b>
+ </td><td>
+ <label for="version" accesskey="o">
+
+ <select name="version" id="version">
+ <option value="other" selected>other
+ </option>
+ </select>
+ </label>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+
+ <b><a href="page.cgi?id=fields.html#priority">Pr<u>i</u>ority</a>:</b>
+ </td><td>
+ <label for="priority" accesskey="i">
+ <select name="priority" id="priority">
+ <option value="P1">P1
+ </option>
+ <option value="P2">P2
+ </option>
+
+ <option value="P3" selected>P3
+ </option>
+ <option value="P4">P4
+ </option>
+ <option value="P5">P5
+ </option>
+ </select>
+ </label>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b><a href="page.cgi?id=fields.html#bug_severity">Severity</a>:</b>
+ </td><td>
+ <label for="bug_severity" accesskey="i">
+ <select name="bug_severity" id="bug_severity">
+ <option value="blocker">blocker
+ </option>
+
+ <option value="critical">critical
+ </option>
+ <option value="major">major
+ </option>
+ <option value="normal" selected>normal
+ </option>
+ <option value="minor">minor
+ </option>
+ <option value="trivial">trivial
+ </option>
+ <option value="enhancement">enhancement
+ </option>
+
+ </select>
+ </label>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right">
+ <b>
+ Target Milestone:
+ </b>
+
+ </td><td>
+ <label for="target_milestone" accesskey="i">
+ <select name="target_milestone" id="target_milestone">
+ <option value="---" selected>---
+ </option>
+ </select>
+ </label>
+ </td>
+ </tr>
+
+ </table>
+ </td>
+
+ <td valign="top">
+
+ <table cellpadding="1" cellspacing="1">
+
+ <tr>
+ <td align="right">
+ <b>Reporter:</b>
+
+ </td>
+ <td>
+ <a href="mailto:relves&#64;cs.ubc.ca">Robert Elves &lt;relves&#64;cs.ubc.ca&gt;</a>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right" valign="top">
+
+ <b><u>A</u>dd&nbsp;CC:</b>
+ </td>
+ <td><input
+ name="newcc"
+ value="" accesskey="a" size="30"
+>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="right" valign="top">
+
+ <b>CC:</b>
+ </td>
+ <td valign="top">
+ <input type="hidden" name="cc" value="">
+ </td>
+ </tr>
+
+ </table>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table cellspacing="1" cellpadding="1">
+
+
+
+
+ <tr>
+ <td align="right">
+ <b>
+
+ <u>U</u>RL:
+ </b>
+ </td>
+ <td colspan="5">
+ <input name="bug_file_loc" accesskey="u"
+ value="" size="60">
+ </td>
+ </tr>
+
+ <tr>
+
+ <td align="right">
+ <b><u>S</u>ummary:</b>
+ </td>
+ <td colspan="5">
+ <input name="short_desc" accesskey="s"
+ value="Another Test" size="60">
+ </td>
+ </tr>
+
+
+ </table>
+ </td>
+
+ <td valign="top">
+ <table cellspacing="1" cellpadding="1">
+ <tr>
+ <td colspan="2" valign="top">
+ </td>
+
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+
+
+
+<br>
+<table cellspacing="0" cellpadding="4" border="1">
+ <tr>
+
+ <th bgcolor="#cccccc" align="left">Attachment</th>
+ <th bgcolor="#cccccc" align="left">Type</th>
+ <th bgcolor="#cccccc" align="left">Creator</th>
+ <th bgcolor="#cccccc" align="left">Created</th>
+ <th bgcolor="#cccccc" align="left">Size</th>
+ <th bgcolor="#cccccc" align="left">Actions</th>
+
+ </tr>
+ <tr >
+ <td valign="top">
+ <a href="attachment.cgi?id=1">Testing upload</a>
+ </td>
+
+ <td valign="top">text/plain
+ </td>
+
+ <td valign="top">
+
+ <a href="mailto:relves&#64;cs.ubc.ca">Robert Elves
+ </a>
+ </td>
+ <td valign="top">2006-03-10 14:11</td>
+ <td valign="top">6.87 KB</td>
+
+
+ <td valign="top">
+ <a href="attachment.cgi?id=1&amp;action=edit">Edit</a>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="5">
+ <a href="attachment.cgi?bugid=4&amp;action=enter">Create a New Attachment</a> (proposed patch, testcase, etc.)
+ </td>
+ <td>
+ <a href="attachment.cgi?bugid=4&amp;action=viewall">View All</a>
+
+ </td>
+ </tr>
+</table>
+<br>
+
+
+
+ <table>
+ <tr><th align="right">Bug 4 depends on:</th>
+ <td>
+ </td>
+
+ <td>
+ <input name="dependson" accesskey="i"
+ value="">
+ </td>
+ <td rowspan="2">
+ <a href="showdependencytree.cgi?id=4">Show
+ dependency tree</a>
+
+ <br>
+ <a href="showdependencygraph.cgi?id=4">Show
+ dependency graph</a>
+
+ </td>
+ </tr>
+
+ <tr><th align="right">Bug 4 <u>b</u>locks:</th>
+ <td>
+ </td>
+ <td>
+ <input name="blocked" accesskey="b"
+ value="">
+
+ </td>
+ </tr>
+ </table>
+
+
+
+
+ <br>
+ <b>Additional <u>C</u>omments:</b>
+
+ <br>
+ <a name="add_comment"></a>
+ <textarea name="comment" id="comment" rows="10" cols="80"
+ accesskey="c"></textarea>
+
+ <br>
+ <label for="addselfcc">
+ <input type="checkbox" id="addselfcc" name="addselfcc">
+ Add relves&#64;cs.ubc.ca to CC list
+ </label>
+
+ <br>
+
+<br>
+ <input type="radio" id="knob-leave" name="knob" value="none" checked="checked">
+ <label for="knob-leave">
+ Leave as <b>NEW&nbsp;</b>
+ </label>
+ <br>
+
+
+ <input type="radio" id="knob-accept" name="knob" value="accept">
+ <label for="knob-accept">
+ Accept bug (change
+ status to <b>ASSIGNED</b>)
+ </label>
+ <br>
+
+
+ <input type="radio" id="knob-resolve" name="knob" value="resolve">
+
+ <label for="knob-resolve">
+ Resolve bug, changing
+ <a href="page.cgi?id=fields.html#resolution">resolution</a> to
+ </label>
+ <select name="resolution"
+ onchange="document.changeform.knob[2].checked=true">
+ <option value="FIXED">FIXED</option>
+ <option value="INVALID">INVALID</option>
+ <option value="WONTFIX">WONTFIX</option>
+
+ <option value="LATER">LATER</option>
+ <option value="REMIND">REMIND</option>
+ <option value="WORKSFORME">WORKSFORME</option>
+ </select>
+ <br>
+
+ <input type="radio" id="knob-duplicate" name="knob" value="duplicate">
+ <label for="knob-duplicate">
+
+ Resolve bug, mark it as duplicate of bug #
+ </label>
+ <input name="dup_id" size="6"
+ onchange="if (this.value != '')
+ {document.changeform.knob[3].checked=true}">
+ <br>
+
+ <input type="radio" id="knob-reassign" name="knob" value="reassign">
+ <label for="knob-reassign">
+ <a href="page.cgi?id=fields.html#assigned_to">Reassign</a> bug to
+ </label><input
+ name="assigned_to"
+ value="relves&#64;cs.ubc.ca" onchange="if ((this.value != 'relves\x40cs.ubc.ca') &amp;&amp; (this.value != '')) {
+ document.changeform.knob[4].checked=true;
+ }" accesskey="b" size="32"
+>
+
+ <br>
+
+ <input type="radio" id="knob-reassign-cmp" name="knob" value="reassignbycomponent">
+ <label for="knob-reassign-cmp">
+ Reassign bug to default assignee
+ of selected component
+ </label>
+ <br>
+
+ <input type="submit" value="Commit">
+ <input type="hidden" name="form_name" value="process_bug">
+
+ <p>
+ <font size="+1">
+ <b>
+ <a href="show_activity.cgi?id=4">View Bug Activity</a>
+ &nbsp; | &nbsp;
+ <a href="show_bug.cgi?format=multiple&amp;id=4">Format For Printing</a>
+ &nbsp; | &nbsp;
+
+ <a href="show_bug.cgi?ctype=xml&amp;id=4">XML</a>
+ &nbsp; | &nbsp;
+ <a href="enter_bug.cgi?cloned_bug_id=4">Clone This Bug</a>
+
+
+ </b>
+ </font>
+
+ </p>
+
+
+
+<hr>
+<script type="text/javascript">
+ <!--
+ function updateCommentPrivacy(checkbox, id) {
+ var text_elem = document.getElementById('comment_text_'+id);
+ if (checkbox.checked) {
+ text_elem.parentNode.className='bz_private';
+ } else {
+ text_elem.parentNode.className='';
+ }
+ }
+ //-->
+ </script>
+
+
+
+
+
+
+
+
+<div >
+ <table>
+
+ <tr>
+ <td align="left">
+ <b><a name="c0" href="show_bug.cgi?id=4#c0">
+ Description</a>:</b>&nbsp;&nbsp;<script type="text/javascript"><!--
+ addReplyLink(0);
+ //--></script>
+ </td>
+ <td align="left" width="30%">
+ <b>Opened:</b> 2006-03-09 13:09
+ </td>
+
+ </tr>
+ </table>
+
+
+
+<pre id="comment_text_0">Testing new 2.22 version capability
+</pre>
+ </div>
+ <div >
+ <br>
+ <span class="bz_comment">
+ ------- <i>Comment
+ <a name="c1" href="show_bug.cgi?id=4#c1">
+
+ #1</a> From
+ <a href="mailto:relves&#64;cs.ubc.ca">Robert Elves</a>
+ 2006-03-10 14:11:48
+ </i>
+ <script type="text/javascript"><!--
+ addReplyLink(1); //--></script>
+ -------
+ </span>
+
+
+
+<pre id="comment_text_1"><span class=""><a href="attachment.cgi?id=1&amp;action=view" title="Testing upload">Created an attachment (id=1)</a> <a href="attachment.cgi?id=1&amp;action=edit" title="Testing upload">[edit]</a></span>
+
+Testing upload
+
+The comment
+</pre>
+ </div>
+
+</form>
+
+<hr>
+<b>Bug List:</b>
+ (4 of 4)
+
+ <a href="show_bug.cgi?id=1">First</a>
+ <a href="show_bug.cgi?id=4">Last</a>
+
+ <a href="show_bug.cgi?id=3">Prev</a>
+
+ <i><font color="#777777">Next</font></i>
+
+ &nbsp;&nbsp;<a href="buglist.cgi?regetlastlist=1">Show last search results</a>
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="query.cgi">Search page</a>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="enter_bug.cgi">Enter new bug</a>
+
+<br>
+<div id="footer">
+ <div class="intro"></div>
+
+
+
+
+<div id="useful-links">
+ <div id="links-actions">
+ <div class="label">Actions:</div>
+ <div class="links">
+
+ <a href="./">Home</a> |
+ <a href="enter_bug.cgi">New</a> |
+ <a href="query.cgi">Search</a> |
+
+ <form action="buglist.cgi" method="get"
+ onsubmit="if (this.quicksearch.value == '')
+ { alert('Please enter one or more search terms first.');
+ return false; } return true;">
+ <input class="txt" type="text" name="quicksearch">
+ <input class="btn" type="submit" value="Find">
+ </form> |
+
+ <a href="report.cgi">Reports</a>
+
+ | <a href="request.cgi?requester=relves%40cs.ubc.ca&amp;requestee=relves%40cs.ubc.ca&amp;do_union=1&amp;group=type">My Requests</a>
+
+
+ | <a href="votes.cgi?action=show_user">My&nbsp;Votes</a>
+ | <a href="sanitycheck.cgi">Sanity&nbsp;check</a>
+ | <a href="relogin.cgi">Log&nbsp;out</a>&nbsp;relves&#64;cs.ubc.ca
+ </div>
+ </div>
+
+
+ <div id="links-edit">
+ <div class="label">Edit:</div>
+ <div class="links">
+
+ <a href="userprefs.cgi">Prefs</a> | <a href="editparams.cgi">Parameters</a> | <a href="editsettings.cgi">User Preferences</a> | <a href="editusers.cgi">Users</a> | <a href="editproducts.cgi">Products</a> | <a href="editflagtypes.cgi">Flags</a> | <a href="editvalues.cgi">Field Values</a> | <a href="editgroups.cgi">Groups</a> | <a href="editkeywords.cgi">Keywords</a> | <a href="editwhines.cgi">Whining</a>
+
+ </div>
+ </div>
+
+
+
+
+ <div id="links-saved">
+ <div class="label">
+ Saved&nbsp;Searches:
+ </div>
+ <div class="links">
+ <a href="buglist.cgi?bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailreporter1=1&amp;emailtype1=exact&amp;email1=relves%40cs.ubc.ca&amp;field0-0-0=bug_status&amp;type0-0-0=notequals&amp;value0-0-0=UNCONFIRMED&amp;field0-0-1=reporter&amp;type0-0-1=equals&amp;value0-0-1=relves%40cs.ubc.ca">My&nbsp;Bugs</a>
+
+ </div>
+ </div>
+
+
+<div id="links-special">
+ <div class="label">&nbsp;</div>
+ <div class="links">
+ <form action="buglist.cgi" method="get">
+ <input type="hidden" name="cmdtype" value="doit">
+ <input type="hidden" name="remtype" value="asnamed">
+
+ <input type="hidden" name="add_bugids" value="1">
+ <input type="submit" value="Add"> bugs
+ <input type="text" name="bug_ids" size="8" maxlength="80"> to
+ the new saved search:
+ <input type="text" name="newqueryname" size="20" maxlength="64">
+ </form>
+ </div>
+ </div>
+
+
+</div>
+
+ <div class="outro"></div>
+</div>
+
+</body>
+</html>
diff --git a/org.eclipse.mylyn.bugzilla.ui/.classpath b/org.eclipse.mylyn.bugzilla.ui/.classpath
new file mode 100644
index 000000000..6f1aa2c56
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins">
+ <accessrules>
+ <accessrule kind="accessible" pattern="**/internal/**"/>
+ </accessrules>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF b/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..c9a5ccb67
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,33 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Mylar Bugzilla Client Ui Plug-in
+Bundle-SymbolicName: org.eclipse.mylar.bugzilla.ui; singleton:=true
+Bundle-Version: 0.5.1
+Bundle-Activator: org.eclipse.mylar.internal.bugzilla.ui.BugzillaUiPlugin
+Bundle-Vendor: Eclipse.org
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.compare,
+ org.eclipse.search,
+ org.eclipse.ui.views,
+ org.eclipse.ui.ide,
+ org.eclipse.mylar.bugzilla.core,
+ org.eclipse.mylar.core,
+ org.eclipse.ui.forms,
+ org.eclipse.jface.text,
+ org.eclipse.mylar.tasklist,
+ org.eclipse.team.ui,
+ org.eclipse.team.cvs.ui,
+ org.eclipse.ui.editors,
+ org.eclipse.ui.workbench.texteditor
+Eclipse-AutoStart: true
+Export-Package: org.eclipse.mylar.internal.bugzilla.ui,
+ org.eclipse.mylar.internal.bugzilla.ui.actions,
+ org.eclipse.mylar.internal.bugzilla.ui.editor,
+ org.eclipse.mylar.internal.bugzilla.ui.search,
+ org.eclipse.mylar.internal.bugzilla.ui.tasklist,
+ org.eclipse.mylar.internal.bugzilla.ui.wizard
+Bundle-ClassPath: bugzilla-ui.jar
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/org.eclipse.mylyn.bugzilla.ui/plugin.xml b/org.eclipse.mylyn.bugzilla.ui/plugin.xml
new file mode 100644
index 000000000..012d2549c
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/plugin.xml
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<?eclipse version="3.0"?>
+<plugin>
+
+ <!-- TODO: remove? -->
+ <extension
+ id="searchHit"
+ name="Bugzilla Search Match"
+ point="org.eclipse.core.resources.markers">
+ <super type="org.eclipse.search.searchmarker"/>
+ <attribute name="id"/>
+ <attribute name="href"/>
+ <attribute name="description"/>
+ <attribute name="label"/>
+ <attribute name="severity"/>
+ <attribute name="priority"/>
+ <attribute name="platform"/>
+ <attribute name="status"/>
+ <attribute name="result"/>
+ <attribute name="owner"/>
+ <attribute name="query"/>
+ </extension>
+
+ <extension
+ id="org.eclipse.mylar.bugzilla.repository"
+ name="Bugzilla Repository"
+ point="org.eclipse.mylar.tasklist.repositories">
+
+ <repositoryType
+ brandingIcon="icons/eview16/bugzilla-logo.gif"
+ class="org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaRepositoryConnector"
+ id="org.eclipse.mylar.bugzilla.tasklist.repositories"
+ name="Bugzilla Repository Client"
+ type="bugzilla"/>
+
+ <externalizer
+ class="org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaTaskExternalizer"
+ id="org.eclipse.mylar.bugzilla.tasklist.externalizer"/>
+ </extension>
+
+ <extension
+ point="org.eclipse.mylar.tasklist.editors">
+ <editorFactory class="org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaReportEditorFactory"/>
+ <hyperlinkDetector
+ class="org.eclipse.mylar.internal.bugzilla.ui.BugzillaTaskHyperlinkDetector"
+ id="org.eclipse.mylar.tasklist.hyperlinkdetector.bugzillatask"/>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension targetID="org.eclipse.jdt.ui.JavaPerspective">
+ <newWizardShortcut id="org.eclipse.mylar.bugzilla.bugWizard"/>
+ </perspectiveExtension>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.decorators">
+ <decorator
+ class="org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaTaskDecorator"
+ id="org.eclipse.mylar.bugzilla.ui.decorator.task"
+ label="Mylar Bugzilla Task Decorator"
+ lightweight="true"
+ objectClass="org.eclipse.mylar.provisional.tasklist.ITaskListElement"
+ state="true">
+ <description>
+ Mylar Bugzilla Task Decorator
+ </description>
+ </decorator>
+ </extension>
+
+ <extension
+ id="org.eclipse.mylar.bugzilla.help.browser"
+ name="Bugzilla Help"
+ point="org.eclipse.help.toc">
+ <toc
+ file="doc/toc.xml"
+ primary="false">
+ </toc>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.editors">
+ <editor
+ name="Bugzilla viewer"
+ icon="icons/etool16/task-remote.gif"
+ class="org.eclipse.mylar.internal.bugzilla.ui.editor.ExistingBugEditor"
+ id="org.eclipse.mylar.bugzilla.ui.existingBugEditor">
+ </editor>
+ <editor
+ name="Bugzilla viewer"
+ icon="icons/etool16/task-remote.gif"
+ class="org.eclipse.mylar.internal.bugzilla.ui.editor.NewBugEditor"
+ id="org.eclipse.mylar.bugzilla.ui.newBugEditor">
+ </editor>
+ <editor
+ icon="icons/etool16/task-repository.gif"
+ name="Bugzilla task viewer"
+ class="org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaTaskEditor"
+ id="org.eclipse.mylar.bugzilla.ui.tasklist.bugzillaTaskEditor"/>
+ </extension>
+ <extension
+ id="org.eclipse.mylar.bugzilla.help.context"
+ name="Bugzilla Context-sensitive Help"
+ point="org.eclipse.help.contexts">
+ <contexts
+ file="bugzilla-help.xml">
+ </contexts>
+ </extension>
+ <extension
+ point="org.eclipse.search.searchPages"
+ id="org.eclipse.mylar.bugzilla.core.search.searchPage"
+ name="Bugzilla Search Page">
+ <page
+ class="org.eclipse.mylar.internal.bugzilla.ui.search.BugzillaSearchPage"
+ enabled="true"
+ icon="icons/elcl16/bug-search.gif"
+ id="org.eclipse.mylar.bugzilla.core.search.bugzillaSearchPage"
+ label="Bugzilla Search"
+ tabPosition="999"/>
+ </extension>
+ <extension
+ id="BugzillaSearchPage"
+ point="org.eclipse.search.searchResultViewPages">
+ <viewPage
+ class="org.eclipse.mylar.internal.bugzilla.ui.search.BugzillaSearchResultView"
+ searchResultClass="org.eclipse.mylar.internal.bugzilla.core.search.BugzillaSearchResult"
+ id="org.eclipse.mylar.bugzilla.BugzillaSearchResultPage"/>
+ </extension>
+<!-- <extension
+ point="org.eclipse.mylar.tasklist.editors">
+ <hyperlinkListener
+ class="org.eclipse.mylar.internal.bugzilla.ui.BugzillaTaskHyperlinkDetector"
+ type="org.eclipse.mylar.bugzilla.ui.hyperlinkListener1"/>
+ </extension>-->
+</plugin>
+
+<!--
+<extension
+ id="org.eclipse.mylar.bugzilla.wizards"
+ name="Bug Wizard"
+ point="org.eclipse.ui.newWizards">
+ <category
+ name="Bugzilla Client"
+ id="org.eclipse.mylar.bugzilla.wizard.category">
+ </category>
+ <wizard
+ category="org.eclipse.mylar.bugzilla.wizard.category"
+ class="org.eclipse.mylar.bugzilla.ui.wizard.NewBugzillaReportWizard"
+ icon="icons/elcl16/bug-new.gif"
+ id="org.eclipse.mylar.bugzilla.bugWizard"
+ name="New Bug Report">
+ <description>
+ Create a new bug report
+ </description>
+ </wizard>
+</extension>
+-->
+
+ <!--
+ <extension
+ id="org.eclipse.mylar.bugzilla.ui"
+ name="Bugzilla Client Views"
+ point="org.eclipse.ui.views">
+ <category
+ name="Bugzilla"
+ id="org.eclipse.mylar.bugzilla.category"/>
+ <view
+ name="Bugzilla Offline Reports"
+ icon="icons/elcl16/bug-dirty.gif"
+ category="org.eclipse.mylar.bugzilla.category"
+ class="org.eclipse.mylar.bugzilla.ui.OfflineView"
+ id="org.eclipse.mylar.bugzilla.ui.offlineReportsView"/>
+ <view
+ name="Bugzilla Favorites"
+ icon="icons/elcl16/bug-favorite.gif"
+ category="org.eclipse.mylar.bugzilla.category"
+ class="org.eclipse.mylar.bugzilla.ui.FavoritesView"
+ id="org.eclipse.mylar.bugzilla.ui.favoritesView"/>
+ </extension>
+ -->
+
+<!-- <extension point="org.eclipse.ui.preferencePages">
+ <page
+ name="Bugzilla Client"
+ class="org.eclipse.mylar.internal.bugzilla.core.BugzillaPreferencePage"
+ id="org.eclipse.mylar.bugzilla.bugzillaPreferences"
+ category="org.eclipse.mylar.ui.preferences"/>
+ </extension>
+ -->
+
+ <!--
+ <action
+ class="org.eclipse.mylar.bugzilla.ui.actions.CreateBugzillaTaskAction"
+ enablesFor="*"
+ icon="icons/etool16/task-bug.gif"
+ id="org.eclipse.mylar.bugzilla.ui.popup.addExisting"
+ label="Add Existing Bugzilla Report"
+ menubarPath="reports"
+ tooltip="Add Existing Bugzilla Report">
+ <enablement>
+ <objectClass name="org.eclipse.mylar.tasklist.internal.TaskCategory"/>
+ </enablement>
+ </action>
+ -->
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaHyperLink.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaHyperLink.java
new file mode 100644
index 000000000..edfe2c3f5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaHyperLink.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.tasklist.ui.TaskUiUtil;
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaHyperLink implements IHyperlink {
+
+ private static final String SHOW_BUG_CGI = "/show_bug.cgi?id=";
+
+ private IRegion region;
+
+ private String id;
+
+ private String repositoryUrl;
+
+ public BugzillaHyperLink(IRegion nlsKeyRegion, String id, String repositoryUrl) {
+ this.region = nlsKeyRegion;
+ this.id = id;
+ this.repositoryUrl = repositoryUrl;
+ }
+
+ public IRegion getHyperlinkRegion() {
+ return region;
+ }
+
+ public String getTypeLabel() {
+ return null;
+ }
+
+ public String getHyperlinkText() {
+ return SHOW_BUG_CGI + id;
+ }
+
+ public void open() {
+ // TaskRepository repository =
+ // MylarTaskListPlugin.getRepositoryManager().getRepositoryForActiveTask(BugzillaPlugin.REPOSITORY_KIND);
+ // TaskRepository repository =
+ // MylarTaskListPlugin.getRepositoryManager().getDefaultRepository(
+ // BugzillaPlugin.REPOSITORY_KIND);
+ if (repositoryUrl != null) {
+ TaskUiUtil.openRepositoryTask(repositoryUrl, id, repositoryUrl + BugzillaRepositoryUtil.POST_ARGS_SHOW_BUG
+ + id);
+ // OpenBugzillaReportJob job = new
+ // OpenBugzillaReportJob(repository.getUrl(), id);
+ // IProgressService service =
+ // PlatformUI.getWorkbench().getProgressService();
+ // try {
+ // service.run(true, false, job);
+ // } catch (Exception e) {
+ // MylarStatusHandler.fail(e, "Could not open report", true);
+ // }
+ } else {
+ MessageDialog.openError(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Could not determine repository for report");
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaTaskHyperlinkDetector.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaTaskHyperlinkDetector.java
new file mode 100644
index 000000000..616426fae
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaTaskHyperlinkDetector.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.RepositoryTextViewer;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+
+/**
+ * @author Rob Elves
+ */
+public class BugzillaTaskHyperlinkDetector implements IHyperlinkDetector {
+
+ private TaskRepository repository;
+
+ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
+ if (region == null || textViewer == null)
+ return null;
+
+ if (!(textViewer instanceof RepositoryTextViewer))
+ return null;
+
+ RepositoryTextViewer viewer = (RepositoryTextViewer) textViewer;
+
+ repository = viewer.getRepository();
+
+ if (repository == null)
+ return null;
+
+ IDocument document = textViewer.getDocument();
+
+ int offset = region.getOffset();
+
+ if (document == null)
+ return null;
+
+ IRegion lineInfo;
+ String line;
+ try {
+ lineInfo = document.getLineInformationOfOffset(offset);
+ line = document.get(lineInfo.getOffset(), lineInfo.getLength());
+ } catch (BadLocationException ex) {
+ return null;
+ }
+
+ int offsetInLine = offset - lineInfo.getOffset();
+
+ IHyperlink[] links = BugzillaUITools.findBugHyperlinks(repository.getUrl(), offsetInLine, lineInfo.getLength(),
+ line, lineInfo.getOffset());
+
+ return links;
+
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaUITools.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaUITools.java
new file mode 100644
index 000000000..21f9ba025
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/BugzillaUITools.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.NewBugModel;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.ExistingBugEditor;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.ExistingBugEditorInput;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.NewBugEditorInput;
+import org.eclipse.search.internal.ui.SearchMessages;
+import org.eclipse.search.internal.ui.SearchPlugin;
+import org.eclipse.search.internal.ui.util.ExceptionHandler;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * @author Rob Elves (multiple bug hyperlink support)
+ */
+public class BugzillaUITools {
+
+ private static final String BUG_HASH = "#";
+
+ private static final String BUG_PATTERN_6 = "bug\\d+";// "^.*bug\\s#\\d+.*";
+
+ private static final String BUG_PATTERN_5 = "bug\\s#\\s\\d+";// "^.*bug\\s#\\d+.*";
+
+ private static final String BUG_PATTERN_4 = "bug#\\d+";// "^.*bug#\\d+.*";
+
+ private static final String BUG_PATTERN_3 = "bug\\s#\\d+";// "^.*bug\\s#\\d+.*";
+
+ private static final String BUG_PATTERN_2 = "bug#\\s+\\d+";// "^.*bug#\\s+\\d+.*";
+
+ private static final String BUG_PATTERN_1 = "bug\\s+\\d+";// "^.*bug\\s+\\d+.*";
+
+ private static final String[] BUG_PATTERNS = { BUG_PATTERN_1, BUG_PATTERN_2, BUG_PATTERN_3, BUG_PATTERN_4,
+ BUG_PATTERN_5, BUG_PATTERN_6 };
+
+ /** The editor to use when a bug is opened */
+ private static IEditorPart fEditor;
+
+ /**
+ * Convenience method for opening a bug in an editor.
+ *
+ * @param id
+ * The bug id of the bug to open in the editor
+ */
+ public static boolean show(String repositoryUrl, int id) {
+ // determine if the editor is to be reused or not and call the
+ // appropriate
+ // function to show the bug
+ if (NewSearchUI.reuseEditor())
+ return showWithReuse(repositoryUrl, id);
+ else
+ return showWithoutReuse(repositoryUrl, id);
+ }
+
+ /**
+ * Show the bug in the same editor window
+ *
+ * @param id
+ * The id of the bug to show
+ */
+ private static boolean showWithReuse(String repositoryUrl, int id) {
+ // get the active page so that we can reuse it
+ IWorkbenchPage page = SearchPlugin.getActivePage();
+ try {
+ // if we couldn't get a page, get out
+ if (page == null)
+ return true;
+
+ IEditorInput input = null;
+
+ // try to get an editor input on the bug
+ input = new ExistingBugEditorInput(repositoryUrl, id);
+
+ // check if we found a valid bug
+ if (((ExistingBugEditorInput) input).getBug() == null) {
+ MessageDialog.openError(null, "No such bug", "No bug exists with this id");
+ return false;
+ }
+
+ // get the editor for the page
+ IEditorPart editor = page.findEditor(input);
+
+ if (editor == null) {
+ // close the current editor if it is clean and open
+ if (fEditor != null && !fEditor.isDirty())
+ page.closeEditor(fEditor, false);
+
+ try {
+ // try to open a new editor with the input bug, but don't
+ // activate it
+ editor = page.openEditor(input, IBugzillaConstants.EXISTING_BUG_EDITOR_ID, false);
+ } catch (PartInitException ex) {
+ // if there was a problem, handle it and log it, then get
+ // out of here
+ ExceptionHandler.handle(ex, SearchMessages.Search_Error_search_title,
+ SearchMessages.Search_Error_search_message); //$NON-NLS-2$ //$NON-NLS-1$
+ BugzillaPlugin.log(ex.getStatus());
+ return false;
+ }
+
+ } else {
+ // if a editor is openon that bug, just bring it to the top
+ // of the editors
+ page.bringToTop(editor);
+ }
+
+ if (editor != null) {
+ // if we have an editor, save it for later use
+ fEditor = editor;
+ }
+ } catch (LoginException e) {
+ 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(e);
+ } catch (IOException e) {
+ IStatus status = new MultiStatus(IBugzillaConstants.PLUGIN_ID, IStatus.ERROR, e.getClass().toString()
+ + " occurred while opening the bug report. \n\nClick Details or see log for more information.", e);
+ IStatus s = new Status(IStatus.ERROR, IBugzillaConstants.PLUGIN_ID, IStatus.ERROR, e.getClass().toString()
+ + ": ", e);
+ ((MultiStatus) status).add(s);
+ s = new Status(IStatus.ERROR, IBugzillaConstants.PLUGIN_ID, IStatus.ERROR, e.getMessage(), e);
+ ((MultiStatus) status).add(s);
+
+ // write error to log
+ BugzillaPlugin.log(status);
+
+ ErrorDialog.openError(null, "Bugzilla Error", null, status);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Show the bug in a new editor window
+ *
+ * @param id
+ * The id of the bug to show
+ */
+ private static boolean showWithoutReuse(String repositoryUrl, int id) {
+ // get the active workbench page
+ IWorkbenchPage page = SearchPlugin.getActivePage();
+ try {
+ // if we couldn't get the page, get out of here
+ if (page == null)
+ return true;
+
+ IEditorInput input = null;
+ String editorId = IBugzillaConstants.EXISTING_BUG_EDITOR_ID;
+
+ // get a new editor input on the bug that we want to open
+ input = new ExistingBugEditorInput(repositoryUrl, id);
+
+ // check if we found a valid bug
+ if (((ExistingBugEditorInput) input).getBug() == null) {
+ MessageDialog.openError(null, "No such bug", "No bug exists with this id");
+ return false;
+ }
+
+ try {
+ // try to open an editor on the input bug
+ page.openEditor(input, editorId);
+ } catch (PartInitException ex) {
+ // if we have a problem, handle it, log it, and get out of here
+ ExceptionHandler.handle(ex, SearchMessages.Search_Error_search_title,
+ SearchMessages.Search_Error_search_message); //$NON-NLS-2$ //$NON-NLS-1$
+ BugzillaPlugin.log(ex.getStatus());
+ return false;
+ }
+ } catch (LoginException e) {
+ 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(e);
+ } catch (IOException e) {
+ IStatus status = new MultiStatus(IBugzillaConstants.PLUGIN_ID, IStatus.ERROR, e.getClass().toString()
+ + " occurred while opening the bug report. \n\nClick Details or see log for more information.", e);
+ IStatus s = new Status(IStatus.ERROR, IBugzillaConstants.PLUGIN_ID, IStatus.ERROR, e.getClass().toString()
+ + ": ", e);
+ ((MultiStatus) status).add(s);
+ s = new Status(IStatus.ERROR, IBugzillaConstants.PLUGIN_ID, IStatus.ERROR, e.getMessage(), e);
+ ((MultiStatus) status).add(s);
+
+ // write error to log
+ BugzillaPlugin.log(status);
+
+ ErrorDialog.openError(null, "Bugzilla Error", null, status);
+ return false;
+ }
+ return true;
+ }
+
+ public static void closeEditor(IWorkbenchPage page, IBugzillaBug bug) {
+ if (bug instanceof NewBugModel) {
+ IEditorInput input = new NewBugEditorInput((NewBugModel) bug);
+ IEditorPart bugEditor = page.findEditor(input);
+ if (bugEditor != null) {
+ page.closeEditor(bugEditor, false);
+ }
+ } else if (bug instanceof BugReport) {
+ IEditorInput input = new ExistingBugEditorInput((BugReport) bug);
+ IEditorPart bugEditor = page.findEditor(input);
+ if (bugEditor != null) {
+ page.closeEditor(bugEditor, false);
+ IEditorPart compareEditor = page.findEditor(((ExistingBugEditor) bugEditor).getCompareInput());
+ if (compareEditor != null) {
+ page.closeEditor(compareEditor, false);
+ }
+ }
+ }
+ }
+
+ // TODO: legacy?: endOffset
+ public static IHyperlink[] findBugHyperlinks(String repositoryUrl, int offset, int endOffset, String comment,
+ int lineOffset) {
+ ArrayList<IHyperlink> hyperlinksFound = new ArrayList<IHyperlink>();
+ for (String regExp : BUG_PATTERNS) {
+ // TODO: Store these compiled patterns rather than always
+ // re-compiling
+ Pattern p = Pattern.compile(regExp, Pattern.CASE_INSENSITIVE);
+ Matcher m = p.matcher(comment);//comment.toLowerCase().trim()
+ while (m.find()) {
+ if (offset >= m.start() && offset <= m.end()) {
+ IHyperlink link = extractHyperlink(repositoryUrl, lineOffset, m);
+ if (link != null)
+ hyperlinksFound.add(link);
+ }
+ }
+ }
+
+ if (hyperlinksFound.size() > 0) {
+ return hyperlinksFound.toArray(new IHyperlink[1]);
+ }
+ return null;
+ }
+
+ private static IHyperlink extractHyperlink(String repositoryUrl, int lineOffset, Matcher m) {
+
+ int start = m.start();
+ int end = m.end();
+ String bugText = m.group();
+ int ahead = 3;
+ if (bugText.contains(BUG_HASH)) {
+ int pound = bugText.indexOf(BUG_HASH);
+ ahead = pound + 1;
+ }
+ String endComment = bugText.substring(ahead, bugText.length());
+ endComment = endComment.trim();
+
+ if (end == -1)
+ end = bugText.length();
+
+ try {
+
+ String bugId = endComment.trim();
+ start += lineOffset;
+ end += lineOffset;
+
+ IRegion sregion = new Region(start, end - start);
+ return new BugzillaHyperLink(sregion, bugId, repositoryUrl);
+
+ } catch (NumberFormatException e) {
+ return null;
+ }
+
+ }
+
+ // public static IHyperlink[] findBugHyperlinks(String repositoryUrl, int
+ // startOffset, int endOffset, String comment, int commentStart) {
+ //
+ //
+ // Pattern p = Pattern.compile("^.*bug\\s+\\d+.*");
+ // Matcher m = p.matcher(comment.toLowerCase().trim());
+ // boolean b = m.matches();
+ //
+ // p = Pattern.compile("^.*bug#\\s+\\d+.*");
+ // m = p.matcher(comment.toLowerCase().trim());
+ // boolean b2 = m.matches();
+ //
+ // p = Pattern.compile("^.*bug\\s#\\d+.*");
+ // m = p.matcher(comment.toLowerCase().trim());
+ // boolean b3 = m.matches();
+ //
+ // p = Pattern.compile("^.*bug#\\d+.*");
+ // m = p.matcher(comment.toLowerCase().trim());
+ // boolean b4 = m.matches();
+ //
+ // // XXX walk forward from where we are
+ // if (b || b2 || b3 || b4) {
+ //
+ // int start = comment.toLowerCase().indexOf("bug");
+ // int ahead = 4;
+ // if (b2 || b3 || b4) {
+ // int pound = comment.toLowerCase().indexOf("#", start);
+ // ahead = pound - start + 1;
+ // }
+ // String endComment = comment.substring(start + ahead, comment.length());
+ // endComment = endComment.trim();
+ // int endCommentStart = comment.indexOf(endComment);
+ //
+ // int end = comment.indexOf(" ", endCommentStart);
+ // int end2 = comment.indexOf(":", endCommentStart);
+ //
+ // if ((end2 < end && end2 != -1) || (end == -1 && end2 != -1)) {
+ // end = end2;
+ // }
+ //
+ // if (end == -1)
+ // end = comment.length();
+ //
+ // try {
+ // //int bugId = Integer.parseInt(comment.substring(endCommentStart,
+ // end).trim());
+ // String bugId = comment.substring(endCommentStart, end).trim();
+ // start += commentStart;
+ // end += commentStart;
+ // if (startOffset >= start && startOffset <= end) {
+ // // if (startOffset >= start && endOffset <= end) {
+ // IRegion sregion = new Region(start, end - start);
+ // return new IHyperlink[] { new BugzillaHyperLink(sregion, bugId,
+ // repositoryUrl) };
+ // }
+ // } catch (NumberFormatException e) {
+ // return null;
+ // }
+ // }
+ // return null;
+ // }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/FavoritesView.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/FavoritesView.java
new file mode 100644
index 000000000..0a9776139
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/FavoritesView.java
@@ -0,0 +1,574 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.ColumnLayoutData;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.internal.Favorite;
+import org.eclipse.mylar.internal.bugzilla.core.internal.FavoritesFile;
+import org.eclipse.mylar.internal.bugzilla.ui.actions.AbstractFavoritesAction;
+import org.eclipse.mylar.internal.bugzilla.ui.actions.DeleteFavoriteAction;
+import org.eclipse.mylar.internal.bugzilla.ui.actions.ViewFavoriteAction;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * A view that shows any bug marked as favorites.
+ */
+public class FavoritesView extends ViewPart {
+
+ private static Composite savedParent;
+
+ private IMemento savedMemento;
+
+ private static DeleteFavoriteAction remove;
+
+ public static DeleteFavoriteAction removeAll;
+
+ public static SelectAllAction selectAll;
+
+ private static ViewFavoriteAction open;
+
+ private Table table;
+
+ private MenuManager contextMenu;
+
+ private static TableViewer viewer;
+
+ private String[] columnHeaders = { "Bug", "Query", "Date" };
+
+ private ColumnLayoutData columnLayouts[] = { new ColumnWeightData(10), new ColumnWeightData(3),
+ new ColumnWeightData(5) };
+
+ /**
+ * Constructor initializes favorites' source file initializes actions
+ */
+ public FavoritesView() {
+ super();
+ open = new ViewFavoriteAction(this);
+ selectAll = new SelectAllAction();
+ remove = new DeleteFavoriteAction(this, false);
+ removeAll = new DeleteFavoriteAction(this, true);
+ }
+
+ @Override
+ public void init(IViewSite site) throws PartInitException {
+ super.init(site);
+ }
+
+ /**
+ * Initializes this view with the given view site. A memento is passed to
+ * the view which contains a snapshot of the views state from a previous
+ * session.
+ */
+ @Override
+ public void init(IViewSite site, IMemento memento) throws PartInitException {
+ init(site);
+ this.savedMemento = memento;
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ FavoritesView.savedParent = parent;
+ setPartName("Bugzilla Favorites");
+ createTable();
+
+ viewer = new TableViewer(table);
+ viewer.setUseHashlookup(true);
+ createColumns();
+
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.verticalSpan = 20;
+ viewer.getTable().setLayoutData(gd);
+
+ viewer.setContentProvider(new FavoritesViewContentProvider(this));
+ viewer.setLabelProvider(new FavoritesViewLabelProvider());
+ viewer.setInput(BugzillaPlugin.getDefault().getFavorites().elements());
+
+ viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ FavoritesView.this.widgetSelected(event);
+ }
+ });
+
+ fillToolbar();
+ createContextMenu();
+
+ Menu menu = contextMenu.createContextMenu(table);
+ table.setMenu(menu);
+
+ hookGlobalActions();
+ parent.layout();
+
+ // Restore state from the previous session.
+ restoreState();
+ }
+
+ @Override
+ public void setFocus() {
+ // don't need to do anything when the focus is set
+ }
+
+ private void createColumns() {
+ TableLayout layout = new TableLayout();
+ table.setLayout(layout);
+ table.setHeaderVisible(true);
+
+ for (int i = 0; i < columnHeaders.length; i++) {
+ TableColumn tc = new TableColumn(table, SWT.NONE, i);
+
+ tc.setText(columnHeaders[i]);
+ tc.pack();
+ tc.setResizable(columnLayouts[i].resizable);
+ layout.addColumnData(columnLayouts[i]);
+ }
+ }
+
+ private void createTable() {
+
+ table = new Table(savedParent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
+ table.setLinesVisible(true);
+
+ // Add action support for a double-click
+ table.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ open.run();
+ }
+ });
+ }
+
+ private void fillToolbar() {
+ IActionBars actionBars = getViewSite().getActionBars();
+ IToolBarManager toolbar = actionBars.getToolBarManager();
+
+ remove.setEnabled(false);
+ toolbar.add(remove);
+ toolbar.add(removeAll);
+ toolbar.add(new Separator());
+ toolbar.add(selectAll);
+
+ // create actions to handle the sorting of the favorites
+ sortByIDAction = new SortByAction(FavoritesFile.ID_SORT);
+ sortByIDAction.setText("by &Bug ID");
+ sortByIDAction.setToolTipText("Sorts by bug number");
+
+ sortByPriorityAction = new SortByAction(FavoritesFile.PRIORITY_SORT);
+ sortByPriorityAction.setText("by &Priority");
+ sortByPriorityAction.setToolTipText("Sorts by riority of the bug");
+
+ sortBySeverityAction = new SortByAction(FavoritesFile.SEVERITY_SORT);
+ sortBySeverityAction.setText("by &Severity");
+ sortBySeverityAction.setToolTipText("Sorts by severity of the bug");
+
+ sortByStatusAction = new SortByAction(FavoritesFile.STATE_SORT);
+ sortByStatusAction.setText("by S&tatus");
+ sortByStatusAction.setToolTipText("Sorts by status of the bug");
+
+ // get the menu manager and create a submenu to contain sorting
+ IMenuManager menu = actionBars.getMenuManager();
+ IMenuManager submenu = new MenuManager("&Sort");
+
+ // add the sorting actions to the menu bar
+ menu.add(submenu);
+ submenu.add(sortByIDAction);
+ submenu.add(sortBySeverityAction);
+ submenu.add(sortByPriorityAction);
+ submenu.add(sortByStatusAction);
+
+ updateSortingState();
+ }
+
+ /**
+ * Function to make sure that the appropriate sort is checked
+ */
+ void updateSortingState() {
+ int curCriterion = FavoritesFile.lastSel;
+
+ sortByIDAction.setChecked(curCriterion == FavoritesFile.ID_SORT);
+ sortBySeverityAction.setChecked(curCriterion == FavoritesFile.SEVERITY_SORT);
+ sortByPriorityAction.setChecked(curCriterion == FavoritesFile.PRIORITY_SORT);
+ sortByStatusAction.setChecked(curCriterion == FavoritesFile.STATE_SORT);
+ viewer.setInput(viewer.getInput());
+ }
+
+ // Sorting actions for the favorites view
+ SortByAction sortByIDAction, sortBySeverityAction, sortByPriorityAction, sortByStatusAction;
+
+ /**
+ * Inner class to handle sorting
+ *
+ * @author Shawn Minto
+ */
+ class SortByAction extends Action {
+ /** The criteria to sort the favorites menu based on */
+ private int criterion;
+
+ /**
+ * Constructor
+ *
+ * @param criteria
+ * The criteria to sort the favorites menu based on
+ */
+ public SortByAction(int criteria) {
+ this.criterion = criteria;
+ }
+
+ /**
+ * Perform the sort
+ */
+ @Override
+ public void run() {
+ BugzillaPlugin.getDefault().getFavorites().sort(criterion);
+ updateSortingState();
+ }
+ }
+
+ /**
+ * Create context menu.
+ */
+ private void createContextMenu() {
+ contextMenu = new MenuManager("#FavoritesView");
+ contextMenu.setRemoveAllWhenShown(true);
+ contextMenu.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ fillContextMenu(manager);
+ updateActionEnablement();
+ }
+ });
+
+ // Register menu for extension.
+ getSite().registerContextMenu("#FavoritesView", contextMenu, viewer);
+ }
+
+ /**
+ * Hook global actions
+ */
+ private void hookGlobalActions() {
+ IActionBars bars = getViewSite().getActionBars();
+ bars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), selectAll);
+ bars.setGlobalActionHandler(ActionFactory.DELETE.getId(), remove);
+ table.addKeyListener(new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent event) {
+ if (event.character == SWT.DEL && event.stateMask == 0 && remove.isEnabled()) {
+ remove.run();
+ }
+ }
+ });
+ }
+
+ /**
+ * Populate context menu
+ */
+ private void fillContextMenu(IMenuManager mgr) {
+ mgr.add(open);
+ mgr.add(new Separator());
+ mgr.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+ mgr.add(new Separator());
+ mgr.add(remove);
+ mgr.add(new DeleteFavoriteAction(this, true));
+ mgr.add(new SelectAllAction());
+ }
+
+ /**
+ * Update action enablement depending on whether or not any items are
+ * selected. Displays name of current item in status bar.
+ */
+ public static void updateActionEnablement() {
+
+ boolean hasSelected = viewer.getTable().getSelectionCount() > 0;
+ remove.setEnabled(hasSelected);
+ open.setEnabled(hasSelected);
+
+ boolean hasItems = viewer.getTable().getItemCount() > 0;
+ removeAll.setEnabled(hasItems);
+ selectAll.setEnabled(hasItems);
+ }
+
+ @Override
+ public void saveState(IMemento memento) {
+ TableItem[] sel = table.getSelection();
+ if (sel.length == 0)
+ return;
+ memento = memento.createChild("selection");
+ for (int i = 0; i < sel.length; i++) {
+ memento.createChild("descriptor", new Integer(table.indexOf(sel[i])).toString());
+ }
+ }
+
+ private void restoreState() {
+ if (savedMemento == null)
+ return;
+ savedMemento = savedMemento.getChild("selection");
+ if (savedMemento != null) {
+ IMemento descriptors[] = savedMemento.getChildren("descriptor");
+ if (descriptors.length > 0) {
+ int[] objList = new int[descriptors.length];
+ for (int nX = 0; nX < descriptors.length; nX++) {
+ String id = descriptors[nX].getID();
+ objList[nX] = BugzillaPlugin.getDefault().getFavorites().find(Integer.valueOf(id).intValue());
+ }
+ table.setSelection(objList);
+ }
+ }
+ viewer.setSelection(viewer.getSelection(), true);
+ savedMemento = null;
+ updateActionEnablement();
+ }
+
+ /**
+ * Returns list of names of selected items.
+ */
+ public List<BugzillaOpenStructure> getBugIdsOfSelected() {
+ IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();// TableItem[]
+ // sel
+ // =
+ // table.getSelection();
+ List<?> sel = selection.toList();
+ List<BugzillaOpenStructure> Ids = new ArrayList<BugzillaOpenStructure>();
+
+ Iterator<?> itr = sel.iterator();
+ while (itr.hasNext()) {
+ Object o = itr.next();
+ if (o instanceof Favorite) {
+ Favorite entry = (Favorite) o;
+ Integer id = (Integer) entry.getAttributes().get(IBugzillaConstants.HIT_MARKER_ATTR_ID);
+ Ids.add(new BugzillaOpenStructure(entry.getServer(), id, -1));
+ }
+ }
+
+ return Ids;
+ }
+
+ /**
+ * Calls remove function in FavoritesFile
+ */
+ @SuppressWarnings("unchecked")
+ public void deleteSelectedFavorites() {
+ List<Favorite> selection = ((IStructuredSelection) viewer.getSelection()).toList();
+ BugzillaPlugin.getDefault().getFavorites().remove(selection);
+ viewer.setInput(viewer.getInput());
+ }
+
+ /**
+ * Removes all of the favorites in the FavoritesFile.
+ */
+ public void deleteAllFavorites() {
+ BugzillaPlugin.getDefault().getFavorites().removeAll();
+ viewer.setInput(viewer.getInput());
+ }
+
+ /**
+ * Refreshes the view.
+ */
+ public static void add() {
+ if (viewer != null)
+ viewer.setInput(viewer.getInput());
+ }
+
+ /**
+ * @see SelectionListener#widgetSelected(SelectionEvent)
+ */
+ @SuppressWarnings("unchecked")
+ public void widgetSelected(SelectionChangedEvent e) {
+
+ IStructuredSelection selection = (IStructuredSelection) e.getSelection();
+
+ boolean enable = selection.size() > 0;
+ selectAll.setEnabled(enable);
+ remove.setEnabled(enable);
+ open.setEnabled(enable);
+
+ IStructuredSelection viewerSelection = (IStructuredSelection) viewer.getSelection();// TableItem[]
+ // sel
+ // =
+ // table.getSelection();
+ List<Favorite> sel = viewerSelection.toList();
+ if (sel.size() > 0) {
+ IStatusLineManager manager = this.getViewSite().getActionBars().getStatusLineManager();
+ manager.setMessage(sel.get(0).toString());// table.getItem(selected).getText(0));
+ }
+
+ updateActionEnablement();
+ }
+
+ /**
+ * Attempts to display this view on the workbench.
+ */
+ public static void checkWindow() {
+ if (savedParent == null || savedParent.isDisposed()) {
+ IWorkbenchWindow w = BugzillaPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
+ if (w != null) {
+ IWorkbenchPage page = w.getActivePage();
+ if (page != null) {
+ try {
+ page.showView(IBugzillaConstants.PLUGIN_ID + ".ui.favoritesView");
+ } catch (PartInitException pie) {
+ BugzillaPlugin.log(pie.getStatus());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Action class - "Select All"
+ */
+ public class SelectAllAction extends AbstractFavoritesAction {
+
+ public SelectAllAction() {
+ setToolTipText("Select all favorites");
+ setText("Select all");
+ setImageDescriptor(BugzillaImages.SELECT_ALL);
+ }
+
+ @Override
+ public void run() {
+ checkWindow();
+ table.selectAll();
+ viewer.setSelection(viewer.getSelection(), true);
+ updateActionEnablement();
+ }
+ }
+
+ private class FavoritesViewLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+ /**
+ * Returns the label text for the given column of a recommendation in
+ * the table.
+ */
+ public String getColumnText(Object element, int columnIndex) {
+ if (element instanceof Favorite) {
+ Favorite f = (Favorite) element;
+ switch (columnIndex) {
+ case 0:
+ return f.toString();
+ case 1:
+ return f.getQuery();
+ case 2:
+ return f.getDate().toString();
+ default:
+ return "Undefined column text";
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object,
+ * int)
+ */
+ public Image getColumnImage(Object arg0, int arg1) {
+ return null;
+ }
+ }
+
+ public void refresh() {
+ // don't need to do anything to refresh
+ }
+
+ private class FavoritesViewContentProvider implements IStructuredContentProvider {
+
+ private List results;
+
+ /**
+ * The constructor.
+ */
+ public FavoritesViewContentProvider(FavoritesView taskList) {
+ // no setup to do
+ }
+
+ /**
+ * Returns the elements to display in the viewer when its input is set
+ * to the given element. These elements can be presented as rows in a
+ * table, items in a list, etc. The result is not modified by the
+ * viewer.
+ *
+ * @param inputElement
+ * the input element
+ * @return the array of elements to display in the viewer
+ */
+ public Object[] getElements(Object inputElement) {
+ if (results != null) {
+ return results.toArray();
+ } else
+ return null;
+ }
+
+ /**
+ * Notifies this content provider that a given viewer's input has been
+ * changed.
+ */
+ public void inputChanged(Viewer viewerChanged, Object oldInput, Object newInput) {
+ this.results = (List) newInput;
+
+ if (viewerChanged.getInput() != null) {
+ viewerChanged.getControl().getDisplay().syncExec(new Runnable() {
+ public void run() {
+ FavoritesView.this.refresh();
+ }
+ });
+ }
+ }
+
+ public void dispose() {
+ if (results != null)
+ results = null;
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/WebBrowserDialog.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/WebBrowserDialog.java
new file mode 100644
index 000000000..759847610
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/WebBrowserDialog.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Dialog to show the contents of an html page to the user
+ *
+ * @author Shawn Minto
+ */
+public class WebBrowserDialog extends MessageDialog {
+
+ private String data = null;
+
+ public WebBrowserDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
+ int dialogImageType, String[] dialogButtonLabels, int defaultIndex, String data) {
+ super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, dialogButtonLabels,
+ defaultIndex);
+ this.data = data;
+ this.setShellStyle(SWT.SHELL_TRIM | SWT.RESIZE);
+ }
+
+ public static int openAcceptAgreement(Shell parent, String title, String message, String data) {
+ WebBrowserDialog dialog = new WebBrowserDialog(parent, title, null, // accept
+ message, NONE, new String[] { IDialogConstants.OK_LABEL }, 0, data);
+ // ok is the default
+ return dialog.open();
+ }
+
+ @Override
+ public Control createCustomArea(Composite parent) {
+ GridLayout layout = new GridLayout();
+ parent.setLayout(layout);
+ layout.numColumns = 1;
+
+ Browser b = new Browser(parent, SWT.NONE);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.horizontalSpan = 1;
+ gd.verticalSpan = 50;
+ b.setLayoutData(gd);
+ b.setText(data);
+
+ return parent;
+ }
+
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/AbstractBugEditor.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/AbstractBugEditor.java
new file mode 100644
index 000000000..b2ea906cd
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/AbstractBugEditor.java
@@ -0,0 +1,1649 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui.editor;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.TextViewer;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.mylar.bugzilla.core.Attribute;
+import org.eclipse.mylar.bugzilla.core.Comment;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaTools;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaAttributeListener;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaReportSelection;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaRepositoryConnector;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.ui.editors.MylarTaskEditor;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.RetargetAction;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.events.IExpansionListener;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.help.WorkbenchHelpSystem;
+import org.eclipse.ui.part.EditorPart;
+import org.eclipse.ui.themes.IThemeManager;
+import org.eclipse.ui.views.contentoutline.ContentOutline;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+/**
+ * Abstract base implementation for an editor to view a bugzilla report.
+ *
+ * @author Mik Kersten (some hardening of prototype)
+ * @author Rob Elves (Conversion to Eclipse Forms)
+ */
+public abstract class AbstractBugEditor extends EditorPart {
+
+ public static final String REPOSITORY_TEXT_ID = "org.eclipse.mylar.tasklist.ui.fonts.task.editor.comment";
+
+ public static final String HYPERLINK_TYPE_TASK = "task";
+
+ public static final String HYPERLINK_TYPE_JAVA = "java";
+
+ private static final String LABEL_BUTTON_SUBMIT = "Submit to Repository";
+
+ private static final String LABEL_SECTION_ACTIONS = "Actions";
+
+ private static final String LABEL_SECTION_ATTRIBUTES = "Attributes";
+
+ protected static final String LABEL_SECTION_DESCRIPTION = "Description";
+
+ protected static final String LABEL_SECTION_COMMENTS = "Comments";
+
+ protected static final String LABEL_SECTION_NEW_COMMENT = "New Comment";
+
+ private FormToolkit toolkit;
+
+ private ScrolledForm form;
+
+ protected TaskRepository repository;
+
+ public static final int WRAP_LENGTH = 90;
+
+ protected Display display;
+
+ public static final Font TITLE_FONT = JFaceResources.getBannerFont();
+
+ public static final Font TEXT_FONT = JFaceResources.getDefaultFont();
+
+ public static final Font COMMENT_FONT = JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT);
+
+ public static final Font HEADER_FONT = JFaceResources.getDefaultFont();
+
+ public static final int DESCRIPTION_WIDTH = 79 * 7;
+
+ public static final int DESCRIPTION_HEIGHT = 10 * 14;
+
+ // protected Color background;
+ //
+ // protected Color foreground;
+
+ protected AbstractBugEditorInput bugzillaInput;
+
+ private MylarTaskEditor parentEditor = null;
+
+ protected BugzillaOutlineNode bugzillaOutlineModel = null;
+
+ // private static int MARGIN = 0;// 5
+
+ protected SimpleDateFormat simpleDateFormat = new SimpleDateFormat("E MMM dd, yyyy hh:mm aa");// "yyyy-MM-dd
+
+ // HH:mm"
+
+ /**
+ * Style option for function <code>newLayout</code>. This will create a
+ * plain-styled, selectable text label.
+ */
+ protected final String VALUE = "VALUE";
+
+ /**
+ * Style option for function <code>newLayout</code>. This will create a
+ * bolded, selectable header. It will also have an arrow image before the
+ * text (simply for decoration).
+ */
+ protected final String HEADER = "HEADER";
+
+ /**
+ * Style option for function <code>newLayout</code>. This will create a
+ * bolded, unselectable label.
+ */
+ protected final String PROPERTY = "PROPERTY";
+
+ protected final int HORZ_INDENT = 0;
+
+ protected CCombo oSCombo;
+
+ protected CCombo versionCombo;
+
+ protected CCombo platformCombo;
+
+ protected CCombo priorityCombo;
+
+ protected CCombo severityCombo;
+
+ protected CCombo milestoneCombo;
+
+ protected CCombo componentCombo;
+
+ protected Text urlText;
+
+ protected Text summaryText;
+
+ protected Text assignedTo;
+
+ protected Button submitButton;
+
+ // protected Button saveButton;
+
+ protected int scrollIncrement;
+
+ protected int scrollVertPageIncrement;
+
+ protected int scrollHorzPageIncrement;
+
+ public boolean isDirty = false;
+
+ /** Manager controlling the context menu */
+ protected MenuManager contextMenuManager;
+
+ protected StyledText currentSelectedText;
+
+ protected static final String cutActionDefId = "org.eclipse.ui.edit.cut"; //$NON-NLS-1$
+
+ protected static final String copyActionDefId = "org.eclipse.ui.edit.copy"; //$NON-NLS-1$
+
+ protected static final String pasteActionDefId = "org.eclipse.ui.edit.paste"; //$NON-NLS-1$
+
+ protected RetargetAction cutAction;
+
+ protected BugzillaEditorCopyAction copyAction;
+
+ // private Action revealAllAction;
+
+ protected RetargetAction pasteAction;
+
+ protected Composite editorComposite;
+
+ // protected CLabel titleLabel;
+
+ // protected ScrolledComposite scrolledComposite;
+
+ // protected Composite scrolledComposite;
+
+ // protected Composite infoArea;
+
+ // protected Hyperlink linkToBug;
+
+ // protected StyledText generalTitleText;
+
+ private List<IBugzillaAttributeListener> attributesListeners = new ArrayList<IBugzillaAttributeListener>();
+
+ protected final ISelectionProvider selectionProvider = new ISelectionProvider() {
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ selectionChangedListeners.add(listener);
+ }
+
+ public ISelection getSelection() {
+ return null;
+ }
+
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ selectionChangedListeners.remove(listener);
+ }
+
+ public void setSelection(ISelection selection) {
+ // No implementation.
+ }
+ };
+
+ protected List<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
+
+ protected HashMap<CCombo, String> comboListenerMap = new HashMap<CCombo, String>();
+
+ private IBugzillaReportSelection lastSelected = null;
+
+ protected final ISelectionListener selectionListener = new ISelectionListener() {
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if ((part instanceof ContentOutline) && (selection instanceof StructuredSelection)) {
+ Object select = ((StructuredSelection) selection).getFirstElement();
+ if (select instanceof BugzillaOutlineNode) {
+ BugzillaOutlineNode n = (BugzillaOutlineNode) select;
+
+ if (n != null && lastSelected != null
+ && BugzillaTools.getHandle(n).equals(BugzillaTools.getHandle(lastSelected))) {
+ // we don't need to set the selection if it is already
+ // set
+ return;
+ }
+ lastSelected = n;
+
+ Object data = n.getData();
+ boolean highlight = true;
+ if (n.getKey().toLowerCase().equals("comments")) {
+ highlight = false;
+ }
+ if (n.getKey().toLowerCase().equals("new comment")) {
+ selectNewComment();
+ } else if (n.getKey().toLowerCase().equals("new description")) {
+ selectNewDescription();
+ } else if (data != null) {
+ select(data, highlight);
+ }
+ }
+ }
+ }
+ };
+
+ private class ComboSelectionListener extends SelectionAdapter {
+
+ private CCombo combo;
+
+ public ComboSelectionListener(CCombo combo) {
+ this.combo = combo;
+ }
+
+ public void widgetDefaultSelected(SelectionEvent event) {
+ // ignore
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ if (comboListenerMap.containsKey(combo)) {
+ if (combo.getSelectionIndex() > -1) {
+ String sel = combo.getItem(combo.getSelectionIndex());
+ Attribute attribute = getBug().getAttribute(comboListenerMap.get(combo));
+ if (sel != null && !(sel.equals(attribute.getNewValue()))) {
+ attribute.setNewValue(sel);
+ for (IBugzillaAttributeListener client : attributesListeners) {
+ client.attributeChanged(attribute.getName(), sel);
+ }
+ changeDirtyStatus(true);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a new <code>AbstractBugEditor</code>. Sets up the default
+ * fonts and cut/copy/paste actions.
+ */
+ public AbstractBugEditor() {
+ // set the scroll increments so the editor scrolls normally with the
+ // scroll wheel
+ FontData[] fd = TEXT_FONT.getFontData();
+ int cushion = 4;
+ scrollIncrement = fd[0].getHeight() + cushion;
+ scrollVertPageIncrement = 0;
+ scrollHorzPageIncrement = 0;
+
+ // set up actions for the context menu
+ cutAction = new RetargetAction(ActionFactory.CUT.getId(), WorkbenchMessages.Workbench_cut);
+ cutAction.setToolTipText(WorkbenchMessages.Workbench_cutToolTip);// WorkbenchMessages.getString("Workbench.cutToolTip"));
+ // //$NON-NLS-1$
+ cutAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
+ cutAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
+ cutAction.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED));
+ cutAction.setAccelerator(SWT.CTRL | 'x');
+ cutAction.setActionDefinitionId(cutActionDefId);
+
+ pasteAction = new RetargetAction(ActionFactory.PASTE.getId(), WorkbenchMessages.Workbench_paste);
+ pasteAction.setToolTipText(WorkbenchMessages.Workbench_pasteToolTip);// WorkbenchMessages.getString("Workbench.pasteToolTip"));
+ // //$NON-NLS-1$
+ pasteAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
+ pasteAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
+ pasteAction.setDisabledImageDescriptor(WorkbenchImages
+ .getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
+ pasteAction.setAccelerator(SWT.CTRL | 'v');
+ pasteAction.setActionDefinitionId(pasteActionDefId);
+
+ copyAction = new BugzillaEditorCopyAction(this);
+ copyAction.setText(WorkbenchMessages.Workbench_copy);// WorkbenchMessages.getString("Workbench.copy"));
+ copyAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ copyAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ copyAction.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
+ copyAction.setAccelerator(SWT.CTRL | 'c');
+
+ copyAction.setEnabled(false);
+
+ //
+ // revealAllAction = new ExpandCommentsAction(this);
+ // revealAllAction.setText("Reveal Comments");//
+ // WorkbenchMessages.getString("Workbench.copy"));
+ // revealAllAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ // revealAllAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ // revealAllAction.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
+ // revealAllAction.setAccelerator(SWT.CTRL | 'r');
+ //
+ // revealAllAction.setEnabled(true);
+
+ }
+
+ /**
+ * @return The bug this editor is displaying.
+ */
+ public abstract IBugzillaBug getBug();
+
+ /**
+ * @return Any currently selected text.
+ */
+ protected StyledText getCurrentText() {
+ return currentSelectedText;
+ }
+
+ /**
+ * @return The action used to copy selected text from a bug editor to the
+ * clipboard.
+ */
+ protected BugzillaEditorCopyAction getCopyAction() {
+ return copyAction;
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+
+ if (getBug() == null) {
+ // close();
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Bugzilla Client Errror",
+ "Could not resolve the requested bug, check Bugzilla server and version.");
+
+ Composite composite = new Composite(parent, SWT.NULL);
+ composite.setLayout(new GridLayout());
+ Label noBugLabel = new Label(composite, SWT.NULL);
+ noBugLabel.setText("Could not resolve bug");
+ return;
+ }
+
+ toolkit = new FormToolkit(parent.getDisplay());
+ form = toolkit.createScrolledForm(parent);
+ String truncatedSummary = getBug().getSummary();
+ int maxLength = 50;
+ if (truncatedSummary.length() > maxLength) {
+ truncatedSummary = truncatedSummary.substring(0, maxLength) + "...";
+ }
+ form.setText("Bugzilla Bug: " + truncatedSummary);
+
+ editorComposite = form.getBody();
+ editorComposite.setLayout(new GridLayout());
+ editorComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ // Header information
+ Composite headerInfoComposite = toolkit.createComposite(editorComposite);
+ headerInfoComposite.setLayout(new GridLayout(6, false));
+ toolkit.createLabel(headerInfoComposite, "Bug# ").setFont(TITLE_FONT);
+ toolkit.createText(headerInfoComposite, "" + getBug().getId());
+
+ toolkit.createLabel(headerInfoComposite, " Opened: ").setFont(TITLE_FONT);
+ String openedDateString = "";
+ if (getBug().getCreated() != null) {
+ openedDateString = simpleDateFormat.format(getBug().getCreated());
+ }
+ toolkit.createText(headerInfoComposite, openedDateString);
+
+ toolkit.createLabel(headerInfoComposite, " Modified: ").setFont(TITLE_FONT);
+ String lastModifiedDateString = "";
+ if (getBug().getLastModified() != null) {
+ lastModifiedDateString = simpleDateFormat.format(getBug().getLastModified());
+ }
+ toolkit.createText(headerInfoComposite, lastModifiedDateString);
+
+ // openedText.setFont(TITLE_FONT);
+ // display = parent.getDisplay();
+ // background = JFaceColors.getBannerBackground(display);
+ // foreground = JFaceColors.getBannerForeground(display);
+
+ // createInfoArea(editorComposite);
+ createContextMenu();
+ createAttributeLayout();
+ createDescriptionLayout(toolkit, form);
+ createCommentLayout(toolkit, form);
+ createButtonLayouts(toolkit, form.getBody());
+
+ WorkbenchHelpSystem.getInstance().setHelp(parent, IBugzillaConstants.EDITOR_PAGE_CONTEXT);
+
+ editorComposite.setMenu(contextMenuManager.createContextMenu(editorComposite));
+ form.reflow(true);
+ getSite().getPage().addSelectionListener(selectionListener);
+ getSite().setSelectionProvider(selectionProvider);
+ }
+
+ /**
+ * Create a context menu for this editor.
+ */
+ protected void createContextMenu() {
+ contextMenuManager = new MenuManager("#BugEditor");
+ contextMenuManager.setRemoveAllWhenShown(true);
+ contextMenuManager.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ manager.add(cutAction);
+ manager.add(copyAction);
+ manager.add(pasteAction);
+ // manager.add(revealAllAction);
+ manager.add(new Separator());
+ manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+ if (currentSelectedText == null || currentSelectedText.getSelectionText().length() == 0) {
+
+ copyAction.setEnabled(false);
+ } else {
+ copyAction.setEnabled(true);
+ }
+ }
+ });
+ getSite().registerContextMenu("#BugEditor", contextMenuManager, getSite().getSelectionProvider());
+ }
+
+ /**
+ * Creates the attribute layout, which contains most of the basic attributes
+ * of the bug (some of which are editable).
+ */
+ protected void createAttributeLayout() {
+
+ String title = getTitleString();
+ String keywords = "";
+ String url = "";
+
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_ATTRIBUTES);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ // Attributes Composite- this holds all the combo fiels and text fields
+ Composite attributesComposite = toolkit.createComposite(section);
+ GridLayout attributesLayout = new GridLayout();
+ attributesLayout.numColumns = 4;
+ attributesLayout.horizontalSpacing = 14;
+ attributesLayout.verticalSpacing = 6;
+ attributesComposite.setLayout(attributesLayout);
+ GridData attributesData = new GridData(GridData.FILL_BOTH);
+ attributesData.horizontalSpan = 1;
+ attributesData.grabExcessVerticalSpace = false;
+ attributesComposite.setLayoutData(attributesData);
+ // attributesComposite.setBackground(background);
+ // End Attributes Composite
+
+ section.setClient(attributesComposite);
+
+ // Attributes Title Area
+ // Composite attributesTitleComposite = new
+ // Composite(attributesComposite, SWT.NONE);
+ // GridLayout attributesTitleLayout = new GridLayout();
+ // attributesTitleLayout.horizontalSpacing = 0;
+ // attributesTitleLayout.marginWidth = 0;
+ // attributesTitleComposite.setLayout(attributesTitleLayout);
+ // attributesTitleComposite.setBackground(background);
+ // GridData attributesTitleData = new
+ // GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ // attributesTitleData.horizontalSpan = 4;
+ // attributesTitleData.grabExcessVerticalSpace = false;
+ // attributesTitleComposite.setLayoutData(attributesTitleData);
+ // End Attributes Title
+
+ // Set the Attributes Title
+ // newAttributesLayout(attributesTitleComposite);
+ // titleLabel.setText(title);
+ bugzillaInput.setToolTipText(title);
+ int currentCol = 1;
+
+ String ccValue = null;
+
+ // Populate Attributes
+ for (Iterator<Attribute> it = getBug().getAttributes().iterator(); it.hasNext();) {
+ Attribute attribute = it.next();
+ String key = attribute.getParameterName();
+ String name = attribute.getName();
+ String value = checkText(attribute.getValue());
+ Map<String, String> values = attribute.getOptionValues();
+
+ // make sure we don't try to display a hidden field
+ if (attribute.isHidden() || (key != null && key.equals("status_whiteboard")))
+ continue;
+
+ if (values == null)
+ values = new HashMap<String, String>();
+
+ if (key == null)
+ key = "";
+
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ data.horizontalSpan = 1;
+ data.horizontalIndent = HORZ_INDENT;
+
+ if (key.equals("short_desc") || key.equals("keywords")) {
+ keywords = value;
+ } else if (key.equals("newcc")) {
+ ccValue = value;
+ if (value == null)
+ ccValue = "";
+ } else if (key.equals("bug_file_loc")) {
+ url = value;
+ } else if (key.equals("op_sys")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ // oSCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND |
+ // SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY);//SWT.NONE
+ oSCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.READ_ONLY);
+ // oSCombo = new Combo(attributesComposite, SWT.FLAT |
+ // SWT.READ_ONLY);
+ toolkit.adapt(oSCombo, true, true);
+ oSCombo.setFont(TEXT_FONT);
+ oSCombo.setLayoutData(data);
+ // oSCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ oSCombo.add(a[i]);
+ }
+ if (oSCombo.indexOf(value) != -1) {
+ oSCombo.select(oSCombo.indexOf(value));
+ } else {
+ oSCombo.select(oSCombo.indexOf("All"));
+ }
+ // oSCombo.addListener(SWT.Modify, this);
+ oSCombo.addSelectionListener(new ComboSelectionListener(oSCombo));
+ comboListenerMap.put(oSCombo, name);
+ oSCombo.addListener(SWT.FocusIn, new GenericListener());
+ currentCol += 2;
+ } else if (key.equals("version")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ versionCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+ toolkit.adapt(versionCombo, true, true);
+ versionCombo.setFont(TEXT_FONT);
+ versionCombo.setLayoutData(data);
+ // versionCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ versionCombo.add(a[i]);
+ }
+ versionCombo.select(versionCombo.indexOf(value));
+ // versionCombo.addListener(SWT.Modify, this);
+ versionCombo.addSelectionListener(new ComboSelectionListener(versionCombo));
+ versionCombo.addListener(SWT.FocusIn, new GenericListener());
+ comboListenerMap.put(versionCombo, name);
+ currentCol += 2;
+ } else if (key.equals("priority")) {
+ // newLayout(attributesComposite, 1, "Priority", PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ priorityCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.V_SCROLL | SWT.READ_ONLY);
+ toolkit.adapt(priorityCombo, true, true);
+ priorityCombo.setFont(TEXT_FONT);
+ priorityCombo.setLayoutData(data);
+ // priorityCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ priorityCombo.add(a[i]);
+ }
+ priorityCombo.select(priorityCombo.indexOf(value));
+ // priorityCombo.addListener(SWT.Modify, this);
+ priorityCombo.addSelectionListener(new ComboSelectionListener(priorityCombo));
+ priorityCombo.addListener(SWT.FocusIn, new GenericListener());
+ comboListenerMap.put(priorityCombo, name);
+ currentCol += 2;
+ } else if (key.equals("bug_severity")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ severityCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.READ_ONLY);
+ toolkit.adapt(severityCombo, true, true);
+ severityCombo.setFont(TEXT_FONT);
+ severityCombo.setLayoutData(data);
+ // severityCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ severityCombo.add(a[i]);
+ }
+ severityCombo.select(severityCombo.indexOf(value));
+ severityCombo.addSelectionListener(new ComboSelectionListener(severityCombo));
+ // severityCombo.addListener(SWT.Modify, this);
+ severityCombo.addListener(SWT.FocusIn, new GenericListener());
+ comboListenerMap.put(severityCombo, name);
+ currentCol += 2;
+ } else if (key.equals("target_milestone")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ milestoneCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.NO_BACKGROUND | SWT.MULTI
+ | SWT.V_SCROLL | SWT.READ_ONLY);
+ toolkit.adapt(milestoneCombo, true, true);
+ milestoneCombo.setFont(TEXT_FONT);
+ milestoneCombo.setLayoutData(data);
+ // milestoneCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ milestoneCombo.add(a[i]);
+ }
+ milestoneCombo.select(milestoneCombo.indexOf(value));
+ // milestoneCombo.addListener(SWT.Modify, this);
+ milestoneCombo.addSelectionListener(new ComboSelectionListener(milestoneCombo));
+ milestoneCombo.addListener(SWT.FocusIn, new GenericListener());
+ comboListenerMap.put(milestoneCombo, name);
+ currentCol += 2;
+ } else if (key.equals("rep_platform")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ platformCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+ toolkit.adapt(platformCombo, true, true);
+ platformCombo.setFont(TEXT_FONT);
+ platformCombo.setLayoutData(data);
+ // platformCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ platformCombo.add(a[i]);
+ }
+ platformCombo.select(platformCombo.indexOf(value));
+ // platformCombo.addListener(SWT.Modify, this);
+ platformCombo.addSelectionListener(new ComboSelectionListener(platformCombo));
+ platformCombo.addListener(SWT.FocusIn, new GenericListener());
+ comboListenerMap.put(platformCombo, name);
+ currentCol += 2;
+ } else if (key.equals("product")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ // toolkit.createLabel(attributesComposite, value);
+ Composite uneditableComp = toolkit.createComposite(attributesComposite);
+ GridLayout textLayout = new GridLayout();
+ textLayout.marginWidth = 1;
+ uneditableComp.setLayout(textLayout);
+ toolkit.createText(uneditableComp, value, SWT.READ_ONLY);// Label(attributesComposite,
+ // value);
+ // newLayout(attributesComposite, 1, value,
+ // VALUE).addListener(SWT.FocusIn, new GenericListener());
+ currentCol += 2;
+ } else if (key.equals("assigned_to")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ assignedTo = new Text(attributesComposite, SWT.BORDER | SWT.SINGLE | SWT.WRAP);
+ assignedTo.setFont(TEXT_FONT);
+ assignedTo.setText(value);
+ data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ data.horizontalSpan = 1;
+ assignedTo.setLayoutData(data);
+
+ assignedTo.addListener(SWT.KeyUp, new Listener() {
+ public void handleEvent(Event event) {
+ String sel = assignedTo.getText();
+ Attribute a = getBug().getAttribute("Assign To");
+ if (!(a.getNewValue().equals(sel))) {
+ a.setNewValue(sel);
+ changeDirtyStatus(true);
+ }
+ }
+ });
+ assignedTo.addListener(SWT.FocusIn, new GenericListener());
+
+ currentCol += 2;
+ } else if (key.equals("component")) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ componentCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.NO_BACKGROUND | SWT.MULTI
+ | SWT.V_SCROLL | SWT.READ_ONLY);
+ toolkit.adapt(componentCombo, true, true);
+ componentCombo.setFont(TEXT_FONT);
+ componentCombo.setLayoutData(data);
+ // componentCombo.setBackground(background);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ Arrays.sort(a);
+ for (int i = 0; i < a.length; i++) {
+ componentCombo.add(a[i]);
+ }
+ componentCombo.select(componentCombo.indexOf(value));
+ // componentCombo.addListener(SWT.Modify, this);
+ componentCombo.addSelectionListener(new ComboSelectionListener(componentCombo));
+ componentCombo.addListener(SWT.FocusIn, new GenericListener());
+ comboListenerMap.put(componentCombo, name);
+ currentCol += 2;
+ } else if (name.equals("Summary")) {
+ // Don't show the summary here.
+ continue;
+ } else if (name.equals("Last Modified")) {
+ // Don't show last modified here.
+ continue;
+ } else if (name.equals("Bug#")) {
+ // Don't show bug number here
+ continue;
+ } else if (values.isEmpty()) {
+ // newLayout(attributesComposite, 1, name, PROPERTY);
+ toolkit.createLabel(attributesComposite, name);
+ Composite uneditableComp = toolkit.createComposite(attributesComposite);
+ GridLayout textLayout = new GridLayout();
+ textLayout.marginWidth = 1;
+ uneditableComp.setLayout(textLayout);
+ toolkit.createText(uneditableComp, value, SWT.READ_ONLY);// Label(attributesComposite,
+ // value);
+ // newLayout(attributesComposite, 1, value,
+ // VALUE).addListener(SWT.FocusIn, new GenericListener());
+ currentCol += 2;
+ }
+ if (currentCol > attributesLayout.numColumns) {
+ currentCol -= attributesLayout.numColumns;
+ }
+ }
+ // End Populate Attributes
+
+ // make sure that we are in the first column
+ if (currentCol > 1) {
+ while (currentCol <= attributesLayout.numColumns) {
+ newLayout(attributesComposite, 1, "", PROPERTY);
+ currentCol++;
+ }
+ }
+
+ // URL, Keywords, Summary Text Fields
+ addUrlText(url, attributesComposite);
+
+ // keywords text field (not editable)
+ addKeywordsList(toolkit, keywords, attributesComposite);
+ if (ccValue != null) {
+ addCCList(toolkit, ccValue, attributesComposite);
+ }
+ addSummaryText(attributesComposite);
+ // End URL, Keywords, Summary Text Fields
+ toolkit.paintBordersFor(attributesComposite);
+ }
+
+ /**
+ * Adds a text field to display and edit the bug's URL attribute.
+ *
+ * @param url
+ * The URL attribute of the bug.
+ * @param attributesComposite
+ * The composite to add the text field to.
+ */
+ protected void addUrlText(String url, Composite attributesComposite) {
+ // newLayout(attributesComposite, 1, "URL:", PROPERTY);
+ toolkit.createLabel(attributesComposite, "URL:");
+ urlText = toolkit.createText(attributesComposite, url);
+ urlText.setFont(TEXT_FONT);
+ GridData urlTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ urlTextData.horizontalSpan = 3;
+ urlTextData.widthHint = 200;
+ urlText.setLayoutData(urlTextData);
+ // urlText.setText(url);
+ urlText.addListener(SWT.KeyUp, new Listener() {
+ public void handleEvent(Event event) {
+ String sel = urlText.getText();
+ Attribute a = getBug().getAttribute("URL");
+ if (!(a.getNewValue().equals(sel))) {
+ a.setNewValue(sel);
+ changeDirtyStatus(true);
+ }
+ }
+ });
+ urlText.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ protected abstract void addKeywordsList(FormToolkit toolkit, String keywords, Composite attributesComposite);
+
+ protected abstract void addCCList(FormToolkit toolkit, String value, Composite attributesComposite);
+
+ /**
+ * Adds a text field to display and edit the bug's summary.
+ *
+ * @param attributesComposite
+ * The composite to add the text field to.
+ */
+ protected void addSummaryText(Composite attributesComposite) {
+ // newLayout(attributesComposite, 1, "Summary:", PROPERTY);
+ toolkit.createLabel(attributesComposite, "Summary:");
+ summaryText = toolkit.createText(attributesComposite, getBug().getSummary());// SWT.BORDER
+ // |
+ // SWT.SINGLE
+ // |
+ // SWT.WRAP
+ summaryText.setFont(TEXT_FONT);
+ GridData summaryTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ summaryTextData.horizontalSpan = 3;
+ summaryTextData.widthHint = 200;
+ summaryText.setLayoutData(summaryTextData);
+ // summaryText.setText(getBug().getSummary());
+ summaryText.addListener(SWT.KeyUp, new SummaryListener());
+ summaryText.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ /**
+ * Creates the description layout, which displays and possibly edits the
+ * bug's description.
+ */
+ protected abstract void createDescriptionLayout(FormToolkit toolkit, final ScrolledForm form);
+
+ /**
+ * Creates the comment layout, which displays the bug's comments and
+ * possibly lets the user enter a new one.
+ */
+ protected abstract void createCommentLayout(FormToolkit toolkit, final ScrolledForm form);
+
+ /**
+ * Creates the button layout. This displays options and buttons at the
+ * bottom of the editor to allow actions to be performed on the bug.
+ */
+ protected void createButtonLayouts(FormToolkit toolkit, Composite formComposite) {
+
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_ACTIONS);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ Composite buttonComposite = toolkit.createComposite(section);
+ GridLayout buttonLayout = new GridLayout();
+ buttonLayout.numColumns = 4;
+ buttonComposite.setLayout(buttonLayout);
+ // buttonComposite.setBackground(background);
+ GridData buttonData = new GridData(GridData.FILL_BOTH);
+ buttonData.horizontalSpan = 1;
+ buttonData.grabExcessVerticalSpace = false;
+ buttonComposite.setLayoutData(buttonData);
+ section.setClient(buttonComposite);
+ addRadioButtons(buttonComposite);
+ addActionButtons(buttonComposite);
+ }
+
+ /**
+ * Adds radio buttons to this composite.
+ *
+ * @param buttonComposite
+ * Composite to add the radio buttons to.
+ */
+ abstract protected void addRadioButtons(Composite buttonComposite);
+
+ /**
+ * Adds buttons to this composite. Subclasses can override this method to
+ * provide different/additional buttons.
+ *
+ * @param buttonComposite
+ * Composite to add the buttons to.
+ */
+ protected void addActionButtons(Composite buttonComposite) {
+ submitButton = toolkit.createButton(buttonComposite, LABEL_BUTTON_SUBMIT, SWT.NONE);
+ // submitButton.setFont(TEXT_FONT);
+ GridData submitButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // submitButtonData.widthHint = AbstractBugEditor.WRAP_LENGTH;
+ // submitButtonData.heightHint = 20;
+
+ submitButton.setLayoutData(submitButtonData);
+ submitButton.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event e) {
+ submitBug();
+ }
+ });
+ submitButton.addListener(SWT.FocusIn, new GenericListener());
+
+ // This is not needed anymore since we have the save working properly
+ // with ctrl-s and file->save
+ // saveButton = new Button(buttonComposite, SWT.NONE);
+ // saveButton.setFont(TEXT_FONT);
+ // GridData saveButtonData = new
+ // GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // saveButtonData.widthHint = 100;
+ // saveButtonData.heightHint = 20;
+ // saveButton.setText("Save Offline");
+ // saveButton.setLayoutData(saveButtonData);
+ // saveButton.addListener(SWT.Selection, new Listener() {
+ // public void handleEvent(Event e) {
+ // saveBug();
+ // updateEditor();
+ // }
+ // });
+ // saveButton.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ /**
+ * Make sure that a String that is <code>null</code> is changed to a null
+ * string
+ *
+ * @param text
+ * The text to check if it is null or not
+ * @return If the text is <code>null</code>, then return the null string (<code>""</code>).
+ * Otherwise, return the text.
+ */
+ public static String checkText(String text) {
+ if (text == null)
+ return "";
+ else
+ return text;
+ }
+
+ /**
+ * @return A string to use as a title for this editor.
+ */
+ protected abstract String getTitleString();
+
+ /**
+ * Creates an uneditable text field for displaying data.
+ */
+ protected StyledText newLayout(Composite composite, int colSpan, String text, String style) {
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ data.horizontalSpan = colSpan;
+
+ StyledText resultText;
+ if (style.equalsIgnoreCase(VALUE)) {
+ resultText = new StyledText(composite, SWT.READ_ONLY);
+ resultText.setText(checkText(text));
+ resultText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+ resultText.setLayoutData(data);
+ } else if (style.equalsIgnoreCase(PROPERTY)) {
+ resultText = new StyledText(composite, SWT.READ_ONLY);
+ resultText.setText(checkText(text));
+ resultText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+ resultText.setLayoutData(data);
+ } else {
+ resultText = new StyledText(composite, SWT.READ_ONLY);
+ resultText.setText(checkText(text));
+ resultText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+ resultText.setLayoutData(data);
+ }
+
+ // composite.setMenu(contextMenuManager.createContextMenu(composite));
+ return resultText;
+ }
+
+ protected TextViewer addRepositoryText(TaskRepository repository, Composite composite, String text) {
+ RepositoryTextViewer commentViewer = new RepositoryTextViewer(repository, composite, SWT.NONE);
+
+ IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
+
+ commentViewer.getTextWidget().setFont(themeManager.getCurrentTheme().getFontRegistry().get(REPOSITORY_TEXT_ID));
+
+ commentViewer.setEditable(false);
+
+ commentViewer.getTextWidget().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+
+ commentViewer.getTextWidget().setMenu(contextMenuManager.createContextMenu(commentViewer.getTextWidget()));
+
+ // textViewer.getControl().setFont(COMMENT_FONT);
+ commentViewer.setDocument(new Document(text));
+ // commentViewer.activatePlugins();
+ // textViewer.refresh();
+ return commentViewer;
+ }
+
+ /**
+ * This refreshes the text in the title label of the info area (it contains
+ * elements which can change).
+ */
+ protected void setGeneralTitleText() {
+ // String text = "[Open in Internal Browser]";
+ // linkToBug.setText(text);
+ // linkToBug.setFont(TEXT_FONT);
+ // if (this instanceof ExistingBugEditor) {
+ // linkToBug.setUnderlined(true);
+ // linkToBug.setForeground(JFaceColors.getHyperlinkText(Display.getCurrent()));
+ // linkToBug.addMouseListener(new MouseListener() {
+ //
+ // public void mouseDoubleClick(MouseEvent e) {
+ // }
+ //
+ // public void mouseUp(MouseEvent e) {
+ // }
+ //
+ // public void mouseDown(MouseEvent e) {
+ // TaskListUiUtil.openUrl(getTitle(), getTitleToolTip(),
+ // BugzillaRepositoryUtil.getBugUrlWithoutLogin(
+ // bugzillaInput.getBug().getRepositoryUrl(),
+ // bugzillaInput.getBug().getId()));
+ // if (e.stateMask == SWT.MOD3) {
+ // // XXX come back to look at this ui
+ // close();
+ // }
+ //
+ // }
+ // });
+ // } else {
+ // linkToBug.setEnabled(false);
+ // }
+ // linkToBug.addListener(SWT.FocusIn, new GenericListener());
+ //
+ // // Resize the composite, in case the new summary is longer than the
+ // // previous one.
+ // // Then redraw it to show the changes.
+ // linkToBug.getParent().pack(true);
+ // linkToBug.redraw();
+
+ // String text = getTitleString();
+ // generalTitleText.setText(text);
+ // StyleRange sr = new StyleRange(generalTitleText.getOffsetAtLine(0),
+ // text.length(), foreground, background,
+ // SWT.BOLD);
+ // generalTitleText.setStyleRange(sr);
+ // generalTitleText.addListener(SWT.FocusIn, new GenericListener());
+ //
+ // // Resize the composite, in case the new summary is longer than the
+ // // previous one.
+ // // Then redraw it to show the changes.
+ // generalTitleText.getParent().pack(true);
+ // generalTitleText.redraw();
+ }
+
+ /**
+ * Creates some blank space underneath the supplied composite.
+ *
+ * @param parent
+ * The composite to add the blank space to.
+ */
+ protected void createSeparatorSpace(Composite parent) {
+ GridData separatorData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ separatorData.verticalSpan = 1;
+ separatorData.grabExcessVerticalSpace = false;
+
+ Composite separatorComposite = new Composite(parent, SWT.NONE);
+ GridLayout separatorLayout = new GridLayout();
+ separatorLayout.marginHeight = 0;
+ separatorLayout.verticalSpacing = 0;
+ separatorComposite.setLayout(separatorLayout);
+ // separatorComposite.setBackground(background);
+ separatorComposite.setLayoutData(separatorData);
+ newLayout(separatorComposite, 1, "", VALUE);
+ }
+
+ /**
+ * Submit the changes to the bug to the bugzilla server. (Public for testing
+ * purposes)
+ */
+ protected abstract void submitBug();
+
+ /**
+ * If there is no locally saved copy of the current bug, then it saved
+ * offline. Otherwise, any changes are updated in the file.
+ */
+ public void saveBug() {
+ try {
+ updateBug();
+ IBugzillaBug bug = getBug();
+
+ final BugzillaRepositoryConnector bugzillaRepositoryClient = (BugzillaRepositoryConnector) MylarTaskListPlugin
+ .getRepositoryManager().getRepositoryConnector(BugzillaPlugin.REPOSITORY_KIND);
+ changeDirtyStatus(false);
+ bugzillaRepositoryClient.saveBugReport(bug);
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, "bug save offline failed", true);
+ }
+
+ }
+
+ /**
+ * Updates the <code>IBugzillaBug</code> object to contain the latest data
+ * entered in the data fields.
+ */
+ protected abstract void updateBug();
+
+ /**
+ * Resets the data fields to contain the data currently in the
+ * <code>IBugzillaBug</code> object.
+ */
+ protected abstract void restoreBug();
+
+ /**
+ * Refreshes any text labels in the editor that contain information that
+ * might change.
+ */
+ protected void updateEditor() {
+ // Reset all summary occurrences, since it might have
+ // been edited.
+ // String title = getTitleString();
+ // titleLabel.setText(title);
+ setGeneralTitleText();
+ }
+
+ @Override
+ public void setFocus() {
+ form.setFocus();
+ }
+
+ @Override
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ /**
+ * Updates the dirty status of this editor page. The dirty status is true if
+ * the bug report has been modified but not saved. The title of the editor
+ * is also updated to reflect the status.
+ *
+ * @param newDirtyStatus
+ * is true when the bug report has been modified but not saved
+ */
+ public void changeDirtyStatus(boolean newDirtyStatus) {
+ isDirty = newDirtyStatus;
+ if (parentEditor == null) {
+ firePropertyChange(PROP_DIRTY);
+ } else {
+ parentEditor.markDirty();
+ }
+
+ }
+
+ /**
+ * Updates the title of the editor to reflect dirty status. If the bug
+ * report has been modified but not saved, then an indicator will appear in
+ * the title.
+ */
+ protected void updateEditorTitle() {
+ setPartName(bugzillaInput.getName());
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return false;
+ }
+
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+ saveBug();
+ updateEditor();
+
+ // XXX notify that saved ofline?
+ }
+
+ @Override
+ public void doSaveAs() {
+ // we don't save, so no need to implement
+ }
+
+ /**
+ * @return The composite for the whole editor.
+ */
+ public Composite getEditorComposite() {
+ return editorComposite;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ isDisposed = true;
+ getSite().getPage().removeSelectionListener(selectionListener);
+ }
+
+ // public void handleEvent(Event event) {
+ // if (event.widget instanceof CCombo) {
+ // CCombo combo = (CCombo) event.widget;
+ // if (comboListenerMap.containsKey(combo)) {
+ // if (combo.getSelectionIndex() > -1) {
+ // String sel = combo.getItem(combo.getSelectionIndex());
+ // Attribute attribute = getBug().getAttribute(comboListenerMap.get(combo));
+ // if (sel != null && !(sel.equals(attribute.getNewValue()))) {
+ // attribute.setNewValue(sel);
+ // for (IBugzillaAttributeListener client : attributesListeners) {
+ // client.attributeChanged(attribute.getName(), sel);
+ // }
+ // changeDirtyStatus(true);
+ // }
+ // }
+ // }
+ // }
+ // }
+
+ /**
+ * Fires a <code>SelectionChangedEvent</code> to all listeners registered
+ * under <code>selectionChangedListeners</code>.
+ *
+ * @param event
+ * The selection event.
+ */
+ protected void fireSelectionChanged(final SelectionChangedEvent event) {
+ Object[] listeners = selectionChangedListeners.toArray();
+ for (int i = 0; i < listeners.length; i++) {
+ final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
+ SafeRunnable.run(new SafeRunnable() {
+ public void run() {
+ l.selectionChanged(event);
+ }
+ });
+ }
+ }
+
+ /**
+ * A generic listener for selection of unimportant items. The default
+ * selection item sent out is the entire bug object.
+ */
+ protected class GenericListener implements Listener {
+ public void handleEvent(Event event) {
+ IBugzillaBug bug = getBug();
+ fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
+ new BugzillaReportSelection(bug.getId(), bug.getRepositoryUrl(), bug.getLabel(), false, bug
+ .getSummary()))));
+ }
+ }
+
+ /**
+ * A listener to check if the summary field was modified.
+ */
+ protected class SummaryListener implements Listener {
+ public void handleEvent(Event event) {
+ handleSummaryEvent();
+ }
+ }
+
+ /**
+ * Check if the summary field was modified, and update it if necessary.
+ */
+ public abstract void handleSummaryEvent();
+
+ /*----------------------------------------------------------*
+ * CODE TO SCROLL TO A COMMENT OR OTHER PIECE OF TEXT
+ *----------------------------------------------------------*/
+
+ /** List of the StyledText's so that we can get the previous and the next */
+ protected ArrayList<StyledText> texts = new ArrayList<StyledText>();
+
+ protected HashMap<Object, StyledText> textHash = new HashMap<Object, StyledText>();
+
+ /** Index into the styled texts */
+ protected int textsindex = 0;
+
+ protected Text addCommentsTextBox = null;
+
+ protected Text descriptionTextBox = null;
+
+ // private FormText previousText = null;
+
+ /**
+ * Selects the given object in the editor.
+ *
+ * @param commentNumber
+ * The comment number to be selected
+ */
+ public void select(int commentNumber) {
+ if (commentNumber == -1)
+ return;
+
+ for (Object o : textHash.keySet()) {
+ if (o instanceof Comment) {
+ if (((Comment) o).getNumber() == commentNumber) {
+ select(o, true);
+ }
+ }
+ }
+ }
+
+ public void revealAllComments() {
+ for (StyledText text : textHash.values()) {
+ Composite comp = text.getParent();
+ while (comp != null) {
+ if (comp instanceof ExpandableComposite) {
+ ExpandableComposite ex = (ExpandableComposite) comp;
+ ex.setExpanded(true);
+ }
+ comp = comp.getParent();
+ }
+ }
+ }
+
+ /**
+ * Selects the given object in the editor.
+ *
+ * @param o
+ * The object to be selected.
+ * @param highlight
+ * Whether or not the object should be highlighted.
+ */
+ public void select(Object o, boolean highlight) {
+ if (textHash.containsKey(o)) {
+ StyledText t = textHash.get(o);
+ if (t != null) {
+ Composite comp = t.getParent();
+ while (comp != null) {
+ if (comp instanceof ExpandableComposite) {
+ ExpandableComposite ex = (ExpandableComposite) comp;
+ ex.setExpanded(true);
+ }
+ comp = comp.getParent();
+ }
+ focusOn(t, highlight);
+ }
+ } else if (o instanceof IBugzillaBug) {
+ focusOn(null, highlight);
+ }
+ }
+
+ public void selectDescription() {
+ for (Object o : textHash.keySet()) {
+ if (o.equals(bugzillaInput.getBug().getDescription())) {
+ select(o, true);
+ }
+ }
+ }
+
+ public void selectNewComment() {
+ focusOn(addCommentsTextBox, false);
+ }
+
+ public void selectNewDescription() {
+ focusOn(descriptionTextBox, false);
+ }
+
+ /**
+ * Scroll to a specified piece of text
+ *
+ * @param selectionComposite
+ * The StyledText to scroll to
+ */
+ private void focusOn(Control selectionComposite, boolean highlight) {
+ int pos = 0;
+ // if (previousText != null && !previousText.isDisposed()) {
+ // previousText.setsetSelection(0);
+ // }
+
+ // if (selectionComposite instanceof FormText)
+ // previousText = (FormText) selectionComposite;
+
+ if (selectionComposite != null) {
+
+ // if (highlight && selectionComposite instanceof FormText &&
+ // !selectionComposite.isDisposed())
+ // ((FormText) selectionComposite).set.setSelection(0, ((FormText)
+ // selectionComposite).getText().length());
+
+ // get the position of the text in the composite
+ pos = 0;
+ Control s = selectionComposite;
+ if (s.isDisposed())
+ return;
+ s.setEnabled(true);
+ s.setFocus();
+ s.forceFocus();
+ while (s != null && s != getEditorComposite()) {
+ if (!s.isDisposed()) {
+ pos += s.getLocation().y;
+ s = s.getParent();
+ }
+ }
+
+ pos = pos - 60; // form.getOrigin().y;
+
+ }
+ if (!form.getBody().isDisposed())
+ form.setOrigin(0, pos);
+ }
+
+ private BugzillaOutlinePage outlinePage = null;
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (IContentOutlinePage.class.equals(adapter)) {
+ if (outlinePage == null && bugzillaInput != null) {
+ outlinePage = new BugzillaOutlinePage(bugzillaOutlineModel);
+ }
+ return outlinePage;
+ }
+ return super.getAdapter(adapter);
+ }
+
+ public BugzillaOutlineNode getOutlineModel() {
+ return bugzillaOutlineModel;
+ }
+
+ public BugzillaOutlinePage getOutline() {
+ return outlinePage;
+ }
+
+ private boolean isDisposed = false;
+
+ public boolean isDisposed() {
+ return isDisposed;
+ }
+
+ public void close() {
+ Display activeDisplay = getSite().getShell().getDisplay();
+ activeDisplay.asyncExec(new Runnable() {
+ public void run() {
+ if (getSite() != null && getSite().getPage() != null && !AbstractBugEditor.this.isDisposed())
+ if (parentEditor != null) {
+ getSite().getPage().closeEditor(parentEditor, false);
+ } else {
+ getSite().getPage().closeEditor(AbstractBugEditor.this, false);
+ }
+ }
+ });
+ }
+
+ public void addAttributeListener(IBugzillaAttributeListener listener) {
+ attributesListeners.add(listener);
+ }
+
+ public void removeAttributeListener(IBugzillaAttributeListener listener) {
+ attributesListeners.remove(listener);
+ }
+
+ public void setParentEditor(MylarTaskEditor parentEditor) {
+ this.parentEditor = parentEditor;
+ }
+
+ public BugzillaOutlineNode getBugzillaOutlineModel() {
+ return bugzillaOutlineModel;
+ }
+
+ public void setBugzillaOutlineModel(BugzillaOutlineNode bugzillaOutlineModel) {
+ this.bugzillaOutlineModel = bugzillaOutlineModel;
+ }
+
+ // private void addHyperlinks(final StyledText styledText, Composite
+ // composite) {
+ //
+ // StringMatcher javaElementMatcher = new StringMatcher("*(*.java:*)", true,
+ // false);
+ // String[] lines = styledText.getText().split("\r\n|\n");
+ //
+ // int totalLength = 0;
+ // for (int x = 0; x < lines.length; x++) {
+ //
+ // String line = lines[x];
+ // Position position = javaElementMatcher.find(line, 0, line.length());
+ // if (position != null) {
+ // String linkText = line.substring(position.getStart() + 1,
+ // position.getEnd() - 1);
+ // // Link hyperlink = new Link(styledText, SWT.NONE);
+ // IRegion region = new Region(styledText.getText().indexOf(line) +
+ // position.getStart(), position.getEnd()
+ // - position.getStart());
+ // addControl(styledText, region, linkText, line, HYPERLINK_TYPE_JAVA);
+ // }
+ //
+ // IHyperlink[] bugHyperlinks = BugzillaUITools.findBugHyperlinks(0,
+ // line.length(), line, 0);
+ // if (bugHyperlinks != null) {
+ // for (IHyperlink hyperlink : bugHyperlinks) {
+ // String linkText = hyperlink.getHyperlinkText();
+ // int index = linkText.lastIndexOf('=');
+ // if (index >= 0) {
+ // String taskId = linkText.substring(index + 1);
+ // String href = repository.getUrl() + hyperlink.getHyperlinkText();
+ // addControl(styledText, hyperlink.getHyperlinkRegion(), "bug# " + taskId,
+ // href,
+ // HYPERLINK_TYPE_TASK);
+ // }
+ //
+ // }
+ // }
+ //
+ // totalLength = totalLength + line.length();
+ //
+ // } // bottom of for loop
+ //
+ // // reposition widgets on paint event
+ // styledText.addPaintObjectListener(new PaintObjectListener() {
+ // public void paintObject(PaintObjectEvent event) {
+ // StyleRange style = event.style;
+ // int start = style.start;
+ // Map<Integer, Control> controlMap = controls.get(styledText);
+ // Control control = controlMap.get(start);
+ // if (control != null) {
+ // Point pt = control.getSize();
+ // int x = event.x + MARGIN;
+ // int y = event.y + event.ascent - 2 * pt.y / 3;
+ // control.setLocation(x, y);
+ // }
+ // }
+ // });
+ // }
+
+ // private void addControl(final StyledText styledText, IRegion region,
+ // String linkText, String href,
+ // final String listenerType) {
+ // Hyperlink hyperlink = toolkit.createHyperlink(styledText, linkText,
+ // SWT.NONE);
+ // hyperlink.setText(linkText);
+ // hyperlink.setFont(COMMENT_FONT);
+ // hyperlink.setHref(href);
+ // IHyperlinkListener hyperlinkListener =
+ // MylarTaskListPlugin.getDefault().getTaskHyperlinkListeners().get(
+ // listenerType);
+ // if (hyperlinkListener != null) {
+ // hyperlink.addHyperlinkListener(hyperlinkListener);
+ // }
+ // Map<Integer, Control> controlMap = controls.get(styledText);
+ // if (controlMap == null) {
+ // controlMap = new HashMap<Integer, Control>();
+ // controls.put(styledText, controlMap);
+ // }
+ // controlMap.put(new Integer(region.getOffset()), hyperlink);
+ // StyleRange style = new StyleRange();
+ // style.start = region.getOffset();
+ // style.length = region.getLength();
+ // hyperlink.pack();
+ // Rectangle rect = hyperlink.getBounds();
+ // int ascent = 2 * rect.height / 3;
+ // int descent = rect.height - ascent;
+ // style.metrics = new GlyphMetrics(ascent + MARGIN, descent + MARGIN,
+ // rect.width + 2 * MARGIN);
+ // styledText.setStyleRange(style);
+ // }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/ExistingBugEditor.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/ExistingBugEditor.java
new file mode 100644
index 000000000..f9c6fd33e
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/ExistingBugEditor.java
@@ -0,0 +1,1083 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui.editor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareUI;
+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.Job;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.TextViewer;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.mylar.bugzilla.core.Attribute;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.Comment;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+import org.eclipse.mylar.bugzilla.core.Operation;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaReportSubmitForm;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.compare.BugzillaCompareInput;
+import org.eclipse.mylar.internal.bugzilla.core.internal.HtmlStreamTokenizer;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaRepositoryConnector;
+import org.eclipse.mylar.internal.tasklist.ui.TaskUiUtil;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.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.Event;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.events.IExpansionListener;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.Section;
+
+/**
+ * An editor used to view a bug report that exists on a server. It uses a
+ * <code>BugReport</code> object to store the data.
+ *
+ * @author Mik Kersten (hardening of prototype)
+ * @author Rob Elves (adaption to Eclipse Forms)
+ */
+public class ExistingBugEditor extends AbstractBugEditor {
+
+ private static final String REASSIGN_BUG_TO = "Reassign bug to";
+
+ private static final String LABEL_EXPAND_ALL_BUTTON = "Expand All";
+
+ private static final String LABEL_COMPARE_BUTTON = "Compare";
+
+ private static final String ATTR_SUMMARY = "Summary";
+
+ protected Set<String> removeCC = new HashSet<String>();
+
+ protected BugzillaCompareInput compareInput;
+
+ protected Button compareButton;
+
+ protected Button[] radios;
+
+ protected Control[] radioOptions;
+
+ protected List keyWordsList;
+
+ protected Text keywordsText;
+
+ protected List ccList;
+
+ protected Text ccText;
+
+ protected Text addCommentsText;
+
+ protected BugReport bug;
+
+ public String getNewCommentText() {
+ return addCommentsTextBox.getText();
+ }
+
+ /**
+ * Creates a new <code>ExistingBugEditor</code>.
+ */
+ public ExistingBugEditor() {
+ super();
+
+ // Set up the input for comparing the bug report to the server
+ CompareConfiguration config = new CompareConfiguration();
+ config.setLeftEditable(false);
+ config.setRightEditable(false);
+ config.setLeftLabel("Local Bug Report");
+ config.setRightLabel("Remote Bug Report");
+ config.setLeftImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT));
+ config.setRightImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT));
+ compareInput = new BugzillaCompareInput(config);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+ if (!(input instanceof ExistingBugEditorInput))
+ throw new PartInitException("Invalid Input: Must be ExistingBugEditorInput");
+ ExistingBugEditorInput editorInput = (ExistingBugEditorInput) input;
+ repository = editorInput.getRepository();
+
+ setSite(site);
+ setInput(input);
+ bugzillaInput = editorInput;
+ bugzillaOutlineModel = BugzillaOutlineNode.parseBugReport(bugzillaInput.getBug());
+
+ bug = editorInput.getBug();
+ restoreBug();
+ isDirty = false;
+ updateEditorTitle();
+ }
+
+ /**
+ * This overrides the existing implementation in order to add an "add to
+ * favorites" option to the context menu.
+ *
+ * @see org.eclipse.mylar.internal.bugzilla.ui.AbstractBugEditor#createContextMenu()
+ */
+ @Override
+ protected void createContextMenu() {
+ contextMenuManager = new MenuManager("#BugEditor");
+ contextMenuManager.setRemoveAllWhenShown(true);
+ contextMenuManager.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ // manager.add(new
+ // AddToFavoritesAction(ExistingBugEditor.this));
+ // manager.add(new Separator());
+ manager.add(cutAction);
+ manager.add(copyAction);
+ manager.add(pasteAction);
+ manager.add(new Separator());
+ manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+ if (currentSelectedText == null || currentSelectedText.getSelectionText().length() == 0) {
+
+ copyAction.setEnabled(false);
+ } else {
+ copyAction.setEnabled(true);
+ }
+ }
+ });
+ getSite().registerContextMenu("#BugEditor", contextMenuManager, getSite().getSelectionProvider());
+ }
+
+ @Override
+ protected void addRadioButtons(Composite buttonComposite) {
+ FormToolkit toolkit = new FormToolkit(buttonComposite.getDisplay());
+ int i = 0;
+ Button selected = null;
+ radios = new Button[bug.getOperations().size()];
+ radioOptions = new Control[bug.getOperations().size()];
+ for (Iterator<Operation> it = bug.getOperations().iterator(); it.hasNext();) {
+ Operation o = it.next();
+ radios[i] = toolkit.createButton(buttonComposite, "", SWT.RADIO);
+ radios[i].setFont(TEXT_FONT);
+ GridData radioData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ if (!o.hasOptions() && !o.isInput())
+ radioData.horizontalSpan = 4;
+ else
+ radioData.horizontalSpan = 3;
+ radioData.heightHint = 20;
+ String opName = o.getOperationName();
+ opName = opName.replaceAll("</.*>", "");
+ opName = opName.replaceAll("<.*>", "");
+ radios[i].setText(opName);
+ radios[i].setLayoutData(radioData);
+ // radios[i].setBackground(background);
+ radios[i].addSelectionListener(new RadioButtonListener());
+ radios[i].addListener(SWT.FocusIn, new GenericListener());
+
+ if (o.hasOptions()) {
+ radioData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ radioData.horizontalSpan = 1;
+ radioData.heightHint = 20;
+ radioData.widthHint = AbstractBugEditor.WRAP_LENGTH;
+ // radioOptions[i] = new Combo(buttonComposite, SWT.NULL);
+ radioOptions[i] = new CCombo(buttonComposite, SWT.FLAT | SWT.READ_ONLY);
+ toolkit.adapt(radioOptions[i], true, true);
+ // radioOptions[i] = new Combo(buttonComposite, SWT.MULTI |
+ // SWT.V_SCROLL | SWT.READ_ONLY);
+ // radioOptions[i].setData(FormToolkit.KEY_DRAW_BORDER,
+ // FormToolkit.TEXT_BORDER);
+ // radioOptions[i] = new Combo(buttonComposite,
+ // SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ // | SWT.READ_ONLY);
+ radioOptions[i].setFont(TEXT_FONT);
+ radioOptions[i].setLayoutData(radioData);
+ // radioOptions[i].setBackground(background);
+
+ Object[] a = o.getOptionNames().toArray();
+ Arrays.sort(a);
+ for (int j = 0; j < a.length; j++) {
+ ((CCombo) radioOptions[i]).add((String) a[j]);
+ }
+ ((CCombo) radioOptions[i]).select(0);
+ ((CCombo) radioOptions[i]).addSelectionListener(new RadioButtonListener());
+ } else if (o.isInput()) {
+ radioData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ radioData.horizontalSpan = 1;
+ radioData.widthHint = 120;
+
+ // TODO: add condition for if opName = reassign to...
+ String assignmentValue = "";
+ if(opName.equals(REASSIGN_BUG_TO)) {
+ assignmentValue = repository.getUserName();
+ }
+ radioOptions[i] = toolkit.createText(buttonComposite, assignmentValue);// ,
+ // SWT.SINGLE);
+ radioOptions[i].setFont(TEXT_FONT);
+ radioOptions[i].setLayoutData(radioData);
+ // radioOptions[i].setBackground(background);
+ ((Text) radioOptions[i]).setText(o.getInputValue());
+ ((Text) radioOptions[i]).addModifyListener(new RadioButtonListener());
+ }
+
+ if (i == 0 || o.isChecked()) {
+ if (selected != null)
+ selected.setSelection(false);
+ selected = radios[i];
+ radios[i].setSelection(true);
+ if (o.hasOptions() && o.getOptionSelection() != null) {
+ int j = 0;
+ for (String s : ((CCombo) radioOptions[i]).getItems()) {
+ if (s.compareTo(o.getOptionSelection()) == 0) {
+ ((CCombo) radioOptions[i]).select(j);
+ }
+ j++;
+ }
+ }
+ bug.setSelectedOperation(o);
+ }
+
+ i++;
+ }
+ toolkit.paintBordersFor(buttonComposite);
+ }
+
+ @Override
+ protected void addActionButtons(Composite buttonComposite) {
+ FormToolkit toolkit = new FormToolkit(buttonComposite.getDisplay());
+ super.addActionButtons(buttonComposite);
+
+ compareButton = toolkit.createButton(buttonComposite, LABEL_COMPARE_BUTTON, SWT.NONE);
+// compareButton.setFont(TEXT_FONT);
+ GridData compareButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+// compareButtonData.widthHint = 100;
+// compareButtonData.heightHint = 20;
+// // compareButton.setText("Compare");
+ compareButton.setLayoutData(compareButtonData);
+ compareButton.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event e) {
+ OpenCompareEditorJob compareJob = new OpenCompareEditorJob("Comparing bug with remote server...");
+ compareJob.schedule();
+ }
+ });
+ compareButton.addListener(SWT.FocusIn, new GenericListener());
+
+ Button expandAll = toolkit.createButton(buttonComposite, LABEL_EXPAND_ALL_BUTTON, SWT.NONE);
+ expandAll.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ expandAll.addSelectionListener(new SelectionListener() {
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // ignore
+
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ revealAllComments();
+
+ }
+ });
+
+
+ // TODO used for spell checking. Add back when we want to support this
+ // checkSpellingButton = new Button(buttonComposite, SWT.NONE);
+ // checkSpellingButton.setFont(TEXT_FONT);
+ // compareButtonData = new
+ // GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // compareButtonData.widthHint = 100;
+ // compareButtonData.heightHint = 20;
+ // checkSpellingButton.setText("CheckSpelling");
+ // checkSpellingButton.setLayoutData(compareButtonData);
+ // checkSpellingButton.addListener(SWT.Selection, new Listener() {
+ // public void handleEvent(Event e) {
+ // checkSpelling();
+ // }
+ // });
+ // checkSpellingButton.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ /**
+ * @return Returns the compareInput.
+ */
+ public BugzillaCompareInput getCompareInput() {
+ return compareInput;
+ }
+
+ @Override
+ public IBugzillaBug getBug() {
+ return bug;
+ }
+
+ @Override
+ protected String getTitleString() {
+// Attribute summary = bug.getAttribute(ATTR_SUMMARY);
+// String summaryVal = ((null != summary) ? summary.getNewValue() : null);
+ return bug.getLabel();// + ": " + checkText(summaryVal);
+ }
+
+ @Override
+ public void submitBug() {
+
+ submitButton.setEnabled(false);
+ ExistingBugEditor.this.showBusy(true);
+
+ final BugzillaReportSubmitForm bugzillaReportSubmitForm = BugzillaReportSubmitForm.makeExistingBugPost(bug,
+ repository, removeCC);
+
+ final BugzillaRepositoryConnector bugzillaRepositoryClient = (BugzillaRepositoryConnector) MylarTaskListPlugin
+ .getRepositoryManager().getRepositoryConnector(BugzillaPlugin.REPOSITORY_KIND);
+
+ IJobChangeListener closeEditorListener = new IJobChangeListener() {
+
+ public void done(final IJobChangeEvent event) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (event.getJob().getResult().equals(Status.OK_STATUS)) {
+ close();
+ } else {
+ submitButton.setEnabled(true);
+ ExistingBugEditor.this.showBusy(false);
+ }
+ }
+ });
+ }
+
+ public void aboutToRun(IJobChangeEvent event) {
+ // ignore
+ }
+
+ public void awake(IJobChangeEvent event) {
+ // ignore
+ }
+
+ public void running(IJobChangeEvent event) {
+ // ignore
+ }
+
+ public void scheduled(IJobChangeEvent event) {
+ // ignore
+ }
+
+ public void sleeping(IJobChangeEvent event) {
+ // ignore
+ }
+ };
+ bugzillaRepositoryClient.submitBugReport(bug, bugzillaReportSubmitForm, closeEditorListener);
+ }
+
+ @Override
+ protected void createDescriptionLayout(FormToolkit toolkit, final ScrolledForm form) {
+
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_DESCRIPTION);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ // Description Area
+ Composite descriptionComposite = toolkit.createComposite(section);
+ GridLayout descriptionLayout = new GridLayout();
+ descriptionLayout.numColumns = 1;
+ descriptionComposite.setLayout(descriptionLayout);
+ // descriptionComposite.setBackground(background);
+ //GridData descriptionData = new GridData(GridData.FILL_HORIZONTAL);
+ //descriptionData.horizontalSpan = 1;
+ //descriptionData.grabExcessVerticalSpace = false;
+ // descriptionComposite.setLayoutData(descriptionData);
+ // End Description Area
+
+ section.setClient(descriptionComposite);
+
+ // FormText t = newLayout(descriptionComposite, 4, "Description:",
+ // HEADER);
+
+ // t.addListener(SWT.FocusIn, new DescriptionListener());
+ //StyledText t = newLayout(descriptionComposite, 4, bug.getDescription(), VALUE);
+ // t.setFont(COMMENT_FONT);
+
+ TextViewer viewer = addRepositoryText(repository, descriptionComposite, bug.getDescription());
+ StyledText styledText = viewer.getTextWidget();
+ styledText.addListener(SWT.FocusIn, new DescriptionListener());
+
+ texts.add(textsindex, styledText);
+ textHash.put(bug.getDescription(), styledText);
+ textsindex++;
+
+ }
+
+ /**
+ * http://www.eclipse.org and http://www.eclipse.org/mylar and a
+ */
+ @Override
+ protected void createCommentLayout(FormToolkit toolkit, final ScrolledForm form) {
+
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_COMMENTS);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ // Additional (read-only) Comments Area
+ Composite addCommentsComposite = toolkit.createComposite(section);
+ section.setClient(addCommentsComposite);
+ GridLayout addCommentsLayout = new GridLayout();
+ addCommentsLayout.numColumns = 1;
+ addCommentsComposite.setLayout(addCommentsLayout);
+ // addCommentsComposite.setBackground(background);
+ GridData addCommentsData = new GridData(GridData.FILL_BOTH);
+ addCommentsData.horizontalSpan = 1;
+ addCommentsData.widthHint = DESCRIPTION_WIDTH;
+ addCommentsData.heightHint = DESCRIPTION_HEIGHT;
+ addCommentsData.grabExcessVerticalSpace = false;
+ addCommentsComposite.setLayoutData(addCommentsData);
+ // End Additional (read-only) Comments Area
+
+
+
+ StyledText styledText = null;
+ for (Iterator<Comment> it = bug.getComments().iterator(); it.hasNext();) {
+ final Comment comment = it.next();
+
+ ExpandableComposite ec = toolkit.createExpandableComposite(addCommentsComposite,
+ ExpandableComposite.TREE_NODE);
+
+ if (!it.hasNext()) {
+ ec.setExpanded(true);
+ }
+
+ ec.setText(comment.getNumber() + ": " +comment.getAuthorName() + ", " + simpleDateFormat.format(comment.getCreated()));
+
+ ec.addExpansionListener(new ExpansionAdapter() {
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ ec.setLayout(new GridLayout());
+
+ Composite ecComposite = toolkit.createComposite(ec);
+ ecComposite.setLayout(new GridLayout());
+ ec.setClient(ecComposite);
+ toolkit.paintBordersFor(ec);
+
+ if (comment.hasAttachment()) {
+
+ Link attachmentLink = new Link(ecComposite, SWT.NONE);
+
+ String attachmentHeader;
+
+ if(!comment.isObsolete()) {
+ attachmentHeader = " Attached: " + comment.getAttachmentDescription() + " [<a>view</a>]";
+ } else {
+ attachmentHeader = " Deprecated: " + comment.getAttachmentDescription();
+ }
+ // String result = MessageFormat.format(attachmentHeader, new
+ // String[] { node
+ // .getLabelText() });
+
+ attachmentLink.addSelectionListener(new SelectionAdapter() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ public void widgetSelected(SelectionEvent e) {
+ String address = repository.getUrl() + "/attachment.cgi?id=" + comment.getAttachmentId()
+ + "&amp;action=view";
+ TaskUiUtil.openUrl(address, address, address);
+
+ }
+ });
+
+ attachmentLink.setText(attachmentHeader);
+
+ }
+
+ // styledText = newLayout(ecComposite, 1, comment.getText(), VALUE);
+ // styledText.addListener(SWT.FocusIn, new
+ // CommentListener(comment));
+ // styledText.setFont(COMMENT_FONT);
+
+ TextViewer viewer = addRepositoryText(repository, ecComposite, comment.getText());
+ styledText = viewer.getTextWidget();
+
+ // code for outline
+ texts.add(textsindex, styledText);
+ textHash.put(comment, styledText);
+ textsindex++;
+ }
+
+ Section sectionAdditionalComments = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR
+ | Section.TWISTIE);
+ sectionAdditionalComments.setText(LABEL_SECTION_NEW_COMMENT);
+ sectionAdditionalComments.setExpanded(true);
+ // sectionAdditionalComments.setLayout(new GridLayout());
+ // GridData newCommentCommentLayoutData = new GridData();
+ // newCommentCommentLayoutData.widthHint = DESCRIPTION_WIDTH;
+ // sectionAdditionalComments.setLayoutData(newCommentCommentLayoutData);
+ sectionAdditionalComments.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ sectionAdditionalComments.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ Composite newCommentsComposite = toolkit.createComposite(sectionAdditionalComments);
+ newCommentsComposite.setLayout(new GridLayout());
+ newCommentsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ addCommentsText = toolkit.createText(newCommentsComposite, bug.getNewComment(), SWT.MULTI | SWT.V_SCROLL
+ | SWT.WRAP);
+ addCommentsText.setFont(COMMENT_FONT);
+ toolkit.paintBordersFor(newCommentsComposite);
+ GridData addCommentsTextData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ //addCommentsTextData.horizontalSpan = 4;
+ addCommentsTextData.widthHint = DESCRIPTION_WIDTH;
+ addCommentsTextData.heightHint = DESCRIPTION_HEIGHT;
+ addCommentsTextData.grabExcessHorizontalSpace = true;
+
+ addCommentsText.setLayoutData(addCommentsTextData);
+ // addCommentsText.setText(bug.getNewComment());
+ addCommentsText.addListener(SWT.KeyUp, new Listener() {
+
+ public void handleEvent(Event event) {
+ String sel = addCommentsText.getText();
+ if (!(bug.getNewNewComment().equals(sel))) {
+ bug.setNewNewComment(sel);
+ changeDirtyStatus(true);
+ }
+ validateInput();
+ }
+ });
+ addCommentsText.addListener(SWT.FocusIn, new NewCommentListener());
+ // End Additional Comments Text
+
+ addCommentsTextBox = addCommentsText;
+
+ // this.createSeparatorSpace(addCommentsComposite);
+ sectionAdditionalComments.setClient(newCommentsComposite);
+ }
+
+ @Override
+ protected void addKeywordsList(FormToolkit toolkit, String keywords, Composite attributesComposite) {
+ // newLayout(attributesComposite, 1, "Keywords:", PROPERTY);
+ toolkit.createLabel(attributesComposite, "Keywords:");
+ keywordsText = toolkit.createText(attributesComposite, keywords);
+ keywordsText.setFont(TEXT_FONT);
+ keywordsText.setEditable(false);
+ // keywordsText.setForeground(foreground);
+ // keywordsText.setBackground(JFaceColors.getErrorBackground(display));
+ GridData keywordsData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ keywordsData.horizontalSpan = 2;
+ keywordsData.widthHint = 200;
+ keywordsText.setLayoutData(keywordsData);
+ // keywordsText.setText(keywords);
+ keywordsText.addListener(SWT.FocusIn, new GenericListener());
+ keyWordsList = new List(attributesComposite, SWT.MULTI | SWT.V_SCROLL);
+ keyWordsList.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
+ keyWordsList.setFont(TEXT_FONT);
+ GridData keyWordsTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ keyWordsTextData.horizontalSpan = 1;
+ keyWordsTextData.widthHint = 125;
+ keyWordsTextData.heightHint = 40;
+ keyWordsList.setLayoutData(keyWordsTextData);
+
+ // initialize the keywords list with valid values
+ java.util.List<String> keywordList = bug.getKeywords();
+ if (keywordList != null) {
+ for (Iterator<String> it = keywordList.iterator(); it.hasNext();) {
+ String keyword = it.next();
+ keyWordsList.add(keyword);
+ }
+
+ // get the selected keywords for the bug
+ StringTokenizer st = new StringTokenizer(keywords, ",", false);
+ ArrayList<Integer> indicies = new ArrayList<Integer>();
+ while (st.hasMoreTokens()) {
+ String s = st.nextToken().trim();
+ int index = keyWordsList.indexOf(s);
+ if (index != -1)
+ indicies.add(new Integer(index));
+ }
+
+ // select the keywords that were selected for the bug
+ int length = indicies.size();
+ int[] sel = new int[length];
+ for (int i = 0; i < length; i++) {
+ sel[i] = indicies.get(i).intValue();
+ }
+ keyWordsList.select(sel);
+ }
+
+ keyWordsList.addSelectionListener(new KeywordListener());
+ keyWordsList.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ @Override
+ protected void addCCList(FormToolkit toolkit, String ccValue, Composite attributesComposite) {
+ newLayout(attributesComposite, 1, "Add CC:", PROPERTY);
+ ccText = toolkit.createText(attributesComposite, ccValue);
+ ccText.setFont(TEXT_FONT);
+ ccText.setEditable(true);
+ // ccText.setForeground(foreground);
+ // ccText.setBackground(background);
+ GridData ccData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ ccData.horizontalSpan = 1;
+ ccData.widthHint = 200;
+ ccText.setLayoutData(ccData);
+ // ccText.setText(ccValue);
+ ccText.addListener(SWT.FocusIn, new GenericListener());
+ ccText.addModifyListener(new ModifyListener() {
+
+ public void modifyText(ModifyEvent e) {
+ changeDirtyStatus(true);
+ Attribute a = bug.getAttributeForKnobName("newcc");
+ if (a != null) {
+ a.setNewValue(ccText.getText());
+ }
+ }
+
+ });
+
+ // newLayout(attributesComposite, 1, "CC: (Select to remove)",
+ // PROPERTY);
+ toolkit.createLabel(attributesComposite, "CC: (Select to remove)");
+ ccList = new List(attributesComposite, SWT.MULTI | SWT.V_SCROLL);// SWT.BORDER
+ ccList.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
+ ccList.setFont(TEXT_FONT);
+ GridData ccListData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ ccListData.horizontalSpan = 1;
+ ccListData.widthHint = 125;
+ ccListData.heightHint = 40;
+ ccList.setLayoutData(ccListData);
+
+ // initialize the keywords list with valid values
+ Set<String> ccs = bug.getCC();
+ if (ccs != null) {
+ for (Iterator<String> it = ccs.iterator(); it.hasNext();) {
+ String cc = it.next();
+ ccList.add(HtmlStreamTokenizer.unescape(cc));
+ }
+ }
+
+ ccList.addSelectionListener(new SelectionListener() {
+
+ public void widgetSelected(SelectionEvent e) {
+ changeDirtyStatus(true);
+
+ for (String cc : ccList.getItems()) {
+ int index = ccList.indexOf(cc);
+ if (ccList.isSelected(index)) {
+ removeCC.add(cc);
+ } else {
+ removeCC.remove(cc);
+ }
+ }
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ ccList.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ @Override
+ protected void updateBug() {
+
+ // go through all of the attributes and update the main values to the
+ // new ones
+ for (Iterator<Attribute> it = bug.getAttributes().iterator(); it.hasNext();) {
+ Attribute a = it.next();
+ if (a.getNewValue() != null && a.getNewValue().compareTo(a.getValue()) != 0) {
+ bug.setHasChanged(true);
+ }
+ a.setValue(a.getNewValue());
+
+ }
+ if (bug.getNewComment().compareTo(bug.getNewNewComment()) != 0) {
+ bug.setHasChanged(true);
+ }
+
+ // Update some other fields as well.
+ bug.setNewComment(bug.getNewNewComment());
+
+ }
+
+ @Override
+ protected void restoreBug() {
+
+ if (bug == null)
+ return;
+
+ // go through all of the attributes and restore the new values to the
+ // main ones
+ for (Iterator<Attribute> it = bug.getAttributes().iterator(); it.hasNext();) {
+ Attribute a = it.next();
+ a.setNewValue(a.getValue());
+ }
+
+ // Restore some other fields as well.
+ bug.setNewNewComment(bug.getNewComment());
+ }
+
+ /**
+ * This job opens a compare editor to compare the current state of the bug
+ * in the editor with the bug on the server.
+ */
+ protected class OpenCompareEditorJob extends Job {
+
+ public OpenCompareEditorJob(String name) {
+ super(name);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final BugReport serverBug;
+ try {
+ serverBug = BugzillaRepositoryUtil.getBug(bug.getRepositoryUrl(), bug.getId());
+ // If no bug was found on the server, throw an exception so that
+ // the
+ // user gets the same message that appears when there is a
+ // problem reading the server.
+ if (serverBug == null)
+ throw new Exception();
+ } catch (Exception e) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ "Could not open bug.", "Bug #" + bug.getId() + " could not be read from the server.");
+ }
+ });
+ return new Status(IStatus.OK, IBugzillaConstants.PLUGIN_ID, IStatus.OK,
+ "Could not get the bug report from the server.", null);
+ }
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ compareInput.setTitle("Bug #" + bug.getId());
+ compareInput.setLeft(bug);
+ compareInput.setRight(serverBug);
+ CompareUI.openCompareEditor(compareInput);
+ }
+ });
+ return new Status(IStatus.OK, IBugzillaConstants.PLUGIN_ID, IStatus.OK, "", null);
+ }
+
+ }
+
+ /**
+ * Class to handle the selection change of the keywords.
+ */
+ protected class KeywordListener implements SelectionListener {
+
+ /*
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ public void widgetSelected(SelectionEvent arg0) {
+ changeDirtyStatus(true);
+
+ // get the selected keywords and create a string to submit
+ StringBuffer keywords = new StringBuffer();
+ String[] sel = keyWordsList.getSelection();
+
+ // allow unselecting 1 keyword when it is the only one selected
+ if (keyWordsList.getSelectionCount() == 1) {
+ int index = keyWordsList.getSelectionIndex();
+ String keyword = keyWordsList.getItem(index);
+ if (bug.getAttribute("Keywords").getNewValue().equals(keyword))
+ keyWordsList.deselectAll();
+ }
+
+ for (int i = 0; i < keyWordsList.getSelectionCount(); i++) {
+ keywords.append(sel[i]);
+ if (i != keyWordsList.getSelectionCount() - 1) {
+ keywords.append(",");
+ }
+ }
+ bug.getAttribute("Keywords").setNewValue(keywords.toString());
+
+ // update the keywords text field
+ keywordsText.setText(keywords.toString());
+ }
+
+ /*
+ * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ public void widgetDefaultSelected(SelectionEvent arg0) {
+ // no need to listen to this
+ }
+
+ }
+
+ /**
+ * A listener for selection of the description field.
+ */
+ protected class DescriptionListener implements Listener {
+ public void handleEvent(Event event) {
+ fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
+ new BugzillaReportSelection(bug.getId(), bug.getRepositoryUrl(), LABEL_SECTION_DESCRIPTION, true,
+ bug.getSummary()))));
+ }
+ }
+
+ /**
+ * A listener for selection of a comment.
+ */
+ protected class CommentListener implements Listener {
+
+ /** The comment that this listener is for. */
+ private Comment comment;
+
+ /**
+ * Creates a new <code>CommentListener</code>.
+ *
+ * @param comment
+ * The comment that this listener is for.
+ */
+ public CommentListener(Comment comment) {
+ this.comment = comment;
+ }
+
+ public void handleEvent(Event event) {
+ fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
+ new BugzillaReportSelection(bug.getId(), bug.getRepositoryUrl(), comment.getCreated().toString(),
+ comment, bug.getSummary()))));
+ }
+ }
+
+ /**
+ * A listener for selection of the textbox where a new comment is entered
+ * in.
+ */
+ protected class NewCommentListener implements Listener {
+ public void handleEvent(Event event) {
+ fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
+ new BugzillaReportSelection(bug.getId(), bug.getRepositoryUrl(), "New Comment", false, bug
+ .getSummary()))));
+ }
+ }
+
+ /**
+ * Class to handle the selection change of the radio buttons.
+ */
+ protected class RadioButtonListener implements SelectionListener, ModifyListener {
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ Button selected = null;
+ for (int i = 0; i < radios.length; i++) {
+ if (radios[i].getSelection())
+ selected = radios[i];
+ }
+ // determine the operation to do to the bug
+ for (int i = 0; i < radios.length; i++) {
+ if (radios[i] != e.widget && radios[i] != selected) {
+ radios[i].setSelection(false);
+ }
+
+ if (e.widget == radios[i]) {
+ Operation o = bug.getOperation(radios[i].getText());
+ bug.setSelectedOperation(o);
+ ExistingBugEditor.this.changeDirtyStatus(true);
+ } else if (e.widget == radioOptions[i]) {
+ Operation o = bug.getOperation(radios[i].getText());
+ o.setOptionSelection(((CCombo) radioOptions[i]).getItem(((CCombo) radioOptions[i])
+ .getSelectionIndex()));
+
+ if (bug.getSelectedOperation() != null)
+ bug.getSelectedOperation().setChecked(false);
+ o.setChecked(true);
+
+ bug.setSelectedOperation(o);
+ radios[i].setSelection(true);
+ if (selected != null && selected != radios[i]) {
+ selected.setSelection(false);
+ }
+ ExistingBugEditor.this.changeDirtyStatus(true);
+ }
+ }
+ validateInput();
+ }
+
+ public void modifyText(ModifyEvent e) {
+ Button selected = null;
+ for (int i = 0; i < radios.length; i++) {
+ if (radios[i].getSelection())
+ selected = radios[i];
+ }
+ // determine the operation to do to the bug
+ for (int i = 0; i < radios.length; i++) {
+ if (radios[i] != e.widget && radios[i] != selected) {
+ radios[i].setSelection(false);
+ }
+
+ if (e.widget == radios[i]) {
+ Operation o = bug.getOperation(radios[i].getText());
+ bug.setSelectedOperation(o);
+ ExistingBugEditor.this.changeDirtyStatus(true);
+ } else if (e.widget == radioOptions[i]) {
+ Operation o = bug.getOperation(radios[i].getText());
+ o.setInputValue(((Text) radioOptions[i]).getText());
+
+ if (bug.getSelectedOperation() != null)
+ bug.getSelectedOperation().setChecked(false);
+ o.setChecked(true);
+
+ bug.setSelectedOperation(o);
+ radios[i].setSelection(true);
+ if (selected != null && selected != radios[i]) {
+ selected.setSelection(false);
+ }
+ ExistingBugEditor.this.changeDirtyStatus(true);
+ }
+ }
+ validateInput();
+ }
+ }
+
+ private void validateInput() {
+ Operation o = bug.getSelectedOperation();
+ if (o != null && o.getKnobName().compareTo("resolve") == 0
+ && (addCommentsText.getText() == null || addCommentsText.getText().equals(""))) {
+ submitButton.setEnabled(false);
+ } else {
+ submitButton.setEnabled(true);
+ }
+ }
+
+ @Override
+ public void handleSummaryEvent() {
+ String sel = summaryText.getText();
+ Attribute a = getBug().getAttribute(ATTR_SUMMARY);
+ if (!(a.getNewValue().equals(sel))) {
+ a.setNewValue(sel);
+ changeDirtyStatus(true);
+ }
+ }
+
+ // TODO used for spell checking. Add back when we want to support this
+ // protected Button checkSpellingButton;
+ //
+ // private void checkSpelling() {
+ // SpellingContext context= new SpellingContext();
+ // context.setContentType(Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT));
+ // IDocument document = new Document(addCommentsTextBox.getText());
+ // ISpellingProblemCollector collector= new
+ // SpellingProblemCollector(document);
+ // EditorsUI.getSpellingService().check(document, context, collector, new
+ // NullProgressMonitor());
+ // }
+ //
+ // private class SpellingProblemCollector implements
+ // ISpellingProblemCollector {
+ //
+ // private IDocument document;
+ //
+ // private SpellingDialog spellingDialog;
+ //
+ // public SpellingProblemCollector(IDocument document){
+ // this.document = document;
+ // spellingDialog = new
+ // SpellingDialog(Display.getCurrent().getActiveShell(), "Spell Checking",
+ // document);
+ // }
+ //
+ // /*
+ // * @see
+ // org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#accept(org.eclipse.ui.texteditor.spelling.SpellingProblem)
+ // */
+ // public void accept(SpellingProblem problem) {
+ // try {
+ // int line= document.getLineOfOffset(problem.getOffset()) + 1;
+ // String word= document.get(problem.getOffset(), problem.getLength());
+ //
+ // spellingDialog.open(word, problem.getProposals());
+ //
+ // } catch (BadLocationException x) {
+ // // drop this SpellingProblem
+ // }
+ // }
+ //
+ // /*
+ // * @see
+ // org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#beginCollecting()
+ // */
+ // public void beginCollecting() {
+ //
+ // }
+ //
+ // /*
+ // * @see
+ // org.eclipse.ui.texteditor.spelling.ISpellingProblemCollector#endCollecting()
+ // */
+ // public void endCollecting() {
+ // MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
+ // "Spell Checking Finished", "The spell check has finished");
+ // }
+ // }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/RepositoryTextViewer.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/RepositoryTextViewer.java
new file mode 100644
index 000000000..651d856aa
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/RepositoryTextViewer.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.editor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.MultiLineRule;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.jface.text.rules.SingleLineRule;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+import org.eclipse.ui.internal.editors.text.URLHyperlinkDetector;
+
+/**
+ * @author Rob Elves
+ */
+public class RepositoryTextViewer extends SourceViewer {
+
+ private TaskRepository repository;
+
+ public RepositoryTextViewer(TaskRepository repository, Composite composite, int style) {
+ super(composite, null, style);
+ this.configure(new RepositoryViewerConfig());
+ this.repository = repository;
+ }
+
+ public TaskRepository getRepository() {
+ return repository;
+ }
+
+ public void setRepository(TaskRepository repository) {
+ this.repository = repository;
+ }
+
+ class RepositoryViewerConfig extends TextSourceViewerConfiguration {
+
+ private RepositoryTextScanner scanner = null;
+
+ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
+ PresentationReconciler reconciler = new PresentationReconciler();
+ reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+
+ DefaultDamagerRepairer dr = new DefaultDamagerRepairer(getDefaultScanner());
+ reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
+
+ return reconciler;
+ }
+
+ private RepositoryTextScanner getDefaultScanner() {
+ if (scanner == null) {
+ scanner = new RepositoryTextScanner();
+ }
+ return scanner;
+ }
+
+ public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
+ URLHyperlinkDetector hyperlinkDetector = new URLHyperlinkDetector();
+ List<IHyperlinkDetector> detectors = new ArrayList<IHyperlinkDetector>();
+ detectors.add(hyperlinkDetector);
+ detectors.addAll(Arrays.asList(MylarTaskListPlugin.getDefault().getTaskHyperlinkDetectors()));
+ return detectors.toArray(new IHyperlinkDetector[detectors.size()]);
+// return MylarTaskListPlugin.getDefault().getTaskHyperlinkDetectors();
+ }
+
+ public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) {
+ return new DefaultHyperlinkPresenter(new RGB(0, 0, 200));
+ }
+
+ public int getHyperlinkStateMask(ISourceViewer sourceViewer) {
+ return SWT.NONE;
+ }
+ }
+
+ class RepositoryTextScanner extends RuleBasedScanner {
+ private Color URL_COLOR = new Color(Display.getCurrent(), new RGB(0, 0, 200));
+
+ public RepositoryTextScanner() {
+ IToken bugToken = new Token(new TextAttribute(URL_COLOR));
+ IRule[] rules = new IRule[7];
+ rules[0] = (new SingleLineRule("http://", " ", bugToken));
+ rules[1] = (new SingleLineRule("https://", " ", bugToken));
+ rules[2] = (new MultiLineRule("bug#", " ", bugToken));
+ rules[3] = (new MultiLineRule("bug #", " ", bugToken));
+ rules[4] = (new SingleLineRule("bug #", "\n", bugToken));
+ rules[5] = (new SingleLineRule("http://", "\n", bugToken));
+ rules[6] = (new SingleLineRule("https://", "\n", bugToken));
+// rules[7] = (new MultiLineRule(" bug ", " ", bugToken));
+// rules[8] = (new SingleLineRule(" at ", ")", bugToken));
+ setRules(rules);
+ }
+
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/search/BugzillaSearchPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/search/BugzillaSearchPage.java
new file mode 100644
index 000000000..64dca1ce5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/search/BugzillaSearchPage.java
@@ -0,0 +1,1602 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui.search;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.search.BugzillaSearchOperation;
+import org.eclipse.mylar.internal.bugzilla.core.search.BugzillaSearchQuery;
+import org.eclipse.mylar.internal.bugzilla.core.search.BugzillaSearchResultCollector;
+import org.eclipse.mylar.internal.bugzilla.core.search.IBugzillaSearchOperation;
+import org.eclipse.mylar.internal.bugzilla.core.search.IBugzillaSearchResultCollector;
+import org.eclipse.mylar.internal.bugzilla.ui.BugzillaUITools;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.AbstractBugzillaQueryPage;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaRepositoryQuery;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.mylar.provisional.tasklist.TaskRepositoryManager;
+import org.eclipse.search.ui.ISearchPage;
+import org.eclipse.search.ui.ISearchPageContainer;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+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.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.internal.help.WorkbenchHelpSystem;
+
+/**
+ * Bugzilla search page
+ *
+ * @author Mik Kersten (hardening of prototype)
+ */
+public class BugzillaSearchPage extends AbstractBugzillaQueryPage implements ISearchPage, Listener {
+
+ private static final String MAX_HITS_GREATER = "Max hits shown must be greater than 0 or enter -1 for all results found.";
+
+ private static final String NUM_DAYS_POSITIVE = "Number of days must be a positive integer. ";
+
+ private static final String TITLE = "New Bugzilla Query";
+
+ private static final String DESCRIPTION = "Enter query parameters. If attributes are blank or stale press the Update button.";
+
+ private static final String TITLE_BUGZILLA_QUERY = "Bugzilla Query";
+
+ private static final String MAX_HITS = "100";
+
+ private static final int HEIGHT_ATTRIBUTE_COMBO = 60;
+
+ private TaskRepository repository = null;
+
+ protected Combo summaryPattern = null;
+
+ protected Combo repositoryCombo = null;
+
+ private static ArrayList<BugzillaSearchData> previousSummaryPatterns = new ArrayList<BugzillaSearchData>(20);
+
+ private static ArrayList<BugzillaSearchData> previousEmailPatterns = new ArrayList<BugzillaSearchData>(20);
+
+ private static ArrayList<BugzillaSearchData> previousCommentPatterns = new ArrayList<BugzillaSearchData>(20);
+
+ protected ISearchPageContainer scontainer = null;
+
+ private boolean firstTime = true;
+
+ private IDialogSettings fDialogSettings;
+
+ protected Text maxHitsText;
+
+ private static final String[] patternOperationText = { "all words", "any word", "regexp" };
+
+ private static final String[] patternOperationValues = { "allwordssubstr", "anywordssubstr", "regexp" };
+
+ private static final String[] emailOperationText = { "substring", "exact", "regexp" };
+
+ private static final String[] emailOperationValues = { "substring", "exact", "regexp" };
+
+ private static final String[] emailRoleValues = { "emailassigned_to1", "emailreporter1", "emailcc1",
+ "emaillongdesc1" };
+
+ protected IPreferenceStore prefs = BugzillaPlugin.getDefault().getPreferenceStore();
+
+ protected String maxHits;
+
+ private BugzillaRepositoryQuery originalQuery = null;
+
+ // private TaskRepository selectedRepository = null;
+
+ private static class BugzillaSearchData {
+ /** Pattern to match on */
+ String pattern;
+
+ /** Pattern matching criterion */
+ int operation;
+
+ BugzillaSearchData(String pattern, int operation) {
+ this.pattern = pattern;
+ this.operation = operation;
+ }
+ }
+
+ public BugzillaSearchPage() {
+ super(TITLE_BUGZILLA_QUERY);
+ setTitle(TITLE);
+ setDescription(DESCRIPTION);
+ setPageComplete(false);
+ }
+
+ public BugzillaSearchPage(TaskRepository repository) {
+ super(TITLE_BUGZILLA_QUERY);
+ setTitle(TITLE);
+ setDescription(DESCRIPTION);
+ this.repository = repository;
+ setPageComplete(false);
+ }
+
+ public BugzillaSearchPage(TaskRepository repository, BugzillaRepositoryQuery origQuery) {
+ super(TITLE_BUGZILLA_QUERY, origQuery.getDescription());
+ originalQuery = origQuery;
+ this.repository = repository;
+ setTitle(TITLE);
+ setDescription(DESCRIPTION);
+ setPageComplete(false);
+ }
+
+ public void createControl(Composite parent) {
+ readConfiguration();
+
+ Composite control = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ control.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ control.setLayoutData(gd);
+
+ if (scontainer == null) {
+ // Not presenting in search pane so add parent's content
+ super.createControl(control);
+ } else {
+ // if (repository == null) {
+ // search pane so add repository selection
+ createRepositoryGroup(control);
+ }
+ createSearchGroup(control);
+ createOptionsGroup(control);
+
+ createEmail(control);
+ createLastDays(control);
+
+ // createSaveQuery(control);
+ // createMaxHits(control);
+ input = new SavedQueryFile(BugzillaPlugin.getDefault().getStateLocation().toString(), "/queries");
+ // createUpdate(control);
+// if (originalQuery != null) {
+// try {
+// updateDefaults(originalQuery.getQueryUrl(), String.valueOf(originalQuery.getMaxHits()));
+// } catch (UnsupportedEncodingException e) {
+// // ignore
+// }
+// }
+ setControl(control);
+ WorkbenchHelpSystem.getInstance().setHelp(control, IBugzillaConstants.SEARCH_PAGE_CONTEXT);
+ }
+
+ private void createRepositoryGroup(Composite control) {
+ Group group = new Group(control, SWT.NONE);
+ group.setText("Repository");
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ group.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ group.setLayoutData(gd);
+
+ repositoryCombo = new Combo(group, SWT.SINGLE | SWT.BORDER);
+ repositoryCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String repositoryUrl = repositoryCombo.getItem(repositoryCombo.getSelectionIndex());
+ repository = MylarTaskListPlugin.getRepositoryManager().getRepository(BugzillaPlugin.REPOSITORY_KIND,
+ repositoryUrl);
+ updateAttributesFromRepository(repositoryUrl, false);
+ }
+ });
+ gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ repositoryCombo.setLayoutData(gd);
+ }
+
+ private void createSearchGroup(Composite control) {
+ Group group = new Group(control, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ group.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 5;
+ group.setLayoutData(gd);
+
+ createTextSearchComposite(group);
+ createComment(group);
+ }
+
+ protected Control createTextSearchComposite(Composite control) {
+ GridData gd;
+ Label label;
+
+ Composite group = new Composite(control, SWT.NONE);
+ GridLayout 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);
+
+ // Info text
+ label = new Label(group, SWT.LEFT);
+ label.setText("Summary/id contains: ");
+ gd = new GridData(GridData.BEGINNING);
+ gd.horizontalSpan = 1;
+ label.setLayoutData(gd);
+
+ // Pattern combo
+ summaryPattern = new Combo(group, SWT.SINGLE | SWT.BORDER);
+ summaryPattern.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ if (scontainer != null) {
+ scontainer.setPerformActionEnabled(canQuery());
+ }
+ }
+ });
+ summaryPattern.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ handleWidgetSelected(summaryPattern, summaryOperation, previousSummaryPatterns);
+ }
+ });
+ gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ summaryPattern.setLayoutData(gd);
+
+ summaryOperation = new Combo(group, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
+ summaryOperation.setItems(patternOperationText);
+ summaryOperation.setText(patternOperationText[0]);
+ summaryOperation.select(0);
+
+ return group;
+ }
+
+ private Control createComment(Composite control) {
+ GridData gd;
+ Label label;
+
+ Composite group = new Composite(control, SWT.NONE);
+ GridLayout 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);
+
+ // Info text
+ label = new Label(group, SWT.LEFT);
+ label.setText("Comment contains: ");
+ gd = new GridData(GridData.BEGINNING);
+ label.setLayoutData(gd);
+
+ // Comment pattern combo
+ commentPattern = new Combo(group, SWT.SINGLE | SWT.BORDER);
+ commentPattern.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ if (scontainer != null) {
+ scontainer.setPerformActionEnabled(canQuery());
+ }
+ }
+ });
+ commentPattern.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ handleWidgetSelected(commentPattern, commentOperation, previousCommentPatterns);
+ }
+ });
+ gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ commentPattern.setLayoutData(gd);
+
+ commentOperation = new Combo(group, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
+ commentOperation.setItems(patternOperationText);
+ commentOperation.setText(patternOperationText[0]);
+ commentOperation.select(0);
+
+ return group;
+ }
+
+ protected Control createOptionsGroup(Composite control) {
+ Group group = new Group(control, SWT.NONE);
+ // group.setText("Bug Attributes");
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ group.setLayout(layout);
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.horizontalSpan = 5;
+ group.setLayoutData(gd);
+
+ createProductAttributes(group);
+ createLists(group);
+ createUpdate(group);
+
+ return group;
+ }
+
+ /**
+ * Creates the area for selection on product/component/version.
+ */
+ protected Control createProductAttributes(Composite control) {
+
+ GridData gd;
+ GridLayout layout;
+
+ // Search expression
+ Composite group = new Composite(control, SWT.NONE);
+ layout = new GridLayout();
+ layout.numColumns = 4;
+ group.setLayout(layout);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.horizontalSpan = 5;
+ group.setLayoutData(gd);
+
+ // Labels
+ Label label = new Label(group, SWT.LEFT);
+ label.setText("Product");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Component");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Version");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Milestone");
+
+ // Lists
+ product = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = HEIGHT_ATTRIBUTE_COMBO;
+ product.setLayoutData(gd);
+
+ component = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = HEIGHT_ATTRIBUTE_COMBO;
+ component.setLayoutData(gd);
+
+ version = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = HEIGHT_ATTRIBUTE_COMBO;
+ version.setLayoutData(gd);
+
+ target = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = HEIGHT_ATTRIBUTE_COMBO;
+ target.setLayoutData(gd);
+
+ return group;
+ }
+
+ /**
+ * Creates the area for selection of bug attributes (status, etc.)
+ */
+ protected Control createLists(Composite control) {
+ GridData gd;
+ GridLayout layout;
+
+ // Search expression
+ Composite group = new Composite(control, SWT.NONE);
+ layout = new GridLayout();
+ layout.numColumns = 6;
+ group.setLayout(layout);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.horizontalSpan = 5;
+ group.setLayoutData(gd);
+
+ // Labels
+ Label label = new Label(group, SWT.LEFT);
+ label.setText("Status");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Resolution");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Severity");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Priority");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("Hardware");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText("OS");
+
+ // Lists
+ status = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 40;
+ status.setLayoutData(gd);
+
+ resolution = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 40;
+ resolution.setLayoutData(gd);
+
+ severity = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 40;
+ severity.setLayoutData(gd);
+
+ priority = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 40;
+ priority.setLayoutData(gd);
+
+ hardware = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 40;
+ hardware.setLayoutData(gd);
+
+ os = new List(group, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 40;
+ os.setLayoutData(gd);
+
+ return group;
+ }
+
+ protected Text daysText;
+
+ protected Control createLastDays(Composite control) {
+ GridLayout layout;
+ GridData gd;
+
+ Group group = new Group(control, SWT.NONE);
+ layout = new GridLayout(6, 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);
+
+ Label label = new Label(group, SWT.LEFT);
+ label.setText("Only bugs changed in the last ");
+
+ // operation combo
+ daysText = new Text(group, SWT.BORDER);
+ daysText.setTextLimit(5);
+ GridData daysLayoutData = new GridData();
+ daysLayoutData.widthHint = 30;
+ daysText.setLayoutData(daysLayoutData);
+ daysText.addListener(SWT.Modify, this);
+ // daysText.addFocusListener(new FocusListener() {
+ //
+ // public void focusGained(FocusEvent e) {
+ // // ignore
+ //
+ // }
+ //
+ // public void focusLost(FocusEvent e) {
+ // String days = daysText.getText();
+ // if (days.length() == 0)
+ // return;
+ // try {
+ // if (Integer.parseInt(days) < 0) {
+ // daysText.setText("");
+ // }
+ // } catch (NumberFormatException ex) {
+ // daysText.setText("");
+ // }
+ // }
+ // });
+
+ // daysText.addModifyListener(new ModifyListener() {
+ // public void modifyText(ModifyEvent e) {
+ // String days = daysText.getText();
+ // if (days.length() == 0)
+ // return;
+ // for (int i = days.length() - 1; i >= 0; i--) {
+ // try {
+ // if (days.equals("") || Integer.parseInt(days) > -1) {
+ // if (i == days.length() - 1)
+ // return;
+ // else
+ // break;
+ // }
+ // } catch (NumberFormatException ex) {
+ // days = days.substring(0, i);
+ // }
+ // }
+ // daysText.setText(days);
+ // }
+ // });
+ label = new Label(group, SWT.LEFT);
+ label.setText(" days.");
+
+ label = new Label(group, SWT.LEFT);
+ label.setText(" Show a maximum of ");
+
+ // operation combo
+ maxHitsText = new Text(group, SWT.BORDER);
+ maxHitsText.setTextLimit(6);
+ maxHitsText.addListener(SWT.Modify, this);
+
+ // maxHitsText.addFocusListener(new FocusListener() {
+ //
+ // public void focusGained(FocusEvent e) {
+ // // ignore
+ //
+ // }
+ //
+ // public void focusLost(FocusEvent e) {
+ // String maxHitss = maxHitsText.getText();
+ // if (maxHitss.length() == 0)
+ // return;
+ //
+ // try {
+ // if (Integer.parseInt(maxHitss) < 0) {
+ // maxHitsText.setText(MAX_HITS);
+ //
+ // }
+ // } catch (NumberFormatException ex) {
+ // maxHitsText.setText(MAX_HITS);
+ // }
+ // }
+ // });
+
+ // maxHitsText.addModifyListener(new ModifyListener() {
+ // public void modifyText(ModifyEvent e) {
+ // String maxHitss = maxHitsText.getText();
+ // if (maxHitss.length() == 0)
+ // return;
+ // for (int i = maxHitss.length() - 1; i >= 0; i--) {
+ // try {
+ // if (maxHitss.equals("") || Integer.parseInt(maxHitss) > -1) {
+ // if (i == maxHitss.length() - 1) {
+ // maxHits = maxHitss;
+ // return;
+ // } else {
+ // break;
+ // }
+ // }
+ // } catch (NumberFormatException ex) {
+ // maxHitss = maxHitss.substring(0, i);
+ // }
+ // }
+ //
+ // BugzillaSearchPage.this.maxHits = maxHitss;
+ // }
+ // });
+ gd = new GridData();
+ gd.widthHint = 30;
+ maxHitsText.setLayoutData(gd);
+ label = new Label(group, SWT.LEFT);
+ label.setText(" hits.");
+
+ maxHits = MAX_HITS;
+ maxHitsText.setText(maxHits);
+
+ return group;
+ }
+
+ // protected Control createMaxHits(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);
+ //
+ // Label label = new Label(group, SWT.LEFT);
+ // label.setText("Show a maximum of ");
+ //
+ // // operation combo
+ // maxHitsText = new Text(group, SWT.BORDER);
+ // maxHitsText.setTextLimit(5);
+ // maxHitsText.addModifyListener(new ModifyListener() {
+ // public void modifyText(ModifyEvent e) {
+ // String maxHitss = maxHitsText.getText();
+ // if (maxHitss.length() == 0)
+ // return;
+ // for (int i = maxHitss.length() - 1; i >= 0; i--) {
+ // try {
+ // if (maxHitss.equals("") || Integer.parseInt(maxHitss) > -1) {
+ // if (i == maxHitss.length() - 1) {
+ // maxHits = maxHitss;
+ // return;
+ // } else {
+ // break;
+ // }
+ // }
+ // } catch (NumberFormatException ex) {
+ // maxHitss = maxHitss.substring(0, i);
+ // }
+ // }
+ //
+ // BugzillaSearchPage.this.maxHits = maxHitss;
+ // }
+ // });
+ // gd = new GridData();
+ // gd.widthHint = 20;
+ // maxHitsText.setLayoutData(gd);
+ // label = new Label(group, SWT.LEFT);
+ // label.setText(" Hits. (-1 means all hits are returned)");
+ //
+ // maxHits = "100";
+ // maxHitsText.setText(maxHits);
+ //
+ // return group;
+ // }
+
+ public String getMaxHits() {
+ return maxHitsText.getText();
+ }
+
+ private static final String[] emailText = { "bug owner", "reporter", "CC list", "commenter" };
+
+ protected Control createEmail(Composite control) {
+ GridLayout layout;
+ GridData gd;
+
+ Group group = new Group(control, SWT.NONE);
+ layout = new GridLayout(7, 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);
+
+ Label label = new Label(group, SWT.LEFT);
+ label.setText("Email: ");
+
+ // pattern combo
+ emailPattern = new Combo(group, SWT.SINGLE | SWT.BORDER);
+ emailPattern.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ if (scontainer != null) {
+ scontainer.setPerformActionEnabled(canQuery());
+ }
+ }
+ });
+ emailPattern.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ handleWidgetSelected(emailPattern, emailOperation, previousEmailPatterns);
+ }
+ });
+ gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ emailPattern.setLayoutData(gd);
+
+ // operation combo
+ emailOperation = new Combo(group, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER);
+ emailOperation.setItems(emailOperationText);
+ emailOperation.setText(emailOperationText[0]);
+ emailOperation.select(0);
+
+ // Composite buttons = new Composite(group, SWT.NONE);
+ // layout = new GridLayout(4, false);
+ // buttons.setLayout(layout);
+ // buttons.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ // gd = new GridData(GridData.BEGINNING);
+ // gd.horizontalSpan = 3;
+ // buttons.setLayoutData(gd);
+
+ emailButton = new Button[emailText.length];
+ for (int i = 0; i < emailButton.length; i++) {
+ Button button = new Button(group, SWT.CHECK);
+ button.setText(emailText[i]);
+ emailButton[i] = button;
+ }
+
+ return group;
+ }
+
+ /**
+ * Creates the buttons for remembering a query and accessing previously
+ * saved queries.
+ */
+ 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...");
+ // final BugzillaSearchPage bsp = this;
+ // loadButton.addSelectionListener(new SelectionAdapter() {
+ //
+ // @Override
+ // public void widgetSelected(SelectionEvent event) {
+ // GetQueryDialog qd = new GetQueryDialog(getShell(), "Saved Queries",
+ // input);
+ // if (qd.open() == InputDialog.OK) {
+ // selIndex = qd.getSelected();
+ // if (selIndex != -1) {
+ // rememberedQuery = true;
+ // performAction();
+ // bsp.getShell().close();
+ // }
+ // }
+ // }
+ // });
+ // 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;
+ }
+
+ public static SavedQueryFile getInput() {
+ return input;
+ }
+
+ protected Control createUpdate(final Composite control) {
+ GridData gd;
+ // Label label;
+
+ Composite group = new Composite(control, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ group.setLayout(layout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ gd = new GridData(GridData.BEGINNING);
+ gd.horizontalSpan = 2;
+ group.setLayoutData(gd);
+
+ // Info text
+ // label = new Label(group, SWT.LEFT);
+ // label.setText("Update search options from server:");
+ // gd = new GridData(GridData.BEGINNING);
+ // label.setLayoutData(gd);
+
+ updateButton = new Button(group, SWT.PUSH);
+ updateButton.setText("Update Attributes from Repository");
+
+ updateButton.setLayoutData(new GridData());
+
+ updateButton.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ if (repository != null) {
+ updateAttributesFromRepository(repository.getUrl(), true);
+ } else {
+ MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
+ IBugzillaConstants.TITLE_MESSAGE_DIALOG, TaskRepositoryManager.MESSAGE_NO_REPOSITORY);
+ }
+ }
+ });
+
+ return group;
+ }
+
+ private void handleWidgetSelected(Combo widget, Combo operation, ArrayList<BugzillaSearchData> history) {
+ if (widget.getSelectionIndex() < 0)
+ return;
+ int index = history.size() - 1 - widget.getSelectionIndex();
+ BugzillaSearchData patternData = history.get(index);
+ if (patternData == null || !widget.getText().equals(patternData.pattern))
+ return;
+ widget.setText(patternData.pattern);
+ operation.setText(operation.getItem(patternData.operation));
+ }
+
+ public boolean performAction() {
+ if (repository == null) {
+ MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
+ IBugzillaConstants.TITLE_MESSAGE_DIALOG, TaskRepositoryManager.MESSAGE_NO_REPOSITORY);
+ return false;
+ }
+
+ getPatternData(summaryPattern, summaryOperation, previousSummaryPatterns);
+ getPatternData(commentPattern, commentOperation, previousCommentPatterns);
+ getPatternData(this.emailPattern, emailOperation, previousEmailPatterns);
+
+ String summaryText;
+ String queryUrl;
+ if (rememberedQuery == true) {
+ queryUrl = getQueryURL(repository, new StringBuffer(input.getQueryParameters(selIndex)));
+ summaryText = input.getSummaryText(selIndex);
+ } else {
+ try {
+ StringBuffer params = getQueryParameters();
+ queryUrl = getQueryURL(repository, params);
+ summaryText = summaryPattern.getText();
+ } catch (UnsupportedEncodingException e) {
+ /*
+ * These statements should never be executed. Every
+ * implementation of the Java platform is required to support
+ * the standard charset "UTF-8"
+ */
+ queryUrl = "";
+ summaryText = "";
+ }
+ }
+
+ try {
+ // if the summary contains a single bug id, open the bug directly
+ int id = Integer.parseInt(summaryText);
+ return BugzillaUITools.show(repository.getUrl(), id);
+ } catch (NumberFormatException ignored) {
+ // ignore this since this means that the text is not a bug id
+ }
+
+ // Don't activate the search result view until it is known that the
+ // user is not opening a bug directly -- there is no need to open
+ // the view if no searching is going to take place.
+ NewSearchUI.activateSearchResultView();
+
+ BugzillaPlugin.getDefault().getPreferenceStore().setValue(IBugzillaConstants.MOST_RECENT_QUERY, summaryText);
+
+ IBugzillaSearchResultCollector collector = new BugzillaSearchResultCollector();
+
+ IBugzillaSearchOperation op = new BugzillaSearchOperation(repository, queryUrl, collector, maxHits);
+
+ BugzillaSearchQuery searchQuery = new BugzillaSearchQuery(op);
+ NewSearchUI.runQueryInBackground(searchQuery);
+
+ return true;
+ }
+
+ /**
+ * @see ISearchPage#setContainer(ISearchPageContainer)
+ */
+ public void setContainer(ISearchPageContainer container) {
+ scontainer = container;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible && summaryPattern != null) {
+ if (firstTime) {
+ firstTime = false;
+ // Set item and text here to prevent page from resizing
+ for (String searchPattern : getPreviousPatterns(previousSummaryPatterns)) {
+ summaryPattern.add(searchPattern);
+ }
+ // summaryPattern.setItems(getPreviousPatterns(previousSummaryPatterns));
+ for (String comment : getPreviousPatterns(previousCommentPatterns)) {
+ commentPattern.add(comment);
+ }
+ // commentPattern.setItems(getPreviousPatterns(previousCommentPatterns));
+ for (String email : getPreviousPatterns(previousEmailPatterns)) {
+ emailPattern.add(email);
+ }
+ // emailPattern.setItems(getPreviousPatterns(previousEmailPatterns));
+
+ // TODO: update status, resolution, severity etc if possible...
+
+ if (repository == null) {
+ repository = MylarTaskListPlugin.getRepositoryManager().getDefaultRepository(
+ BugzillaPlugin.REPOSITORY_KIND);
+ }
+ Set<TaskRepository> repositories = MylarTaskListPlugin.getRepositoryManager().getRepositories(
+ BugzillaPlugin.REPOSITORY_KIND);
+ String[] repositoryUrls = new String[repositories.size()];
+ int i = 0;
+ int indexToSelect = 0;
+ for (Iterator<TaskRepository> iter = repositories.iterator(); iter.hasNext();) {
+ TaskRepository currRepsitory = iter.next();
+ // if (i == 0 && repository == null) {
+ // repository = currRepsitory;
+ // indexToSelect = 0;
+ // }
+ if (repository != null && repository.equals(currRepsitory)) {
+ indexToSelect = i;
+ }
+ repositoryUrls[i] = currRepsitory.getUrl();
+ i++;
+ }
+
+ if (repository != null) {
+ updateAttributesFromRepository(repository.getUrl(), false);
+ }
+ if (repositoryCombo != null) {
+ repositoryCombo.setItems(repositoryUrls);
+ if (repositoryUrls.length == 0) {
+ MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
+ IBugzillaConstants.TITLE_MESSAGE_DIALOG, TaskRepositoryManager.MESSAGE_NO_REPOSITORY);
+ } else {
+ repositoryCombo.select(indexToSelect);
+ updateAttributesFromRepository(repositoryCombo.getItem(indexToSelect), false);
+ }
+ }
+ if (originalQuery != null) {
+ try {
+ updateDefaults(originalQuery.getQueryUrl(), String.valueOf(originalQuery.getMaxHits()));
+ } catch (UnsupportedEncodingException e) {
+ // ignore
+ }
+ }
+ }
+ if (scontainer != null) {
+ scontainer.setPerformActionEnabled(canQuery());
+ }
+ summaryPattern.setFocus();
+
+ }
+ super.setVisible(visible);
+ }
+
+ /**
+ * Returns <code>true</code> if at least some parameter is given to query
+ * on.
+ */
+ private boolean canQuery() {
+ return product.getSelectionCount() > 0 || component.getSelectionCount() > 0 || version.getSelectionCount() > 0
+ || target.getSelectionCount() > 0 || status.getSelectionCount() > 0
+ || resolution.getSelectionCount() > 0 || severity.getSelectionCount() > 0
+ || priority.getSelectionCount() > 0 || hardware.getSelectionCount() > 0 || os.getSelectionCount() > 0
+ || summaryPattern.getText().length() > 0 || commentPattern.getText().length() > 0
+ || emailPattern.getText().length() > 0;
+ }
+
+ /**
+ * Return search pattern data and update search history list. An existing
+ * entry will be updated or a new one created.
+ */
+ private BugzillaSearchData getPatternData(Combo widget, Combo operation,
+ ArrayList<BugzillaSearchData> previousSearchQueryData) {
+ String pattern = widget.getText();
+ if (pattern == null || pattern.trim().equals("")) {
+ return null;
+ }
+ BugzillaSearchData match = null;
+ int i = previousSearchQueryData.size() - 1;
+ while (i >= 0) {
+ match = previousSearchQueryData.get(i);
+ if (pattern.equals(match.pattern)) {
+ break;
+ }
+ i--;
+ }
+ if (i >= 0) {
+ match.operation = operation.getSelectionIndex();
+ // remove - will be added last (see below)
+ previousSearchQueryData.remove(match);
+ } else {
+ match = new BugzillaSearchData(widget.getText(), operation.getSelectionIndex());
+ }
+ previousSearchQueryData.add(match);
+ return match;
+ }
+
+ /**
+ * Returns an array of previous summary patterns
+ */
+ private String[] getPreviousPatterns(ArrayList<BugzillaSearchData> patternHistory) {
+ int size = patternHistory.size();
+ String[] patterns = new String[size];
+ for (int i = 0; i < size; i++)
+ patterns[i] = (patternHistory.get(size - 1 - i)).pattern;
+ return patterns;
+ }
+
+ public String getSearchURL(TaskRepository repository) {
+ try {
+ if (rememberedQuery) {
+ return getQueryURL(repository, new StringBuffer(input.getQueryParameters(selIndex)));
+ } else {
+ return getQueryURL(repository, getQueryParameters());
+ }
+ } catch (UnsupportedEncodingException e) {
+ // ignore
+ }
+ return "";
+ }
+
+ protected String getQueryURL(TaskRepository repository, StringBuffer params) {
+ StringBuffer url = new StringBuffer(getQueryURLStart(repository).toString());
+ url.append(params);
+
+ // HACK make sure that the searches come back sorted by priority. This
+ // should be a search opetion though
+ url.append("&order=Importance");
+ return url.toString();
+ }
+
+ /**
+ * Creates the bugzilla query URL start.
+ *
+ * Example: https://bugs.eclipse.org/bugs/buglist.cgi?
+ */
+ private StringBuffer getQueryURLStart(TaskRepository repository) {
+ // StringBuffer sb = new
+ // StringBuffer(BugzillaPlugin.getDefault().getServerName());
+ StringBuffer sb = new StringBuffer(repository.getUrl());
+
+ if (sb.charAt(sb.length() - 1) != '/') {
+ sb.append('/');
+ }
+ sb.append("buglist.cgi?");
+
+ // use the username and password if we have it
+ if (repository.hasCredentials()) {
+ try {
+ sb.append("GoAheadAndLogIn=1&Bugzilla_login="
+ + URLEncoder.encode(repository.getUserName(), BugzillaPlugin.ENCODING_UTF_8)
+ + "&Bugzilla_password="
+ + URLEncoder.encode(repository.getPassword(), BugzillaPlugin.ENCODING_UTF_8) + "&");
+ } catch (UnsupportedEncodingException e) {
+ MylarStatusHandler.fail(e, "unsupported encoding", false);
+ }
+ }
+
+ return sb;
+ }
+
+ /**
+ * Goes through the query form and builds up the query parameters.
+ *
+ * Example: short_desc_type=substring&amp;short_desc=bla&amp; ...
+ *
+ * @throws UnsupportedEncodingException
+ */
+ protected StringBuffer getQueryParameters() throws UnsupportedEncodingException {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("short_desc_type=");
+ sb.append(patternOperationValues[summaryOperation.getSelectionIndex()]);
+
+ sb.append("&short_desc=");
+ sb.append(URLEncoder.encode(summaryPattern.getText(), "UTF-8"));
+
+ int[] selected = product.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&product=");
+ sb.append(URLEncoder.encode(product.getItem(selected[i]), "UTF-8"));
+ }
+
+ selected = component.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&component=");
+ sb.append(URLEncoder.encode(component.getItem(selected[i]), "UTF-8"));
+ }
+
+ selected = version.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&version=");
+ sb.append(URLEncoder.encode(version.getItem(selected[i]), "UTF-8"));
+ }
+
+ selected = target.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&target_milestone=");
+ sb.append(URLEncoder.encode(target.getItem(selected[i]), "UTF-8"));
+ }
+
+ sb.append("&long_desc_type=");
+ sb.append(patternOperationValues[commentOperation.getSelectionIndex()]);
+ sb.append("&long_desc=");
+ sb.append(URLEncoder.encode(commentPattern.getText(), "UTF-8"));
+
+ selected = status.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&bug_status=");
+ sb.append(status.getItem(selected[i]));
+ }
+
+ selected = resolution.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&resolution=");
+ sb.append(resolution.getItem(selected[i]));
+ }
+
+ selected = severity.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&bug_severity=");
+ sb.append(severity.getItem(selected[i]));
+ }
+
+ selected = priority.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&priority=");
+ sb.append(priority.getItem(selected[i]));
+ }
+
+ selected = hardware.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&ref_platform=");
+ sb.append(URLEncoder.encode(hardware.getItem(selected[i]), "UTF-8"));
+ }
+
+ selected = os.getSelectionIndices();
+ for (int i = 0; i < selected.length; i++) {
+ sb.append("&op_sys=");
+ sb.append(URLEncoder.encode(os.getItem(selected[i]), "UTF-8"));
+ }
+
+ if (emailPattern.getText() != null) {
+ for (int i = 0; i < emailButton.length; i++) {
+ if (emailButton[i].getSelection()) {
+ sb.append("&");
+ sb.append(emailRoleValues[i]);
+ sb.append("=1");
+ }
+ }
+ sb.append("&emailtype1=");
+ sb.append(emailOperationValues[emailOperation.getSelectionIndex()]);
+ sb.append("&email1=");
+ sb.append(URLEncoder.encode(emailPattern.getText(), "UTF-8"));
+ }
+
+ if (daysText.getText() != null && !daysText.getText().equals("")) {
+ try {
+ Integer.parseInt(daysText.getText());
+ sb.append("&changedin=");
+ sb.append(URLEncoder.encode(daysText.getText(), "UTF-8"));
+ } catch (NumberFormatException ignored) {
+ // this means that the days is not a number, so don't worry
+ }
+ }
+
+ return sb;
+ }
+
+ // --------------- Configuration handling --------------
+
+ // Dialog store id constants
+ protected final static String PAGE_NAME = "BugzillaSearchPage"; //$NON-NLS-1$
+
+ protected Combo summaryOperation;
+
+ protected List product;
+
+ protected List os;
+
+ protected List hardware;
+
+ protected List priority;
+
+ protected List severity;
+
+ protected List resolution;
+
+ protected List status;
+
+ protected Combo commentOperation;
+
+ protected Combo commentPattern;
+
+ protected List component;
+
+ protected List version;
+
+ protected List target;
+
+ protected Combo emailOperation;
+
+ protected Combo emailPattern;
+
+ protected Button[] emailButton;
+
+ /** File containing saved queries */
+ protected static SavedQueryFile input;
+
+ // /** "Remember query" button */
+ // protected Button saveButton;
+
+ // /** "Saved queries..." button */
+ // protected Button loadButton;
+
+ /** Run a remembered query */
+ protected boolean rememberedQuery = false;
+
+ /** Index of the saved query to run */
+ protected int selIndex;
+
+ protected Button updateButton;
+
+ protected ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(BugzillaPlugin.getDefault()
+ .getWorkbench().getActiveWorkbenchWindow().getShell());
+
+ public IDialogSettings getDialogSettings() {
+ IDialogSettings settings = BugzillaPlugin.getDefault().getDialogSettings();
+ fDialogSettings = settings.getSection(PAGE_NAME);
+ if (fDialogSettings == null)
+ fDialogSettings = settings.addNewSection(PAGE_NAME);
+ return fDialogSettings;
+ }
+
+ /**
+ * Initializes itself from the stored page settings.
+ */
+ private void readConfiguration() {
+ getDialogSettings();
+ }
+
+ private void updateAttributesFromRepository(String repositoryUrl, boolean connect) {
+ monitorDialog.open();
+ IProgressMonitor monitor = monitorDialog.getProgressMonitor();
+ monitor.beginTask("Updating search options...", 55);
+
+ try {
+ // TaskRepository repository =
+ // MylarTaskListPlugin.getRepositoryManager().getDefaultRepository(
+ // BugzillaPlugin.REPOSITORY_KIND);
+ // String repositoryUrl = repository.getUrl();
+ if (connect) {
+ BugzillaRepositoryUtil.updateQueryOptions(repository, monitor);
+ }
+ product.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_PRODUCT, repositoryUrl));
+ monitor.worked(1);
+
+ component.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_COMPONENT,
+ repositoryUrl));
+ monitor.worked(1);
+
+ version.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_VERSION, repositoryUrl));
+ monitor.worked(1);
+
+ target.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_TARGET, repositoryUrl));
+ monitor.worked(1);
+
+ status.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_STATUS, repositoryUrl));
+ monitor.worked(1);
+
+// status.setSelection(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUSE_STATUS_PRESELECTED,
+// repositoryUrl));
+ monitor.worked(1);
+
+ resolution.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_RESOLUTION,
+ repositoryUrl));
+ monitor.worked(1);
+
+ severity
+ .setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_SEVERITY, repositoryUrl));
+ monitor.worked(1);
+
+ priority
+ .setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_PRIORITY, repositoryUrl));
+ monitor.worked(1);
+
+ hardware
+ .setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_HARDWARE, repositoryUrl));
+ monitor.worked(1);
+
+ os.setItems(BugzillaRepositoryUtil.getQueryOptions(IBugzillaConstants.VALUES_OS, repositoryUrl));
+ monitor.worked(1);
+ } catch (LoginException exception) {
+ // we had a problem that seems to have been caused from bad
+ // login info
+ 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(exception);
+ } catch (IOException e) {
+ MessageDialog.openError(null, "Connection Error", e.getMessage()
+ + "\nPlease check your settings in the bugzilla preferences. ");
+ } finally {
+ monitor.done();
+ monitorDialog.close();
+ }
+ }
+
+ public TaskRepository getRepository() {
+ return repository;
+ }
+
+ public void setRepository(TaskRepository repository) {
+ this.repository = repository;
+ }
+
+ public boolean canFlipToNextPage() {
+ // if (getErrorMessage() != null)
+ // return false;
+ //
+ // return true;
+ return false;
+ }
+
+ public void handleEvent(Event event) {
+ String message = null;
+ if (event.widget == daysText) {
+ String days = daysText.getText();
+ if (days.length() > 0) {
+ try {
+ if (Integer.parseInt(days) < 0) {
+ message = NUM_DAYS_POSITIVE + days + " is invalid.";
+ }
+ } catch (NumberFormatException ex) {
+ message = NUM_DAYS_POSITIVE + days + " is invalid.";
+ }
+ }
+ } else if (event.widget == maxHitsText) {
+ String maxHitss = maxHitsText.getText();
+ if (maxHitss.length() == 0) {
+ message = MAX_HITS_GREATER;
+ } else {
+ try {
+ if (Integer.parseInt(maxHitss) < -1 || Integer.parseInt(maxHitss) == 0) {
+ message = MAX_HITS_GREATER;
+ }
+ } catch (NumberFormatException ex) {
+ message = MAX_HITS_GREATER;
+ }
+ }
+ }
+
+ setPageComplete(message == null);
+ setErrorMessage(message);
+ if(getWizard() != null) {
+ getWizard().getContainer().updateButtons();
+ }
+ }
+
+ /**
+ * TODO: get rid of this?
+ */
+ public void updateDefaults(String startingUrl, String maxHits) throws UnsupportedEncodingException {
+ // String serverName = startingUrl.substring(0,
+ // startingUrl.indexOf("?"));
+
+ startingUrl = startingUrl.substring(startingUrl.indexOf("?") + 1);
+ String[] options = startingUrl.split("&");
+ for (String option : options) {
+ String key = option.substring(0, option.indexOf("="));
+ String value = URLDecoder.decode(option.substring(option.indexOf("=") + 1), "UTF-8");
+ if (key == null)
+ continue;
+
+ if (key.equals("short_desc")) {
+ summaryPattern.setText(value);
+ } else if (key.equals("short_desc_type")) {
+ if (value.equals("allwordssubstr"))
+ value = "all words";
+ else if (value.equals("anywordssubstr"))
+ value = "any word";
+ int index = 0;
+ for (String item : summaryOperation.getItems()) {
+ if (item.compareTo(value) == 0)
+ break;
+ index++;
+ }
+ if (index < summaryOperation.getItemCount()) {
+ summaryOperation.select(index);
+ }
+ } else if (key.equals("product")) {
+ String[] sel = product.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ product.setSelection(selList.toArray(sel));
+ } else if (key.equals("component")) {
+ String[] sel = component.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ component.setSelection(selList.toArray(sel));
+ } else if (key.equals("version")) {
+ String[] sel = version.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ version.setSelection(selList.toArray(sel));
+ } else if (key.equals("target_milestone")) { // XXX
+ String[] sel = target.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ target.setSelection(selList.toArray(sel));
+ } else if (key.equals("version")) {
+ String[] sel = version.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ version.setSelection(selList.toArray(sel));
+ } else if (key.equals("long_desc_type")) {
+ if (value.equals("allwordssubstr"))
+ value = "all words";
+ else if (value.equals("anywordssubstr"))
+ value = "any word";
+ int index = 0;
+ for (String item : commentOperation.getItems()) {
+ if (item.compareTo(value) == 0)
+ break;
+ index++;
+ }
+ if (index < commentOperation.getItemCount()) {
+ commentOperation.select(index);
+ }
+ } else if (key.equals("long_desc")) {
+ commentPattern.setText(value);
+ } else if (key.equals("bug_status")) {
+ String[] sel = status.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ status.setSelection(selList.toArray(sel));
+ } else if (key.equals("resolution")) {
+ String[] sel = resolution.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ resolution.setSelection(selList.toArray(sel));
+ } else if (key.equals("bug_severity")) {
+ String[] sel = severity.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ severity.setSelection(selList.toArray(sel));
+ } else if (key.equals("priority")) {
+ String[] sel = priority.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ priority.setSelection(selList.toArray(sel));
+ } else if (key.equals("ref_platform")) {
+ String[] sel = hardware.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ hardware.setSelection(selList.toArray(sel));
+ } else if (key.equals("op_sys")) {
+ String[] sel = os.getSelection();
+ java.util.List<String> selList = Arrays.asList(sel);
+ selList = new ArrayList<String>(selList);
+ selList.add(value);
+ sel = new String[selList.size()];
+ os.setSelection(selList.toArray(sel));
+ } else if (key.equals("emailassigned_to1")) { // HACK: email
+ // buttons
+ // assumed to be
+ // in same
+ // position
+ if (value.equals("1"))
+ emailButton[0].setSelection(true);
+ else
+ emailButton[0].setSelection(false);
+ } else if (key.equals("emailreporter1")) { // HACK: email
+ // buttons assumed
+ // to be in same
+ // position
+ if (value.equals("1"))
+ emailButton[1].setSelection(true);
+ else
+ emailButton[1].setSelection(false);
+ } else if (key.equals("emailcc1")) { // HACK: email buttons
+ // assumed to be in same
+ // position
+ if (value.equals("1"))
+ emailButton[2].setSelection(true);
+ else
+ emailButton[2].setSelection(false);
+ } else if (key.equals("emaillongdesc1")) { // HACK: email
+ // buttons assumed
+ // to be in same
+ // position
+ if (value.equals("1"))
+ emailButton[3].setSelection(true);
+ else
+ emailButton[3].setSelection(false);
+ } else if (key.equals("emailtype1")) {
+ int index = 0;
+ for (String item : emailOperation.getItems()) {
+ if (item.compareTo(value) == 0)
+ break;
+ index++;
+ }
+ if (index < emailOperation.getItemCount()) {
+ emailOperation.select(index);
+ }
+ } else if (key.equals("email1")) {
+ emailPattern.setText(value);
+ } else if (key.equals("changedin")) {
+ daysText.setText(value);
+ }
+ }
+ this.maxHits = maxHits;
+ maxHitsText.setText(maxHits);
+ }
+
+ @Override
+ public BugzillaRepositoryQuery getQuery() {
+ if (originalQuery == null) {
+ try {
+ originalQuery = new BugzillaRepositoryQuery(repository.getUrl(), getQueryURL(repository,
+ getQueryParameters()), getQueryTitle(), getMaxHits(), MylarTaskListPlugin.getTaskListManager()
+ .getTaskList());
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+
+ } else {
+ try {
+ originalQuery.setQueryUrl(getQueryURL(repository, getQueryParameters()));
+ originalQuery.setMaxHits(Integer.parseInt(getMaxHits()));
+
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+ return originalQuery;
+ }
+
+// @Override
+// public boolean isPageComplete() {
+// return super.canFlipToNextPage();
+// }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/AbstractBugzillaQueryPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/AbstractBugzillaQueryPage.java
new file mode 100644
index 000000000..ea68d7634
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/AbstractBugzillaQueryPage.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @author Rob Elves
+ */
+public abstract class AbstractBugzillaQueryPage extends WizardPage {
+
+ private static final String TITLE_QUERY_TITLE = "Query Title";
+
+ private Text title;
+
+ private String titleString = "";
+
+ public AbstractBugzillaQueryPage(String wizardTitle) {
+ this(wizardTitle, "");
+ }
+
+ public AbstractBugzillaQueryPage(String wizardTitle, String queryTitle) {
+ super(wizardTitle);
+ titleString = queryTitle;
+ }
+
+ public void createControl(Composite parent) {
+
+ createTitleGroup(parent);
+
+ }
+
+ private void createTitleGroup(Composite composite) {
+ Group group = new Group(composite, SWT.NONE);
+ group.setText(TITLE_QUERY_TITLE);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ group.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ group.setLayoutData(gd);
+
+ title = new Text(group, SWT.BORDER);
+ gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ title.setLayoutData(gd);
+ title.setText(titleString);
+
+ title.addKeyListener(new KeyListener() {
+
+ public void keyPressed(KeyEvent e) {
+ // ignore
+
+ }
+
+ public void keyReleased(KeyEvent e) {
+ setPageComplete(canFlipToNextPage());
+
+ }
+ });
+ }
+
+ public boolean canFlipToNextPage() {
+ if (getErrorMessage() != null || !isPageComplete())
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ if (title != null && !title.getText().equals("")) {
+ return true;
+ }
+ return false;
+ }
+
+ public String getQueryTitle() {
+ return title.getText();
+ }
+
+ public abstract BugzillaRepositoryQuery getQuery();
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaCustomQueryWizardPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaCustomQueryWizardPage.java
new file mode 100644
index 000000000..e241421b0
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaCustomQueryWizardPage.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @author Rob Elves
+ */
+public class BugzillaCustomQueryWizardPage extends AbstractBugzillaQueryPage {
+
+ private static final String LABEL_CUSTOM_QUERY = "Custom Query";
+
+ private static final String TITLE = "Create query from URL";
+
+ private static final String DESCRIPTION = "Enter the name and URL for the query";
+
+ private Text queryText;
+
+ private Composite composite;
+
+ private BugzillaRepositoryQuery query;
+
+ private TaskRepository repository;
+
+ public BugzillaCustomQueryWizardPage(TaskRepository repository, BugzillaRepositoryQuery query) {
+ super(TITLE, query.getDescription());
+ this.query = query;
+ this.repository = repository;
+ setTitle(LABEL_CUSTOM_QUERY);
+ setDescription(DESCRIPTION);
+ }
+
+ public BugzillaCustomQueryWizardPage(TaskRepository repository) {
+ super(TITLE);
+ this.repository = repository;
+ setTitle(LABEL_CUSTOM_QUERY);
+ setDescription(DESCRIPTION);
+ }
+
+ public void createControl(Composite parent) {
+ composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout());
+
+ super.createControl(composite);
+ createCustomQueryGroup(composite);
+ composite.pack();
+ setControl(composite);
+ }
+
+ private void createCustomQueryGroup(Composite composite) {
+ Group group = new Group(composite, SWT.NONE);
+ group.setText(LABEL_CUSTOM_QUERY);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ group.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ gd.widthHint = 300;
+ group.setLayoutData(gd);
+
+ queryText = new Text(group, SWT.BORDER);
+ gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ queryText.setLayoutData(gd);
+
+ if (query != null) {
+ queryText.setText(query.getQueryUrl());
+ }
+
+ queryText.addKeyListener(new KeyListener() {
+
+ public void keyPressed(KeyEvent e) {
+ // ignore
+
+ }
+
+ public void keyReleased(KeyEvent e) {
+ setPageComplete(canFlipToNextPage());
+
+ }
+ });
+
+ }
+
+ public boolean canFlipToNextPage() {
+ return false;
+ }
+
+// @Override
+// public boolean isPageComplete() {
+// return super.canFlipToNextPage();
+// }
+
+// @Override
+// public IWizardPage getNextPage() {
+// return null;
+// }
+
+ @Override
+ public BugzillaRepositoryQuery getQuery() {
+ if (query == null) {
+ query = new BugzillaRepositoryQuery(repository.getUrl(), queryText.getText(), this.getQueryTitle(), "-1",
+ MylarTaskListPlugin.getTaskListManager().getTaskList());
+ query.setCustomQuery(true);
+ } else {
+ query.setQueryUrl(queryText.getText());
+ }
+ return query;
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaQueryTypeWizardPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaQueryTypeWizardPage.java
new file mode 100644
index 000000000..a6f0d3d6c
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaQueryTypeWizardPage.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.mylar.internal.bugzilla.ui.search.BugzillaSearchPage;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * @author Rob Elves
+ */
+public class BugzillaQueryTypeWizardPage extends WizardPage {
+
+ private static final String BUTTON_LABEL_QUERY = "Create query from URL";
+
+ private static final String BUTTON_LABEL_FORM = "Create query using form";
+
+ private static final String TITLE = "Choose Bugzilla query type";
+
+ private static final String DESCRIPTION = "Select query type below.";
+
+ private Button buttonCustom;
+
+ private Button buttonForm;
+
+ private Composite composite;
+
+ private BugzillaCustomQueryWizardPage customPage;
+
+ private BugzillaSearchPage searchPage;
+
+ public BugzillaQueryTypeWizardPage(TaskRepository repository) {
+ super(TITLE);
+ setTitle(TITLE);
+ setDescription(DESCRIPTION);
+ customPage = new BugzillaCustomQueryWizardPage(repository);
+ searchPage = new BugzillaSearchPage(repository);
+
+
+ }
+
+ public void createControl(Composite parent) {
+ composite = new Composite(parent, SWT.NONE);
+ GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
+ gridData.grabExcessVerticalSpace = false;
+ composite.setLayoutData(gridData);
+ composite.setLayout(new GridLayout(1, false));
+
+ buttonForm = new Button(composite, SWT.RADIO);
+ buttonForm.setText(BUTTON_LABEL_FORM);
+ buttonForm.setSelection(true);
+
+ buttonCustom = new Button(composite, SWT.RADIO);
+ buttonCustom.setText(BUTTON_LABEL_QUERY);
+
+ setPageComplete(true);
+ setControl(composite);
+ }
+
+ @Override
+ public IWizardPage getNextPage() {
+ if(buttonForm.getSelection()) {
+ searchPage.setWizard(this.getWizard());
+ return searchPage;
+ }
+ customPage.setWizard(this.getWizard());
+ return customPage;
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositoryConnector.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositoryConnector.java
new file mode 100644
index 000000000..b9d433633
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositoryConnector.java
@@ -0,0 +1,732 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.window.ApplicationWindow;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.BugzillaRemoteContextDelegate;
+import org.eclipse.mylar.bugzilla.core.Comment;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaException;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaReportSubmitForm;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.PossibleBugzillaFailureException;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants.BugzillaServerVersion;
+import org.eclipse.mylar.internal.bugzilla.core.internal.OfflineReportsFile;
+import org.eclipse.mylar.internal.bugzilla.core.internal.OfflineReportsFile.BugzillaOfflineStatus;
+import org.eclipse.mylar.internal.bugzilla.core.search.BugzillaSearchHit;
+import org.eclipse.mylar.internal.bugzilla.ui.WebBrowserDialog;
+import org.eclipse.mylar.internal.bugzilla.ui.search.BugzillaResultCollector;
+import org.eclipse.mylar.internal.bugzilla.ui.tasklist.BugzillaCategorySearchOperation.ICategorySearchListener;
+import org.eclipse.mylar.internal.bugzilla.ui.wizard.NewBugzillaReportWizard;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.core.util.ZipFileUtil;
+import org.eclipse.mylar.internal.tasklist.ui.views.TaskRepositoriesView;
+import org.eclipse.mylar.internal.tasklist.ui.wizards.AbstractAddExistingTaskWizard;
+import org.eclipse.mylar.internal.tasklist.ui.wizards.AbstractRepositorySettingsPage;
+import org.eclipse.mylar.internal.tasklist.ui.wizards.ExistingTaskWizardPage;
+import org.eclipse.mylar.internal.tasklist.util.TaskDataExportJob;
+import org.eclipse.mylar.provisional.core.MylarPlugin;
+import org.eclipse.mylar.provisional.tasklist.AbstractQueryHit;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryConnector;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryQuery;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask;
+import org.eclipse.mylar.provisional.tasklist.DateRangeContainer;
+import org.eclipse.mylar.provisional.tasklist.IRemoteContextDelegate;
+import org.eclipse.mylar.provisional.tasklist.ITask;
+import org.eclipse.mylar.provisional.tasklist.ITaskActivityListener;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask.RepositoryTaskSyncState;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.progress.IProgressService;
+
+/**
+ * @author Mik Kersten
+ * @author Rob Elves
+ */
+public class BugzillaRepositoryConnector extends AbstractRepositoryConnector {
+
+ private static final String ZIPFILE_EXTENSION = ".zip";
+
+ private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
+
+ private static final String LABEL_JOB_SUBMIT = "Submitting to Bugzilla repository";
+
+ private static final String DESCRIPTION_DEFAULT = "<needs synchronize>";
+
+ private static final String CLIENT_LABEL = "Bugzilla (supports uncustomized 2.18-2.22)";
+
+ private List<String> supportedVersions;
+
+ private OfflineReportsFile offlineReportsFile;
+
+ public BugzillaRepositoryConnector() {
+ super();
+ offlineReportsFile = BugzillaPlugin.getDefault().getOfflineReports();
+ if (!BugzillaPlugin.getDefault().getPreferenceStore().getString(IBugzillaConstants.SERVER_VERSION).equals("")) {
+ MylarTaskListPlugin.getTaskListManager().addActivityListener(new ITaskActivityListener() {
+
+ public void tasklistRead() {
+ String oldVersionSetting = BugzillaPlugin.getDefault().getPreferenceStore().getString(
+ IBugzillaConstants.SERVER_VERSION);
+
+ Set<TaskRepository> existingBugzillaRepositories = MylarTaskListPlugin.getRepositoryManager()
+ .getRepositories(BugzillaPlugin.REPOSITORY_KIND);
+ for (TaskRepository repository : existingBugzillaRepositories) {
+ MylarTaskListPlugin.getRepositoryManager().setVersion(repository, oldVersionSetting);
+ }
+ BugzillaPlugin.getDefault().getPreferenceStore().setValue(IBugzillaConstants.SERVER_VERSION, "");
+ MylarTaskListPlugin.getTaskListManager().removeActivityListener(this);
+ }
+
+ public void taskActivated(ITask task) {
+ // ignore
+ }
+
+ public void tasksActivated(List<ITask> tasks) {
+ // ignore
+ }
+
+ public void taskDeactivated(ITask task) {
+ // ignore
+ }
+
+ public void activityChanged(DateRangeContainer week) {
+ // ignore
+ }
+ });
+ }
+ }
+
+ public String getLabel() {
+ return CLIENT_LABEL;
+ }
+
+ public AbstractRepositorySettingsPage getSettingsPage() {
+ return new BugzillaRepositorySettingsPage(this);
+ }
+
+ public String getRepositoryType() {
+ return BugzillaPlugin.REPOSITORY_KIND;
+ }
+
+ public void saveBugReport(IBugzillaBug bugzillaBug) {
+ String handle = AbstractRepositoryTask.getHandle(bugzillaBug.getRepositoryUrl(), bugzillaBug.getId());
+ ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
+ if (task instanceof BugzillaTask) {
+ BugzillaTask bugzillaTask = (BugzillaTask) task;
+ bugzillaTask.setBugReport((BugReport) bugzillaBug);
+
+ if (bugzillaBug.hasChanges()) {
+ bugzillaTask.setSyncState(RepositoryTaskSyncState.OUTGOING);
+ } else {
+ bugzillaTask.setSyncState(RepositoryTaskSyncState.SYNCHRONIZED);
+ }
+ }
+ saveOffline(bugzillaBug, true);
+
+ }
+
+ private BugReport downloadReport(final BugzillaTask bugzillaTask) {
+ try {
+ return BugzillaRepositoryUtil.getBug(bugzillaTask.getRepositoryUrl(), AbstractRepositoryTask
+ .getTaskIdAsInt(bugzillaTask.getHandleIdentifier()));
+ } catch (final LoginException e) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Report Download Failed",
+ "Ensure proper repository configuration in " + TaskRepositoriesView.NAME + ".");
+ }
+ });
+ } catch (IOException e) {
+ if (PlatformUI.getWorkbench() != null && !PlatformUI.getWorkbench().isClosing()) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ ((ApplicationWindow) PlatformUI.getWorkbench().getActiveWorkbenchWindow())
+ .setStatus("Download of bug: " + bugzillaTask + " failed due to I/O exception");
+ }
+ });
+ }
+ }
+ return null;
+ }
+
+ public ITask createTaskFromExistingId(TaskRepository repository, String id) {
+ int bugId = -1;
+ try {
+ if (id != null) {
+ bugId = Integer.parseInt(id);
+ } else {
+ return null;
+ }
+ } catch (NumberFormatException nfe) {
+ if (!forceSyncExecForTesting) {
+ MessageDialog.openInformation(null, MylarTaskListPlugin.TITLE_DIALOG, "Invalid report id: " + id);
+ }
+ return null;
+ }
+
+ String handle = AbstractRepositoryTask.getHandle(repository.getUrl(), bugId);
+ ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
+
+ if (task == null) {
+ task = new BugzillaTask(handle, DESCRIPTION_DEFAULT, true);
+ MylarTaskListPlugin.getTaskListManager().getTaskList().addTask(task);
+ }
+
+ // MylarTaskListPlugin.BgetTaskListManager().getTaskList().addTaskToArchive(newTask);
+ if (task instanceof AbstractRepositoryTask) {
+ synchronize((AbstractRepositoryTask) task, true, null);
+ }
+ return task;
+ }
+
+ public IWizard getNewQueryWizard(TaskRepository repository) {
+ return new NewBugzillaQueryWizard(repository);
+ }
+
+ public IWizard getEditQueryWizard(TaskRepository repository, AbstractRepositoryQuery query) {
+ if (!(query instanceof BugzillaRepositoryQuery)) {
+ return null;
+ }
+ return new EditBugzillaQueryWizard(repository, (BugzillaRepositoryQuery) query);
+ }
+
+ public IWizard getAddExistingTaskWizard(TaskRepository repository) {
+
+ // TODO create a propper subclass for Bugzilla
+ return new AbstractAddExistingTaskWizard(repository) {
+
+ private ExistingTaskWizardPage page;
+
+ public void addPages() {
+ super.addPages();
+ this.page = new ExistingTaskWizardPage();
+ addPage(page);
+ }
+
+ protected String getTaskId() {
+ return page.getTaskId();
+ }
+ };
+ }
+
+ public void openEditQueryDialog(AbstractRepositoryQuery query) {
+ if (!(query instanceof BugzillaRepositoryQuery)) {
+ return;
+ }
+ // BugzillaRepositoryQuery queryCategory = (BugzillaRepositoryQuery)
+ // query;
+ //
+ // if (queryCategory.isCustomQuery()) {
+ // // BugzillaCustomRepositoryQuery queryCategory =
+ // // (BugzillaCustomRepositoryQuery) query;
+ // BugzillaCustomQueryDialog sqd = new
+ // BugzillaCustomQueryDialog(Display.getCurrent().getActiveShell(),
+ // queryCategory.getQueryUrl(), queryCategory.getDescription(),
+ // queryCategory.getMaxHits() + "");
+ // if (sqd.open() == Dialog.OK) {
+ // MylarTaskListPlugin.getTaskListManager().getTaskList().renameContainer(queryCategory,
+ // sqd.getName());
+ // // queryCategory.setDescription(sqd.getName());
+ // queryCategory.setQueryUrl(sqd.getUrl());
+ // int maxHits = -1;
+ // try {
+ // maxHits = Integer.parseInt(sqd.getMaxHits());
+ // } catch (Exception e) {
+ // }
+ // queryCategory.setMaxHits(maxHits);
+ //
+ // synchronize(queryCategory, null);
+ // }
+ // } else {
+ // // BugzillaRepositoryQuery queryCategory = (BugzillaRepositoryQuery)
+ // // query;
+ // BugzillaQueryDialog queryDialog = new
+ // BugzillaQueryDialog(Display.getCurrent().getActiveShell(),
+ // queryCategory.getRepositoryUrl(), queryCategory.getQueryUrl(),
+ // queryCategory.getDescription(),
+ // queryCategory.getMaxHits() + "");
+ // if (queryDialog.open() == Dialog.OK) {
+ // MylarTaskListPlugin.getTaskListManager().getTaskList().renameContainer(queryCategory,
+ // queryDialog.getName());
+ // // queryCategory.setDescription(queryDialog.getName());
+ // queryCategory.setQueryUrl(queryDialog.getUrl());
+ // queryCategory.setRepositoryUrl(queryDialog.getRepository().getUrl());
+ // int maxHits = -1;
+ // try {
+ // maxHits = Integer.parseInt(queryDialog.getMaxHits());
+ // } catch (Exception e) {
+ // }
+ // queryCategory.setMaxHits(maxHits);
+ //
+ // new SynchronizeReportsAction(queryCategory).run();
+ // }
+ // }
+
+ try {
+ TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(
+ query.getRepositoryKind(), query.getRepositoryUrl());
+ if (repository == null)
+ return;
+
+ IWizard wizard = this.getEditQueryWizard(repository, query);
+
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ if (wizard != null && shell != null && !shell.isDisposed()) {
+ WizardDialog dialog = new WizardDialog(shell, wizard);
+ dialog.create();
+ dialog.setTitle("Edit Bugzilla Query");
+ dialog.setBlockOnOpen(true);
+ if (dialog.open() == Dialog.CANCEL) {
+ dialog.close();
+ return;
+ }
+ }
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, e.getMessage(), true);
+ }
+ }
+
+ private static void offlineStatusChange(IBugzillaBug bug, BugzillaOfflineStatus status, boolean forceSynch) {
+
+ RepositoryTaskSyncState state = null;
+ if (status == BugzillaOfflineStatus.SAVED_WITH_OUTGOING_CHANGES) {
+ state = RepositoryTaskSyncState.OUTGOING;
+ } else if (status == BugzillaOfflineStatus.SAVED) {
+ state = RepositoryTaskSyncState.SYNCHRONIZED;
+ } else if (status == BugzillaOfflineStatus.SAVED_WITH_INCOMMING_CHANGES) {
+ if (forceSynch) {
+ state = RepositoryTaskSyncState.INCOMING;
+ } else {
+ // User opened (forceSynch = false) so no need to denote
+ // incomming
+ state = RepositoryTaskSyncState.SYNCHRONIZED;
+ }
+ } else if (status == BugzillaOfflineStatus.CONFLICT) {
+ state = RepositoryTaskSyncState.CONFLICT;
+ } else if (status == BugzillaOfflineStatus.DELETED) {
+ state = RepositoryTaskSyncState.SYNCHRONIZED;
+ }
+ if (state == null) {
+ // this means that we got a status that we didn't understand
+ return;
+ }
+
+ String handle = AbstractRepositoryTask.getHandle(bug.getRepositoryUrl(), bug.getId());
+ ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
+ if (task != null && task instanceof BugzillaTask) {
+ BugzillaTask bugTask = (BugzillaTask) task;
+ bugTask.setSyncState(state);
+ MylarTaskListPlugin.getTaskListManager().getTaskList().notifyRepositoryInfoChanged(bugTask);
+ }
+ }
+
+ public void submitBugReport(final IBugzillaBug bugReport, final BugzillaReportSubmitForm form,
+ IJobChangeListener listener) {
+
+ if (forceSyncExecForTesting) {
+ internalSubmitBugReport(bugReport, form);
+ } else {
+ // TODO: get rid of this idiom?
+ final WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(final IProgressMonitor monitor) throws CoreException {
+ internalSubmitBugReport(bugReport, form);
+ }
+ };
+
+ Job job = new Job(LABEL_JOB_SUBMIT) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ op.run(monitor);
+ } catch (final Throwable throwable) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ // TODO: clean up exception handling
+ if (throwable.getCause() instanceof BugzillaException) {
+ MessageDialog.openError(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Bugzilla could not post your bug.");
+ } else if (throwable.getCause() instanceof PossibleBugzillaFailureException) {
+ WebBrowserDialog.openAcceptAgreement(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Possible problem posting Bugzilla report.\n\n"
+ + throwable.getCause().getMessage(), form.getError());
+ } else if (throwable.getCause() instanceof LoginException) {
+ MessageDialog.openError(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Bugzilla could not post your bug since your login name or password is incorrect."
+ + " Ensure proper repository configuration in "
+ + TaskRepositoriesView.NAME + ".");
+ } else {
+ MylarStatusHandler.fail(throwable, "could not post bug", false);
+ MessageDialog.openError(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Could not post bug. Check repository credentials and connectivity.\n\n"
+ + throwable);
+ }
+ }
+ });
+ return new Status(Status.INFO, "org.eclipse.mylar.internal.bugzilla.ui", Status.INFO,
+ "Failed to submit bug", throwable);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.addJobChangeListener(listener);
+ job.schedule();
+ }
+ }
+
+ private void internalSubmitBugReport(IBugzillaBug bugReport, BugzillaReportSubmitForm form) {
+ try {
+ form.submitReportToRepository();
+ removeReport(bugReport);
+ String handle = AbstractRepositoryTask.getHandle(bugReport.getRepositoryUrl(), bugReport.getId());
+ // TODO: avoid getting archive tasks?
+ ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
+
+ Set<AbstractRepositoryQuery> queriesWithHandle = MylarTaskListPlugin.getTaskListManager().getTaskList()
+ .getQueriesForHandle(task.getHandleIdentifier());
+ synchronize(queriesWithHandle, null, Job.INTERACTIVE, 0);
+ // for (AbstractRepositoryQuery query : queriesWithHandle) {
+ // synchronize(query, null);
+ // }
+ if (task instanceof AbstractRepositoryTask) {
+ synchronize((AbstractRepositoryTask) task, true, null);
+ }
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Saves the given report to the offlineReportsFile, or, if it already
+ * exists in the file, updates it.
+ *
+ * @param bug
+ * The bug to add/update.
+ * @param saveChosen
+ * This is used to determine a refresh from a user save
+ */
+ public BugzillaOfflineStatus saveOffline(final IBugzillaBug bug, final boolean forceSynch) {
+
+ BugzillaOfflineStatus status = BugzillaOfflineStatus.ERROR;
+
+ if (!forceSyncExecForTesting) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ internalSaveOffline(bug, forceSynch);
+ }
+ });
+ } else {
+ internalSaveOffline(bug, forceSynch);
+ }
+ return status;
+ }
+
+ private void internalSaveOffline(final IBugzillaBug bug, final boolean forceSynch) {
+ // If there is already an offline report for this bug, update the file.
+ if (bug.isSavedOffline()) {
+ offlineReportsFile.update();
+ } else {
+ try {
+ // int index = -1;
+ // // If there is already an offline report with the
+ // same id, don't
+ // // save this report.
+ // if ((index = file.find(bug.getId())) >= 0) {
+ // removeReport(getOfflineBugs().get(index));
+ // // MessageDialog.openInformation(null, "Bug's Id
+ // is already
+ // // used.", "There is already a bug saved offline
+ // with an
+ // // identical id.");
+ // // return;
+ // }
+ BugzillaOfflineStatus offlineStatus = offlineReportsFile.add(bug, false);
+ bug.setOfflineState(true);
+ // saveForced forced to false (hack)
+ offlineStatusChange(bug, offlineStatus, forceSynch);
+
+ } catch (CoreException e) {
+ MylarStatusHandler.fail(e, e.getMessage(), false);
+ }
+ // file.sort(OfflineReportsFile.lastSel);
+ }
+ }
+
+ public static List<IBugzillaBug> getOfflineBugs() {
+ OfflineReportsFile file = BugzillaPlugin.getDefault().getOfflineReports();
+ return file.elements();
+ }
+
+ public static void removeReport(IBugzillaBug bug) {
+ bug.setOfflineState(false);
+ offlineStatusChange(bug, BugzillaOfflineStatus.DELETED, false);
+ ArrayList<IBugzillaBug> bugList = new ArrayList<IBugzillaBug>();
+ bugList.add(bug);
+ BugzillaPlugin.getDefault().getOfflineReports().remove(bugList);
+ }
+
+ @Override
+ public boolean canCreateTaskFromId() {
+ return true;
+ }
+
+ @Override
+ public boolean canCreateNewTask() {
+ return true;
+ }
+
+ @Override
+ public IWizard getNewTaskWizard(TaskRepository taskRepository) {
+ return new NewBugzillaReportWizard(taskRepository);
+ }
+
+ public List<String> getSupportedVersions() {
+ if (supportedVersions == null) {
+ supportedVersions = new ArrayList<String>();
+ for (BugzillaServerVersion version : BugzillaServerVersion.values()) {
+ supportedVersions.add(version.toString());
+ }
+ }
+ return supportedVersions;
+ }
+
+ /** public for testing purposes * */
+ @Override
+ public List<AbstractQueryHit> performQuery(final AbstractRepositoryQuery repositoryQuery, IProgressMonitor monitor,
+ MultiStatus status) {
+ TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(
+ repositoryQuery.getRepositoryKind(), repositoryQuery.getRepositoryUrl());
+
+ final BugzillaCategorySearchOperation categorySearch = new BugzillaCategorySearchOperation(repository,
+ repositoryQuery.getQueryUrl(), repositoryQuery.getMaxHits());
+
+ final ArrayList<AbstractQueryHit> newHits = new ArrayList<AbstractQueryHit>();
+ categorySearch.addResultsListener(new ICategorySearchListener() {
+ public void searchCompleted(BugzillaResultCollector collector) {
+ for (BugzillaSearchHit hit : collector.getResults()) {
+ String description = hit.getId() + ": " + hit.getDescription();
+
+ // TODO: Associate new hit with task (if already exists)
+ newHits.add(new BugzillaQueryHit(description, hit.getPriority(),
+ repositoryQuery.getRepositoryUrl(), hit.getId(), null, hit.getState()));
+ }
+ }
+ });
+
+ categorySearch.execute(monitor);
+ try {
+ IStatus queryStatus = categorySearch.getStatus();
+ if (!queryStatus.isOK()) {
+ status.add(new Status(IStatus.OK, MylarTaskListPlugin.PLUGIN_ID, IStatus.OK, queryStatus.getMessage(),
+ queryStatus.getException()));
+ } else {
+ status.add(queryStatus);
+ }
+ } catch (LoginException e) {
+ // TODO: Set some form of disconnect status on Query?
+ MylarStatusHandler.fail(e, "login failure for repository url: " + repository, false);
+ status.add(new Status(IStatus.OK, MylarTaskListPlugin.PLUGIN_ID, IStatus.OK, "Could not log in", e));
+ }
+
+ return newHits;
+ }
+
+ @Override
+ protected void updateOfflineState(AbstractRepositoryTask repositoryTask, boolean forceSync) {
+ if (repositoryTask instanceof BugzillaTask) {
+ BugzillaTask bugzillaTask = (BugzillaTask) repositoryTask;
+ BugReport downloadedReport = downloadReport(bugzillaTask);
+ if (downloadedReport != null) {
+ bugzillaTask.setBugReport(downloadedReport);
+ saveOffline(downloadedReport, forceSync);
+ }
+ }
+ }
+
+ @Override
+ public boolean attachContext(TaskRepository repository, AbstractRepositoryTask task, String longComment)
+ throws IOException {
+ if (!repository.hasCredentials()) {
+ MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ MylarTaskListPlugin.TITLE_DIALOG, "Repository credentials missing or invalid.");
+ return false;
+ } else {
+ boolean result = false;
+ MylarPlugin.getContextManager().saveContext(task.getHandleIdentifier());
+ File sourceContextFile = MylarPlugin.getContextManager().getFileForContext(task.getHandleIdentifier());
+
+ if (sourceContextFile != null && sourceContextFile.exists()) {
+ File folder = sourceContextFile.getParentFile();
+ if (folder != null && folder.exists() && folder.isDirectory()) {
+ List<ITask> tasksToExport = new ArrayList<ITask>();
+ tasksToExport.add(task);
+ TaskDataExportJob job = new TaskDataExportJob(MylarPlugin.getDefault().getDataDirectory(), false,
+ false, true, true, sourceContextFile.getName() + ZIPFILE_EXTENSION, tasksToExport);
+
+ // IProgressService service =
+ // PlatformUI.getWorkbench().getProgressService();
+
+ try {
+ // service.run(true, false, job);
+ job.run(new NullProgressMonitor());
+
+ File zippedContextFile = new File(MylarPlugin.getDefault().getDataDirectory() + File.separator
+ + sourceContextFile.getName() + ZIPFILE_EXTENSION);
+ if (zippedContextFile != null && zippedContextFile.exists()) {
+ result = BugzillaRepositoryUtil.uploadAttachment(repository, BugzillaTask
+ .getTaskIdAsInt(task.getHandleIdentifier()), longComment,
+ MYLAR_CONTEXT_DESCRIPTION, zippedContextFile, APPLICATION_OCTET_STREAM, false);
+ if (result) {
+ synchronize(task, false, null);
+ }
+ }
+
+ } catch (InvocationTargetException e) {
+ MylarStatusHandler.fail(e, "Could not export task context as zip file", true);
+ } catch (InterruptedException e) {
+ MylarStatusHandler.fail(e, "Could not export task context as zip file", true);
+ }
+
+ }
+ }
+
+ // if (sourceContextFile != null && sourceContextFile.exists()) {
+ // result = BugzillaRepositoryUtil.uploadAttachment(repository,
+ // BugzillaTask.getTaskIdAsInt(task
+ // .getHandleIdentifier()), longComment, MYLAR_CONTEXT_DESCRIPTION,
+ // sourceContextFile,
+ // CONTENTTYPE_APPLICATION_XML, false);
+ // if (result) {
+ // synchronize(task, false, null);
+ // }
+ // }
+ return result;
+ }
+ }
+
+ @Override
+ public Set<IRemoteContextDelegate> getAvailableContexts(TaskRepository repository, AbstractRepositoryTask task) {
+ Set<IRemoteContextDelegate> contextDelegates = new HashSet<IRemoteContextDelegate>();
+ if (task instanceof BugzillaTask) {
+ BugzillaTask bugzillaTask = (BugzillaTask) task;
+ if (bugzillaTask.getBugReport() != null) {
+ for (Comment comment : bugzillaTask.getBugReport().getComments()) {
+ if (comment.hasAttachment() && comment.getAttachmentDescription().equals(MYLAR_CONTEXT_DESCRIPTION)) {
+ contextDelegates.add(new BugzillaRemoteContextDelegate(comment));
+ }
+ }
+ }
+ }
+ return contextDelegates;
+ }
+
+ @Override
+ public boolean retrieveContext(TaskRepository repository, AbstractRepositoryTask task,
+ IRemoteContextDelegate remoteContextDelegate) throws IOException {
+ boolean result = false;
+ boolean wasActive = false;
+ if (remoteContextDelegate instanceof BugzillaRemoteContextDelegate) {
+ BugzillaRemoteContextDelegate contextDelegate = (BugzillaRemoteContextDelegate) remoteContextDelegate;
+
+ if (task.isActive()) {
+ wasActive = true;
+ MylarTaskListPlugin.getTaskListManager().deactivateTask(task);
+ }
+
+ File destinationContextFile = MylarPlugin.getContextManager().getFileForContext(task.getHandleIdentifier());
+
+ File destinationZipFile = new File(destinationContextFile.getPath() + ZIPFILE_EXTENSION);
+
+ // if(destinationContextFile.exists()) {
+ // destinationContextFile.delete();
+ // }
+
+ result = BugzillaRepositoryUtil.downloadAttachment(repository, contextDelegate.getId(), destinationZipFile,
+ true);
+
+ if (result) {
+
+ ZipFileUtil.unzipFiles(destinationZipFile, MylarPlugin.getDefault().getDataDirectory());
+
+ if (destinationContextFile.exists()) {
+
+ MylarTaskListPlugin.getTaskListManager().getTaskList().notifyLocalInfoChanged(task);
+ if (wasActive) {
+ MylarTaskListPlugin.getTaskListManager().activateTask(task);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public String getRepositoryUrlFromTaskUrl(String url) {
+ if (url == null) {
+ return null;
+ } else {
+ int index = url.indexOf(BugzillaRepositoryUtil.POST_ARGS_SHOW_BUG);
+ if (index != -1) {
+ return url.substring(0, index);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public void openRemoteTask(String repositoryUrl, String idString) {
+ int id = -1;
+ try {
+ id = Integer.parseInt(idString);
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ if (id != -1) {
+ OpenBugzillaReportJob job = new OpenBugzillaReportJob(repositoryUrl, id);
+ IProgressService service = PlatformUI.getWorkbench().getProgressService();
+ try {
+ service.run(true, false, job);
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, "Could not open report", true);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositorySettingsPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositorySettingsPage.java
new file mode 100644
index 000000000..7a43b8ee8
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaRepositorySettingsPage.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.tasklist.ui.wizards.AbstractRepositorySettingsPage;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaRepositorySettingsPage extends AbstractRepositorySettingsPage {
+
+ private static final String TITLE = "Bugzilla Repository Settings";
+
+ private static final String DESCRIPTION = "Example: https://bugs.eclipse.org/bugs (do not include index.cgi)";
+ private BugzillaRepositoryConnector connector;
+ protected Combo repositoryVersionCombo;
+
+ public BugzillaRepositorySettingsPage(BugzillaRepositoryConnector connector) {
+ super(TITLE, DESCRIPTION);
+ this.connector = connector;
+ }
+
+ protected void createAdditionalControls(Composite parent) {
+ Label repositoryVersionLabel = new Label(parent, SWT.NONE);
+ repositoryVersionLabel.setText("Repository Version: ");
+ repositoryVersionCombo = new Combo (parent, SWT.READ_ONLY);
+
+ for (String version : connector.getSupportedVersions()) {
+ repositoryVersionCombo.add(version);
+ }
+ if(repository != null && repositoryVersionCombo.indexOf(repository.getVersion()) >= 0) {
+ repositoryVersionCombo.select(repositoryVersionCombo.indexOf(repository.getVersion()));
+ } else {
+ int defaultIndex = connector.getSupportedVersions().size()-1;
+ repositoryVersionCombo.select(defaultIndex);
+ setVersion(repositoryVersionCombo.getItem(defaultIndex));
+ }
+
+ repositoryVersionCombo.addSelectionListener(new SelectionListener() {
+
+ public void widgetSelected(SelectionEvent e) {
+ if(repositoryVersionCombo.getSelectionIndex() >= 0) {
+ setVersion(repositoryVersionCombo.getItem(repositoryVersionCombo.getSelectionIndex()));
+ }
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // ignore
+ }
+ });
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ return super.isPageComplete();
+ }
+
+ protected boolean isValidUrl(String name) {
+ if (name.startsWith(URL_PREFIX_HTTPS) || name.startsWith(URL_PREFIX_HTTP)) {
+ try {
+ new URL(name);
+ return true;
+ } catch (MalformedURLException e) {
+ }
+ }
+ return false;
+ }
+
+ protected void validateSettings() {
+ try {
+ URL serverURL = new URL(super.serverUrlEditor.getStringValue());
+ URLConnection cntx = BugzillaPlugin.getDefault().getUrlConnection(serverURL);
+ if (cntx == null || !(cntx instanceof HttpURLConnection)) {
+ MessageDialog.openInformation(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG, "Could not connect.");
+ }
+
+ HttpURLConnection serverConnection = (HttpURLConnection) cntx;
+ serverConnection.connect();
+ TaskRepository tempRepository = new TaskRepository(BugzillaPlugin.REPOSITORY_KIND, getServerUrl());
+ tempRepository.setAuthenticationCredentials(getUserName(), getPassword());
+ BugzillaRepositoryUtil.getProductList(tempRepository);
+ } catch (MalformedURLException e) {
+ MessageDialog.openWarning(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG, "Server URL is invalid.");
+ return;
+ } catch (LoginException e) {
+ MessageDialog.openWarning(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Unable to authenticate with server. Login credentials invalid.");
+ return;
+ } catch (IOException e) {
+ MessageDialog.openWarning(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG, "No Bugzilla server found at url");
+ return;
+ } catch (Throwable t) {
+ MessageDialog.openWarning(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Unknown error occured. Check that server url and credentials are valid.");
+ return;
+ }
+
+ MessageDialog.openInformation(null, IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ "Authentication credentials are valid.");
+
+ super.getWizard().getContainer().updateButtons();
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTask.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTask.java
new file mode 100644
index 000000000..c9fe67a3b
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTask.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+/*
+ * Created on 14-Jan-2005
+ */
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.Comment;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.internal.HtmlStreamTokenizer;
+import org.eclipse.mylar.internal.bugzilla.core.internal.OfflineReportsFile;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask;
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaTask extends AbstractRepositoryTask {
+
+ /**
+ * 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;
+
+ public BugzillaTask(String handle, String label, boolean newTask) {
+ super(handle, label, newTask);
+ isDirty = false;
+ initFromHandle();
+ }
+
+ public BugzillaTask(BugzillaQueryHit hit, boolean newTask) {
+ this(hit.getHandleIdentifier(), hit.getDescription(), newTask);
+ setPriority(hit.getPriority());
+ initFromHandle();
+ }
+
+ private void initFromHandle() {
+ int id = AbstractRepositoryTask.getTaskIdAsInt(getHandleIdentifier());
+ String repositoryUrl = getRepositoryUrl();
+ // repositoryUrl =
+ // TaskRepositoryManager.getRepositoryUrl(getHandleIdentifier());
+ if (repositoryUrl != null) {
+ String url = BugzillaRepositoryUtil.getBugUrlWithoutLogin(repositoryUrl, id);
+ if (url != null) {
+ super.setUrl(url);
+ }
+ }
+ }
+
+ /**
+ * TODO: move?
+ */
+ public boolean readBugReport() {
+ IBugzillaBug tempBug = OfflineReportsFile.findBug(getRepositoryUrl(), AbstractRepositoryTask.getTaskIdAsInt(getHandleIdentifier()));
+ if (tempBug == null) {
+ bugReport = null;
+ return true;
+ }
+ bugReport = (BugReport) tempBug;
+
+ if (bugReport.hasChanges())
+ syncState = RepositoryTaskSyncState.OUTGOING;
+ return true;
+ }
+
+ @Override
+ public String getDescription() {
+ if (this.isDownloaded() || !super.getDescription().startsWith("<")) {
+ return super.getDescription();
+ } else {
+ if (!isSynchronizing()) {
+ return AbstractRepositoryTask.getTaskIdAsInt(getHandleIdentifier()) + ": <Could not find bug>";
+ } else {
+ return AbstractRepositoryTask.getTaskIdAsInt(getHandleIdentifier()) + ":";
+ }
+ }
+ }
+
+ public BugReport getBugReport() {
+ return bugReport;
+ }
+
+ public String getTaskType() {
+ if (bugReport != null && bugReport.getAttribute(BugReport.ATTRIBUTE_SEVERITY) != null) {
+ return bugReport.getAttribute(BugReport.ATTRIBUTE_SEVERITY).getValue();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @param bugReport
+ * The bugReport to set.
+ */
+ public void setBugReport(BugReport bugReport) {
+ this.bugReport = bugReport;
+
+ // TODO: remove?
+ if (bugReport != null) {
+ setDescription(HtmlStreamTokenizer.unescape(AbstractRepositoryTask
+ .getTaskIdAsInt(getHandleIdentifier())
+ + ": " + bugReport.getSummary()));
+ }
+ }
+
+ public boolean isDownloaded() {
+ return bugReport != null;
+ }
+
+ @Override
+ public String toString() {
+ return "bugzilla report id: " + getHandleIdentifier();
+ }
+
+ @Override
+ public boolean isCompleted() {
+ if (bugReport != null) {
+ return bugReport.isResolved();
+ } else {
+ return super.isCompleted();
+ }
+ }
+
+ @Override
+ public String getUrl() {
+ // fix for bug 103537 - should login automatically, but dont want to
+ // show the login info in the query string
+ return BugzillaRepositoryUtil.getBugUrlWithoutLogin(getRepositoryUrl(), AbstractRepositoryTask
+ .getTaskIdAsInt(handle));
+ }
+
+ @Override
+ public Date getCompletionDate() {
+ if (bugReport != null) {
+ if (bugReport.isResolved()) {
+ List<Comment> comments = bugReport.getComments();
+ if (comments != null && !comments.isEmpty()) {
+ return comments.get(comments.size() - 1).getCreated();
+ }
+ }
+ }
+ return null;
+ }
+
+ public String getRepositoryKind() {
+ return BugzillaPlugin.REPOSITORY_KIND;
+ }
+
+ @Override
+ public String getPriority() {
+ if (bugReport != null && bugReport.getAttribute(BugReport.ATTR_PRIORITY) != null) {
+ return bugReport.getAttribute(BugReport.ATTR_PRIORITY).getValue();
+ } else {
+ return super.getPriority();
+ }
+ }
+
+ @Override
+ public boolean isPersistentInWorkspace() {
+ return true;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskDecorator.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskDecorator.java
new file mode 100644
index 000000000..5747b7cc3
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskDecorator.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2006 - 2006 Mylar eclipse.org project 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:
+ * Mylar project committers - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.mylar.internal.bugzilla.ui.BugzillaImages;
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaTaskDecorator implements ILightweightLabelDecorator {
+
+ public void decorate(Object element, IDecoration decoration) {
+ if (element instanceof BugzillaTask) {
+ String kind = ((BugzillaTask)element).getTaskType();
+ if ("major".equals(kind) || "blocker".equals(kind)) {
+ decoration.addOverlay(BugzillaImages.OVERLAY_MAJOR, IDecoration.BOTTOM_RIGHT);
+ } else if ("enhancement".equals(kind)){
+ decoration.addOverlay(BugzillaImages.OVERLAY_ENHANCEMENT, IDecoration.BOTTOM_RIGHT);
+ }
+ } else if (element instanceof BugzillaQueryHit) {
+ BugzillaQueryHit hit = (BugzillaQueryHit)element;
+ if (hit.getCorrespondingTask() != null) {
+ decorate(hit.getCorrespondingTask(), decoration);
+ }
+ }
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ // ignore
+ }
+
+ public void dispose() {
+ // ignore
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ // ignore
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskEditor.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskEditor.java
new file mode 100644
index 000000000..7eae841b5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskEditor.java
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+/*
+ * Created on 31-Jan-2005
+ */
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+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.internal.bugzilla.core.IBugzillaAttributeListener;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.AbstractBugEditor;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.BugzillaOutlineNode;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.ExistingBugEditor;
+import org.eclipse.mylar.internal.tasklist.ui.TaskListImages;
+import org.eclipse.mylar.internal.tasklist.ui.editors.MylarTaskEditor;
+import org.eclipse.mylar.internal.tasklist.ui.editors.TaskEditorInput;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaTaskEditor extends MylarTaskEditor {
+
+ private static final String EDITOR_TAB_ITLE = "Bug Editor";
+
+ /** 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 BugzillaOutlinePage outlinePage = null;
+
+// protected BugzillaOutlineNode bugzillaOutlineModel = null;
+
+ private IBugzillaAttributeListener ATTRIBUTE_LISTENER = new IBugzillaAttributeListener() {
+ public void attributeChanged(String attribute, String value) {
+ // TODO: get rid of this?
+ 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 = MylarTaskListPlugin.getDefault().getWorkbench();
+ // IWorkbenchWindow aw = wb.getActiveWorkbenchWindow();
+ // IWorkbenchPage ap = aw.getActivePage();
+ // BugzillaTaskEditorListener listener = new
+ // BugzillaTaskEditorListener();
+ // ap.addPartListener(listener);
+
+ bugzillaEditor = new ExistingBugEditor();
+ bugzillaEditor.setParentEditor(this);
+ bugzillaEditor.addAttributeListener(ATTRIBUTE_LISTENER);
+ // taskSummaryEditor = new TaskInfoEditor();
+ // taskSummaryEditor.setParentEditor(this);
+ }
+
+ public AbstractBugEditor getBugzillaEditor() {
+ return bugzillaEditor;
+ }
+
+ 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, EDITOR_TAB_ITLE);
+ }
+
+ /**
+ * Creates the pages of the multi-page editor.
+ */
+ @Override
+ protected void createPages() {
+ createBugzillaSubmitPage();
+ super.createPages();
+ }
+
+ /**
+ * Saves the multi-page editor's document.
+ */
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+ super.doSave(monitor);
+ // if(taskSummaryEditor.isDirty())
+ // taskSummaryEditor.doSave(monitor);
+ if (bugzillaEditor.isDirty())
+ bugzillaEditor.doSave(monitor);
+
+ // TODO save both editors if needed
+ }
+
+ public boolean isDirty() {
+ return bugzillaEditor.isDirty() || super.isDirty();
+ }
+
+ public void changeDirtyStatus(boolean newDirtyStatus) {
+ firePropertyChange(PROP_DIRTY);
+ }
+
+ @Override
+ public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
+ if (!(editorInput instanceof BugzillaTaskEditorInput))
+ throw new PartInitException("Invalid Input: Must be BugzillaTaskEditorInput");
+ super.init(site, (IEditorInput) new TaskEditorInput(((BugzillaTaskEditorInput) editorInput).getBugTask(), false));
+ bugzillaEditorInput = (BugzillaTaskEditorInput) editorInput;
+ bugTask = bugzillaEditorInput.getBugTask();
+ bugzillaEditor.setBugzillaOutlineModel(BugzillaOutlineNode.parseBugReport(bugzillaEditorInput.getBug()));
+ offlineBug = bugzillaEditorInput.getOfflineBug();
+
+ 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.setPartName(bugTask.getDescription());
+ this.setTitleImage(TaskListImages.getImage(TaskListImages.TASK_REPOSITORY));
+ }
+
+ @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());
+ }
+
+
+// @Override
+// public Object getAdapter(Class adapter) {
+// if (IContentOutlinePage.class.equals(adapter)) {
+// if (outlinePage == null && bugzillaEditorInput != null) {
+// outlinePage = new BugzillaOutlinePage(bugzillaOutlineModel);
+// }
+// return outlinePage;
+// }
+// return super.getAdapter(adapter);
+// }
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ return bugzillaEditor.getAdapter(adapter);
+ }
+
+ // /**
+ // * 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(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ "Could not open bug.", "Bug #" + offlineBug.getId()
+ + " could not be read from the server. Try refreshing the bug task.");
+ return;
+ }
+ }
+
+ public void close() {
+ Display display = getSite().getShell().getDisplay();
+ display.asyncExec(new Runnable() {
+ public void run() {
+ getSite().getPage().closeEditor(BugzillaTaskEditor.this, false);
+ }
+ });
+ }
+
+ @Override
+ public void doSaveAs() {
+ // do nothing here
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskExternalizer.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskExternalizer.java
new file mode 100644
index 000000000..aa4d9d5a9
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/BugzillaTaskExternalizer.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import java.util.Date;
+
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.TaskExternalizationException;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryQuery;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask;
+import org.eclipse.mylar.provisional.tasklist.AbstractTaskContainer;
+import org.eclipse.mylar.provisional.tasklist.DelegatingTaskExternalizer;
+import org.eclipse.mylar.provisional.tasklist.ITask;
+import org.eclipse.mylar.provisional.tasklist.TaskList;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask.RepositoryTaskSyncState;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaTaskExternalizer extends DelegatingTaskExternalizer {
+
+ private static final String STATUS_RESO = "RESO";
+
+ private static final String STATUS_NEW = "NEW";
+
+ private static final String LAST_DATE = "LastDate";
+
+ private static final String DIRTY = "Dirty";
+
+ private static final String SYNC_STATE = "offlineSyncState";
+
+ private static final String TAG_BUGZILLA_QUERY_HIT = "Bugzilla" + KEY_QUERY_HIT;
+
+ private static final String TAG_BUGZILLA_QUERY = "Bugzilla" + KEY_QUERY;
+
+ private static final String TAG_BUGZILLA_CUSTOM_QUERY = "BugzillaCustom" + KEY_QUERY;
+
+ private static final String TAG_BUGZILLA_REPORT = "BugzillaReport";
+
+ public String getQueryTagNameForElement(AbstractRepositoryQuery query) {
+ if (query instanceof BugzillaRepositoryQuery) {
+ if (((BugzillaRepositoryQuery)query).isCustomQuery()) {
+ return TAG_BUGZILLA_CUSTOM_QUERY;
+ } else {
+ return TAG_BUGZILLA_QUERY;
+ }
+ }
+ return "";
+ }
+
+ public boolean canReadQuery(Node node) {
+ return node.getNodeName().equals(TAG_BUGZILLA_CUSTOM_QUERY) || node.getNodeName().equals(TAG_BUGZILLA_QUERY);
+ }
+
+ public AbstractRepositoryQuery readQuery(Node node, TaskList taskList) throws TaskExternalizationException {
+ boolean hasCaughtException = false;
+ Element element = (Element) node;
+ BugzillaRepositoryQuery query = new BugzillaRepositoryQuery(
+ element.getAttribute(KEY_REPOSITORY_URL),
+ element.getAttribute(KEY_QUERY_STRING),
+ element.getAttribute(KEY_NAME),
+ element.getAttribute(KEY_QUERY_MAX_HITS), taskList);
+ if (node.getNodeName().equals(TAG_BUGZILLA_CUSTOM_QUERY)) {
+ query.setCustomQuery(true);
+ }
+ if(!element.getAttribute(KEY_LAST_REFRESH).equals("")) {
+ Date refreshDate = new Date();
+ try {
+ refreshDate.setTime(Long.parseLong(element.getAttribute(KEY_LAST_REFRESH)));
+ query.setLastRefresh(refreshDate);
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ }
+
+ NodeList list = node.getChildNodes();
+ for (int i = 0; i < list.getLength(); i++) {
+ Node child = list.item(i);
+ try {
+ readQueryHit(child, taskList, query);
+ } catch (TaskExternalizationException e) {
+ hasCaughtException = true;
+ }
+ }
+ if (hasCaughtException) {
+ throw new TaskExternalizationException("Failed to load all tasks");
+ } else {
+ return query;
+ }
+ }
+
+// public void readRegistry(Node node, TaskList taskList) throws TaskExternalizationException {
+// boolean hasCaughtException = false;
+// NodeList list = node.getChildNodes();
+// for (int i = 0; i < list.getLength(); i++) {
+// try {
+// Node child = list.item(i);
+// ITask task = readTask(child, taskList, null, null);
+// if (task instanceof AbstractRepositoryTask) {
+// taskList.addTaskToArchive((AbstractRepositoryTask)task);
+// }
+// } catch (TaskExternalizationException e) {
+// hasCaughtException = true;
+// }
+// }
+//
+// if (hasCaughtException)
+// throw new TaskExternalizationException("Failed to restore all tasks");
+// }
+
+// public boolean canCreateElementFor(ITaskContainer cat) {
+// return false;
+// }
+
+ public boolean canCreateElementFor(AbstractRepositoryQuery category) {
+ return category instanceof BugzillaRepositoryQuery;
+ }
+
+ 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 bugzillaTask = (BugzillaTask) task;
+ if (bugzillaTask.getLastRefresh() != null) {
+ node.setAttribute(LAST_DATE, new Long(bugzillaTask.getLastRefresh().getTime()).toString());
+ } else {
+ node.setAttribute(LAST_DATE, new Long(new Date().getTime()).toString());
+ }
+
+ node.setAttribute(SYNC_STATE, bugzillaTask.getSyncState().toString());
+
+ if (bugzillaTask.isDirty()) {
+ node.setAttribute(DIRTY, VAL_TRUE);
+ } else {
+ node.setAttribute(DIRTY, VAL_FALSE);
+ }
+ return node;
+ }
+
+ @Override
+ public boolean canReadTask(Node node) {
+ return node.getNodeName().equals(getTaskTagName());
+ }
+
+ @Override
+ public ITask readTask(Node node, TaskList taskList, AbstractTaskContainer category, ITask parent)
+ throws TaskExternalizationException {
+ Element element = (Element) node;
+ String handle;
+ String label;
+ if (element.hasAttribute(KEY_HANDLE)) {
+ handle = element.getAttribute(KEY_HANDLE);
+ } else {
+ throw new TaskExternalizationException("Handle not stored for bug report");
+ }
+ if (element.hasAttribute(KEY_LABEL)) {
+ label = element.getAttribute(KEY_LABEL);
+ } else {
+ throw new TaskExternalizationException("Description not stored for bug report");
+ }
+ BugzillaTask task = new BugzillaTask(handle, label, false);
+ readTaskInfo(task, taskList, element, parent, category);
+
+ task.setCurrentlyDownloading(false);
+ task.setLastRefresh(new Date(new Long(element.getAttribute("LastDate")).longValue()));
+
+ if (element.getAttribute("Dirty").compareTo("true") == 0) {
+ task.setDirty(true);
+ } else {
+ task.setDirty(false);
+ }
+ try {
+ if (task.readBugReport() == false) {
+ MylarStatusHandler.log("Failed to read bug report", null);
+ }
+ } catch (Exception e) {
+ MylarStatusHandler.log(e, "Failed to read bug report");
+ }
+
+ if (element.hasAttribute(SYNC_STATE)) {
+ String syncState = element.getAttribute(SYNC_STATE);
+ if (syncState.compareTo(RepositoryTaskSyncState.SYNCHRONIZED.toString()) == 0) {
+ task.setSyncState(RepositoryTaskSyncState.SYNCHRONIZED);
+ } else if (syncState.compareTo(RepositoryTaskSyncState.INCOMING.toString()) == 0) {
+ task.setSyncState(RepositoryTaskSyncState.INCOMING);
+ } else if (syncState.compareTo(RepositoryTaskSyncState.OUTGOING.toString()) == 0) {
+ task.setSyncState(RepositoryTaskSyncState.OUTGOING);
+ } else if (syncState.compareTo(RepositoryTaskSyncState.CONFLICT.toString()) == 0) {
+ task.setSyncState(RepositoryTaskSyncState.CONFLICT);
+ }
+ }
+
+ // TODO: put back, checking for null category?
+// taskList.internalAddTask(task, category);
+ return task;
+ }
+
+ public boolean canReadQueryHit(Node node) {
+ return node.getNodeName().equals(getQueryHitTagName());
+ }
+
+ public void readQueryHit(Node node, TaskList taskList, AbstractRepositoryQuery query) throws TaskExternalizationException {
+ Element element = (Element) node;
+ String handle;
+ String label;
+ String priority;
+ String status;
+ if (element.hasAttribute(KEY_HANDLE)) {
+ handle = element.getAttribute(KEY_HANDLE);
+ } else {
+ throw new TaskExternalizationException("Handle not stored for bug report");
+ }
+ if (element.hasAttribute(KEY_NAME)) {
+ label = element.getAttribute(KEY_NAME);
+ } else {
+ throw new TaskExternalizationException("Description not stored for bug report");
+ }
+ if (element.hasAttribute(KEY_PRIORITY)) {
+ priority = element.getAttribute(KEY_PRIORITY);
+ } else {
+ throw new TaskExternalizationException("Description not stored for bug report");
+ }
+
+ status = STATUS_NEW;
+ if (element.hasAttribute(KEY_COMPLETE)) {
+ status = element.getAttribute(KEY_COMPLETE);
+ if (status.equals(VAL_TRUE)) {
+ status = STATUS_RESO;
+ }
+ }
+ BugzillaQueryHit hit = new BugzillaQueryHit(label, priority, query.getRepositoryUrl(), AbstractRepositoryTask
+ .getTaskIdAsInt(handle), null, status);
+ ITask correspondingTask = taskList.getTask(hit.getHandleIdentifier());
+ if (correspondingTask instanceof BugzillaTask) {
+ hit.setCorrespondingTask((BugzillaTask)correspondingTask);
+ }
+
+ query.addHit(hit);
+ }
+
+ @Override
+ public String getTaskTagName() {
+ return TAG_BUGZILLA_REPORT;
+ }
+
+ @Override
+ public String getQueryHitTagName() {
+ return TAG_BUGZILLA_QUERY_HIT;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/EditBugzillaQueryWizard.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/EditBugzillaQueryWizard.java
new file mode 100644
index 000000000..7dbe2e009
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/EditBugzillaQueryWizard.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.ui.search.BugzillaSearchPage;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.TaskListPreferenceConstants;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryConnector;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+
+/**
+ * @author Rob Elves
+ */
+public class EditBugzillaQueryWizard extends Wizard {
+
+ private static final String TITLE = "Edit Bugzilla Query";
+
+ private final TaskRepository repository;
+
+ private AbstractBugzillaQueryPage page;
+
+ private BugzillaRepositoryQuery query;
+
+ public EditBugzillaQueryWizard(TaskRepository repository, BugzillaRepositoryQuery query) {
+ this.repository = repository;
+ this.query = query;
+ setNeedsProgressMonitor(true);
+ setWindowTitle(TITLE);
+ }
+
+ @Override
+ public void addPages() {
+ if (query.isCustomQuery()) {
+ page = new BugzillaCustomQueryWizardPage(repository, query);
+ } else {
+ page = new BugzillaSearchPage(repository, query);
+ }
+ addPage(page);
+
+ }
+
+ @Override
+ public boolean performFinish() {
+
+ query = page.getQuery();
+
+ final String queryTitle = page.getQueryTitle().trim();
+
+ MylarTaskListPlugin.getTaskListManager().getTaskList().renameContainer(query, queryTitle);
+
+ boolean offline = MylarTaskListPlugin.getMylarCorePrefs().getBoolean(TaskListPreferenceConstants.WORK_OFFLINE);
+ if (!offline) {
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Executing query", 50);
+ try {
+ AbstractRepositoryConnector client = MylarTaskListPlugin.getRepositoryManager()
+ .getRepositoryConnector(BugzillaPlugin.REPOSITORY_KIND);
+
+ client.synchronize(query, null);
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+
+ try {
+ getContainer().run(true, false, op);
+ } catch (Exception e) {
+ MylarStatusHandler.log(e, "There was a problem executing the query refresh");
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean canFinish() {
+ if (page != null && page.isPageComplete()) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/NewBugzillaQueryWizard.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/NewBugzillaQueryWizard.java
new file mode 100644
index 000000000..a4e5f0278
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/NewBugzillaQueryWizard.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.TaskListPreferenceConstants;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryConnector;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+
+/**
+ * @author Mik Kersten
+ * @author Brock Janiczak
+ */
+public class NewBugzillaQueryWizard extends Wizard {
+
+ private static final String TITLE = "New Bugzilla Query";
+
+ private final TaskRepository repository;
+
+ BugzillaQueryTypeWizardPage page1;
+
+ public NewBugzillaQueryWizard(TaskRepository repository) {
+ this.repository = repository;
+ setNeedsProgressMonitor(true);
+ setWindowTitle(TITLE);
+ }
+
+ @Override
+ public void addPages() {
+ page1 = new BugzillaQueryTypeWizardPage(repository);
+ page1.setWizard(this);
+ addPage(page1);
+
+ }
+
+ @Override
+ public boolean performFinish() {
+
+ AbstractBugzillaQueryPage page;
+
+ if (page1.getNextPage() != null && page1.getNextPage() instanceof AbstractBugzillaQueryPage) {
+ page = (AbstractBugzillaQueryPage) page1.getNextPage();
+ } else {
+ return false;
+ }
+
+ final BugzillaRepositoryQuery queryCategory = page.getQuery();
+
+ MylarTaskListPlugin.getTaskListManager().getTaskList().addQuery(queryCategory);
+ boolean offline = MylarTaskListPlugin.getMylarCorePrefs().getBoolean(TaskListPreferenceConstants.WORK_OFFLINE);
+ if (!offline) {
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Executing query", 50);
+ try {
+ AbstractRepositoryConnector client = MylarTaskListPlugin.getRepositoryManager()
+ .getRepositoryConnector(BugzillaPlugin.REPOSITORY_KIND);
+ client.synchronize(queryCategory, null);
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+
+ try {
+ getContainer().run(true, false, op);
+ } catch (Exception e) {
+ MylarStatusHandler.log(e, "There was a problem executing the query refresh");
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean canFinish() {
+ if (page1.getNextPage() != null && page1.getNextPage().isPageComplete()) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/OpenBugzillaReportJob.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/OpenBugzillaReportJob.java
new file mode 100644
index 000000000..6cf39e800
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/tasklist/OpenBugzillaReportJob.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.bugzilla.ui.tasklist;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.mylar.internal.bugzilla.ui.BugzillaOpenStructure;
+import org.eclipse.mylar.internal.bugzilla.ui.ViewBugzillaAction;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+
+/**
+ * @author Mik Kersten
+ */
+public class OpenBugzillaReportJob implements IRunnableWithProgress {
+
+ private int id;
+
+ private String serverUrl;
+
+ public OpenBugzillaReportJob(String serverUrl, int id) {
+ this.id = id;
+ this.serverUrl = serverUrl;
+ }
+
+ public void run(IProgressMonitor monitor) {
+ try {
+ monitor.beginTask("Opening Bugzilla Report", 10);
+ List<BugzillaOpenStructure> list = new ArrayList<BugzillaOpenStructure>(1);
+ list.add(new BugzillaOpenStructure(serverUrl, id, -1));
+ new ViewBugzillaAction("Open Bug " + id, list).run(monitor);
+ monitor.done();
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, "Unable to open Bug report: " + id, true);
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugWizard.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugWizard.java
new file mode 100644
index 000000000..c5fb9f79a
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugWizard.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui.wizard;
+
+import java.io.IOException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaReportSubmitForm;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaException;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.NewBugModel;
+import org.eclipse.mylar.internal.bugzilla.core.PossibleBugzillaFailureException;
+import org.eclipse.mylar.internal.bugzilla.ui.BugzillaUiPlugin;
+import org.eclipse.mylar.internal.bugzilla.ui.WebBrowserDialog;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.ExistingBugEditorInput;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.search.internal.ui.SearchMessages;
+import org.eclipse.search.internal.ui.util.ExceptionHandler;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.progress.IProgressService;
+
+/**
+ * Class that contains shared functions for the wizards that submit bug reports.
+ *
+ * @author Eric Booth
+ * @author Mik Kersten (some hardening of prototype)
+ */
+public abstract class AbstractBugWizard extends Wizard implements INewWizard {
+
+ /** The ID of the posted bug report. */
+ private String id;
+
+ protected boolean fromDialog = false;
+
+ /** The model used to store all of the data for the wizard */
+ protected NewBugModel model;
+
+ /**
+ * Flag to indicate if the wizard can be completed based on the attributes
+ * page
+ */
+ protected boolean attributeCompleted = false;
+
+ /** The workbench instance */
+ protected IWorkbench workbenchInstance;
+
+ private final TaskRepository repository;
+
+ public AbstractBugWizard(TaskRepository repository) {
+ super();
+ this.repository = repository;
+ model = new NewBugModel();
+ id = null; // Since there is no bug posted yet.
+ super.setDefaultPageImageDescriptor(BugzillaUiPlugin.imageDescriptorFromPlugin(
+ "org.eclipse.mylar.internal.bugzilla.ui", "icons/wizban/bug-wizard.gif"));
+ // setForcePreviousAndNextButtons(true);
+ }
+
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ this.workbenchInstance = workbench;
+ }
+
+ @Override
+ public void addPages() {
+ super.addPages();
+ }
+
+ @Override
+ public boolean performFinish() {
+ // if (getWizardDataPage().serverSelected()) {
+ getWizardDataPage().saveDataToModel();
+ // If the bug report is sent successfully,
+ // then close the wizard and open the bug in an editor
+ if (postBug()) {
+ // if (!fromDialog)
+ // openBugEditor();
+ return true;
+ }
+ // If the report was not sent, keep the wizard open
+ else {
+ return false;
+ }
+ // }
+
+ // if (getWizardDataPage().offlineSelected()) {
+ // saveBugOffline();
+ // return true;
+ // }
+
+ // If no action was selected, keep the wizard open.
+ // return false;
+ }
+
+ // Flag to indicate if the bug was successfully sent
+ private boolean sentSuccessfully = false;
+
+ /**
+ * Attempts to post the bug on the Bugzilla server. If it fails, an error
+ * message pops up.
+ *
+ * @return true if the bug is posted successfully, and false otherwise
+ */
+ protected boolean postBug() {
+ final WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(final IProgressMonitor monitor) throws CoreException {
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+ public void run() {
+ BugzillaReportSubmitForm form = BugzillaReportSubmitForm.makeNewBugPost(repository, model);
+ try {
+ id = form.submitReportToRepository();
+
+ if (id != null) {
+ sentSuccessfully = true;
+ }
+ } catch (BugzillaException e) {
+ MessageDialog.openError(null, "I/O Error", "Bugzilla could not post your bug.");
+ BugzillaPlugin.log(e);
+ } catch (PossibleBugzillaFailureException e) {
+ WebBrowserDialog.openAcceptAgreement(null, "Possible Bugzilla Client Failure",
+ "Bugzilla may not have posted your bug.\n" + e.getMessage(), form.getError());
+ BugzillaPlugin.log(e);
+ } catch (LoginException e) {
+ MessageDialog.openError(null, "Posting Error",
+ "Bugzilla could not post your bug since your login name or password is incorrect."
+ + "\nPlease check your settings in the bugzilla preferences. ");
+ sentSuccessfully = false;
+ }
+ }
+
+ });
+ }
+ };
+
+ IProgressService service = PlatformUI.getWorkbench().getProgressService();
+ try {
+ service.run(false, false, op);
+ } catch (Exception e) {
+ MylarStatusHandler.log(e, "Unable to submit bug");
+ }
+ return sentSuccessfully;
+ }
+
+ /**
+ * Try to open the editor with the newly created bug.
+ */
+ protected void openBugEditor() {
+
+ IEditorInput input = null;
+ try {
+ input = new ExistingBugEditorInput(repository.getUrl(), Integer.parseInt(id));
+ BugzillaPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(input,
+ IBugzillaConstants.EXISTING_BUG_EDITOR_ID, false);
+ } catch (LoginException e) {
+ // if we had an error with logging in, display an error
+ MessageDialog.openError(null, "Posting Error",
+ "Bugzilla could not access and display your bug in the editor because your login name or password is incorrect."
+ + "\nPlease check your settings in the bugzilla preferences. ");
+ } catch (PartInitException e) {
+ // if there was a problem, handle it and log it, then get out of
+ // here
+ ExceptionHandler.handle(e, SearchMessages.Search_Error_search_title,
+ SearchMessages.Search_Error_search_message);
+ BugzillaPlugin.log(e.getStatus());
+ } catch (IOException e) {
+ BugzillaPlugin.getDefault().logAndShowExceptionDetailsDialog(e, "occurred while opening the bug report.",
+ "Bugzilla Error");
+ }
+ }
+
+ /**
+ * Saves the bug report offline on the user's hard-drive. All offline bug
+ * reports are saved together in a single file in the plug-in's directory.
+ */
+ abstract protected void saveBugOffline();
+
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * @return the last page of this wizard
+ */
+ abstract protected AbstractBugzillaWizardPage getWizardDataPage();
+
+ public TaskRepository getRepository() {
+ return repository;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugzillaWizardPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugzillaWizardPage.java
new file mode 100644
index 000000000..42f0efaad
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/AbstractBugzillaWizardPage.java
@@ -0,0 +1,770 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui.wizard;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.mylar.bugzilla.core.Attribute;
+import org.eclipse.mylar.internal.bugzilla.core.NewBugModel;
+import org.eclipse.mylar.internal.bugzilla.core.internal.BugReportElement;
+import org.eclipse.mylar.internal.bugzilla.ui.editor.AbstractBugEditor;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
+
+/**
+ * Class that contains shared functions for the last page of the wizards that
+ * submit bug reports. This page allows the user to set the bug report's
+ * attributes before submitting it.
+ *
+ * @author Mik Kersten (hardening of initial prototype)
+ */
+public abstract class AbstractBugzillaWizardPage extends WizardPage implements Listener {
+
+ /** The instance of the workbench */
+ protected IWorkbench workbench;
+
+ /** Text field for the bugs url */
+ protected Text urlText;
+
+ /** Text field for the description of the bug */
+ protected Text descriptionText;
+
+ /** Text field for the summary of the bug */
+ protected Text summaryText;
+
+ /** Text field for the assignedTo of the bug */
+ protected Text assignedToText;
+
+ // /** Radio button to select when sending the new bug report to the server
+ // */
+ // protected Button serverButton;
+ //
+ // /** Radio button to select when saving the new bug report offline */
+ // protected Button offlineButton;
+
+ /** Combo box for the component that caused the bug */
+ protected Combo componentCombo;
+
+ /** Combo box for the priority of the bug */
+ protected Combo priorityCombo;
+
+ /** Combo box for the platform the bug occurred on */
+ protected Combo platformCombo;
+
+ /** Combo box for the severity of the bug */
+ protected Combo severityCombo;
+
+ /** Combo box for the products version */
+ protected Combo versionCombo;
+
+ /** Combo box for the OS that the bug occurred under */
+ protected Combo oSCombo;
+
+ /** Combo box for the Milestone that the bug addresses */
+ protected Combo milestoneCombo;
+
+ /** Enum for value */
+ protected final String VALUE = "VALUE";
+
+ /** Enum for property */
+ protected final String PROPERTY = "PROPERTY";
+
+ /** Enum for header */
+ protected final String HEADER = "HEADER";
+
+ /** The horizontal indentation of the labels */
+ protected final int HORZ_INDENT = 0;
+
+ /** Status variable for the possible errors on this page */
+ protected IStatus attributeStatus;
+
+ /**
+ * Constructor for AbstractWizardDataPage
+ *
+ * @param pageName
+ * the name of the page
+ * @param title
+ * the title of the page
+ * @param description
+ * the description text for the page
+ * @param workbench
+ * the instance of the workbench
+ */
+ public AbstractBugzillaWizardPage(String pageName, String title, String description, IWorkbench workbench) {
+ super(pageName);
+ setTitle(title);
+ setDescription(description);
+ this.workbench = workbench;
+
+ // set the status for the page
+ attributeStatus = new Status(IStatus.OK, "not_used", 0, "", null);
+ }
+
+ /**
+ * Applies the status to the status line of a dialog page.
+ *
+ * @param status
+ * The status to apply to the status line
+ */
+ protected void applyToStatusLine(IStatus status) {
+ String message = status.getMessage();
+ if (message.length() == 0)
+ message = null;
+ switch (status.getSeverity()) {
+ case IStatus.OK:
+ setErrorMessage(null);
+ setMessage(message);
+ break;
+ case IStatus.WARNING:
+ setErrorMessage(null);
+ setMessage(message, WizardPage.WARNING);
+ break;
+ case IStatus.INFO:
+ setErrorMessage(null);
+ setMessage(message, WizardPage.INFORMATION);
+ break;
+ default:
+ setErrorMessage(null);
+ setMessage(message, WizardPage.ERROR);
+ break;
+ }
+ }
+
+ /**
+ * Make sure that a String that is <code>null</code> is changed to a null
+ * string
+ *
+ * @param text
+ * The text to check if it is null or not
+ * @return The string in its proper format
+ */
+ public String checkText(String text) {
+ if (text == null)
+ return "";
+ else
+ return text;
+ }
+
+ @Override
+ public boolean canFlipToNextPage() {
+ // no next page for this path through the wizard
+ return false;
+ }
+
+ /**
+ * Create a new layout for a component
+ *
+ * @param composite
+ * The parent composite
+ * @param colSpan
+ * The number of columns that this can span
+ * @param text
+ * The text to add to the control
+ * @param style
+ * The style that the control should have
+ */
+ public void newLayout(Composite composite, int colSpan, String text, String style) {
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ data.horizontalSpan = colSpan;
+
+ // create the proper layout for the style
+ if (style.equalsIgnoreCase(VALUE)) {
+ Label l = new Label(composite, SWT.NONE);
+ FontData fontData = l.getFont().getFontData()[0];
+ fontData.setStyle(SWT.BOLD | fontData.getStyle());
+ Font font = new Font(null, fontData);
+ l.setFont(font);
+ l.setText(checkText(text));
+
+ data.horizontalIndent = HORZ_INDENT;
+ l.setLayoutData(data);
+ } else if (style.equalsIgnoreCase(PROPERTY)) {
+ Label l = new Label(composite, SWT.NONE);
+ FontData fontData = l.getFont().getFontData()[0];
+ fontData.setStyle(SWT.BOLD | fontData.getStyle());
+ Font font = new Font(null, fontData);
+ l.setFont(font);
+ l.setText(checkText(text));
+
+ data.horizontalIndent = HORZ_INDENT;
+ l.setLayoutData(data);
+ } else {
+ Composite generalTitleGroup = new Composite(composite, SWT.NONE);
+ generalTitleGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ generalTitleGroup.setLayoutData(data);
+ GridLayout generalTitleLayout = new GridLayout();
+ generalTitleLayout.numColumns = 2;
+ generalTitleLayout.marginWidth = 0;
+ generalTitleLayout.marginHeight = 9;
+ generalTitleGroup.setLayout(generalTitleLayout);
+
+ Label image = new Label(generalTitleGroup, SWT.NONE);
+ image.setImage(WorkbenchImages.getImage(IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM));
+
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
+ image.setLayoutData(gd);
+ Label l = new Label(composite, SWT.NONE);
+ FontData fontData = l.getFont().getFontData()[0];
+ fontData.setStyle(SWT.BOLD | fontData.getStyle());
+ Font font = new Font(null, fontData);
+ l.setFont(font);
+ l.setText(checkText(text));
+
+ data.horizontalIndent = HORZ_INDENT;
+ l.setLayoutData(data);
+ }
+ }
+
+ /**
+ * Determine if the page is complete when the summary is changed
+ *
+ * @param e
+ * The event which occurred
+ */
+ public void handleEvent(Event e) {
+ boolean pageComplete = isPageComplete();
+
+ // Initialize a variable with the no error status
+ Status status = new Status(IStatus.OK, "not_used", 0, "", null);
+
+ setPageComplete(pageComplete);
+
+ if (!pageComplete)
+ status = new Status(IStatus.ERROR, "not_used", 0, "You must enter a summary and a description", null);
+
+ attributeStatus = status;
+
+ // Show the most serious error
+ applyToStatusLine(attributeStatus);
+
+ setPageComplete(pageComplete);
+ getWizard().getContainer().updateButtons();
+ }
+
+ @Override
+ public IWizardPage getNextPage() {
+ saveDataToModel();
+ return null;
+ }
+
+ /**
+ * Sets the completed field on the wizard class when all the needed
+ * information is entered and the wizard can be completed
+ *
+ * @return true if the wizard can be completed, false otherwise
+ */
+ @Override
+ public boolean isPageComplete() {
+ AbstractBugWizard wizard = (AbstractBugWizard) getWizard();
+ if (summaryText.getText() == null || summaryText.getText().equals("") || descriptionText.getText() == null
+ || descriptionText.getText().equals("")) {
+ wizard.attributeCompleted = false;
+ return false;
+ }
+ // saveDataToModel();
+ wizard.attributeCompleted = true;
+ return true;
+ }
+
+ /**
+ * Save the data obtained from this point in the wizard to the model.
+ */
+ public void saveDataToModel() {
+ // get the model that we are using
+ AbstractBugWizard wizard = (AbstractBugWizard) getWizard();
+ NewBugModel nbm = wizard.model;
+
+ nbm.setDescription(descriptionText.getText());
+ nbm.setSummary(summaryText.getText());
+
+ // go through each of the attributes and sync their values with the
+ // combo boxes
+ for (Iterator<Attribute> it = nbm.getAttributes().iterator(); it.hasNext();) {
+ Attribute attribute = it.next();
+ String key = attribute.getName();
+ Map<String, String> values = attribute.getOptionValues();
+
+ try {
+ if (values == null)
+ values = new HashMap<String, String>();
+ if (key.equals(BugReportElement.OP_SYS.toString())) {
+ String os = oSCombo.getItem(oSCombo.getSelectionIndex());
+ attribute.setValue(os);
+ } else if (key.equals(BugReportElement.VERSION.toString())) {
+ String version = versionCombo.getItem(versionCombo.getSelectionIndex());
+ attribute.setValue(version);
+ } else if (key.equals(BugReportElement.BUG_SEVERITY.toString())) {
+ String severity = severityCombo.getItem(severityCombo.getSelectionIndex());
+ attribute.setValue(severity);
+ } else if (key.equals(BugReportElement.REP_PLATFORM.toString())) {
+ String platform = platformCombo.getItem(platformCombo.getSelectionIndex());
+ attribute.setValue(platform);
+ } else if (key.equals(BugReportElement.TARGET_MILESTONE.toString())) {
+ int index = milestoneCombo.getSelectionIndex();
+ if(index >= 0) {
+ String milestone = milestoneCombo.getItem(milestoneCombo.getSelectionIndex());
+ attribute.setValue(milestone);
+ }
+ } else if (key.equals(BugReportElement.COMPONENT.toString())) {
+ String component = componentCombo.getItem(componentCombo.getSelectionIndex());
+ attribute.setValue(component);
+ } else if (key.equals(BugReportElement.PRIORITY.toString())) {
+ String priority = priorityCombo.getItem(priorityCombo.getSelectionIndex());
+ attribute.setValue(priority);
+ } else if (key.equals(BugReportElement.BUG_FILE_LOC.toString())) {
+ String url = urlText.getText();
+ if (url.equalsIgnoreCase("http://"))
+ url = "";
+ attribute.setValue(url);
+ } else if (key.equals(BugReportElement.ASSIGNED_TO.toString())) {
+ String assignTo = assignedToText.getText();
+ attribute.setValue(assignTo);
+ } else {
+ // do nothing
+ }
+ } catch (IllegalArgumentException e) {
+ MylarStatusHandler.fail(e, "could not set attribute: " + attribute, false);
+ }
+ }
+ // wizard.attributeCompleted = true;
+ }
+
+ @Override
+ protected void setControl(Control c) {
+ super.setControl(c);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ public void createControl(Composite parent) {
+ // whether the priority exists or not
+ boolean priExist = false;
+ boolean mileExist = false;
+
+ String url = null;
+
+ // get the model for the new bug
+ AbstractBugWizard wizard = (AbstractBugWizard) getWizard();
+ NewBugModel nbm = wizard.model;
+
+ // Set the current platform and OS on the model
+ setPlatformOptions(nbm);
+
+ // Attributes Composite- this holds all the combo fields and text
+ // fields
+ Composite attributesComposite = new Composite(parent, SWT.NONE);
+ GridLayout attributesLayout = new GridLayout();
+ attributesLayout.numColumns = 4;
+ attributesLayout.horizontalSpacing = 14;
+ attributesLayout.verticalSpacing = 6;
+ attributesLayout.makeColumnsEqualWidth = false;
+ attributesComposite.setLayout(attributesLayout);
+
+ GridData attributesData = new GridData(GridData.FILL_BOTH);
+ attributesData.horizontalSpan = 1;
+ attributesData.grabExcessVerticalSpace = false;
+ attributesComposite.setLayoutData(attributesData);
+ // End Attributes Composite
+
+ GridLayout attributesTitleLayout = new GridLayout();
+ attributesTitleLayout.horizontalSpacing = 0;
+ attributesTitleLayout.marginWidth = 0;
+
+ GridData attributesTitleData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ attributesTitleData.horizontalSpan = 4;
+
+ attributesTitleData.grabExcessVerticalSpace = false;
+
+ // Add the product to the composite
+ newLayout(attributesComposite, 1, "Product", PROPERTY);
+ newLayout(attributesComposite, 1, nbm.getProduct(), VALUE);
+
+ // Populate Attributes
+ for (Iterator<Attribute> it = nbm.getAttributes().iterator(); it.hasNext();) {
+ Attribute attribute = it.next();
+ String key = attribute.getParameterName();
+ String name = attribute.getName();
+ String value = checkText(attribute.getValue());
+ Map<String, String> values = attribute.getOptionValues();
+
+ // if it is a hidden field, don't try to display it
+ if (attribute.isHidden())
+ continue;
+
+ if (key == null)
+ key = "";
+
+ if (values == null)
+ values = new HashMap<String, String>();
+
+ GridData data = new GridData(GridData.BEGINNING);
+ data.horizontalSpan = 1;
+ data.horizontalIndent = HORZ_INDENT;
+ data.widthHint = 150;
+ // create and populate the combo fields for the attributes
+ if (key.equals(BugReportElement.OP_SYS.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+ oSCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY);
+
+ oSCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ oSCombo.add(a[i]);
+ }
+ int index;
+ if ((index = oSCombo.indexOf(value)) == -1)
+ index = 0;
+ oSCombo.select(index);
+ oSCombo.addListener(SWT.Modify, this);
+ } else if (key.equals(BugReportElement.VERSION.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+
+ versionCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+
+ versionCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ versionCombo.add(a[i]);
+ }
+ int index;
+ if ((index = versionCombo.indexOf(value)) == -1)
+ index = 0;
+ versionCombo.select(index);
+ versionCombo.addListener(SWT.Modify, this);
+ } else if (key.equals(BugReportElement.BUG_SEVERITY.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+ severityCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+
+ severityCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ severityCombo.add(a[i]);
+ }
+ int index;
+ if ((index = severityCombo.indexOf(value)) == -1)
+ index = 0;
+ severityCombo.select(index);
+ severityCombo.addListener(SWT.Modify, this);
+
+ } else if (key.equals(BugReportElement.REP_PLATFORM.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+ platformCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+
+ platformCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ platformCombo.add(a[i]);
+ }
+ int index;
+ if ((index = platformCombo.indexOf(value)) == -1)
+ index = 0;
+ platformCombo.select(index);
+ platformCombo.addListener(SWT.Modify, this);
+ } else if (key.equals(BugReportElement.TARGET_MILESTONE.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+ milestoneCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+ milestoneCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ milestoneCombo.add(a[i]);
+ }
+ int index;
+ if ((index = milestoneCombo.indexOf(value)) == -1)
+ index = 0;
+ milestoneCombo.select(index);
+ milestoneCombo.addListener(SWT.Modify, this);
+ //if(s.isEmpty()) milestoneCombo.setEnabled(false);
+ mileExist = true;
+ } else if (key.equals(BugReportElement.COMPONENT.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+ componentCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+
+ componentCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ componentCombo.add(a[i]);
+ }
+ int index;
+ if ((index = componentCombo.indexOf(value)) == -1)
+ index = 0;
+ componentCombo.select(index);
+ componentCombo.addListener(SWT.Modify, this);
+ } else if (key.equals(BugReportElement.PRIORITY.getKeyString())) {
+ newLayout(attributesComposite, 1, name, PROPERTY);
+ priorityCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ | SWT.READ_ONLY);
+
+ priorityCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ priorityCombo.add(a[i]);
+ }
+ int index;
+ if ((index = priorityCombo.indexOf(value)) == -1)
+ index = 0;
+ priorityCombo.select(index);
+ priorityCombo.addListener(SWT.Modify, this);
+ priExist = true;
+ } else if (key.equals(BugReportElement.BUG_FILE_LOC.getKeyString())) {
+ url = value;
+ } else {
+ // do nothing if it isn't a standard value to change
+ }
+ }
+
+ if (priExist && !mileExist) {
+ newLayout(attributesComposite, 1, "", PROPERTY);
+ newLayout(attributesComposite, 1, "", PROPERTY);
+ }
+
+ Composite textComposite = new Composite(attributesComposite, SWT.NONE);
+ textComposite.setLayout(new GridLayout(3, false));
+ GridData textCompositeGD = new GridData();
+ textCompositeGD.horizontalSpan = 4;
+ textCompositeGD.grabExcessHorizontalSpace = true;
+ textComposite.setLayoutData(textCompositeGD);
+
+
+ GridData urlTextData;
+ if (url != null) {
+ newLayout(textComposite, 1, BugReportElement.BUG_FILE_LOC.toString(), PROPERTY);
+ urlText = new Text(textComposite, SWT.BORDER | SWT.SINGLE | SWT.WRAP);
+ urlTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+
+ urlTextData.horizontalSpan = 2;
+ // summaryTextData.widthHint = 200;
+ urlText.setLayoutData(urlTextData);
+ urlText.setText(url);
+ urlText.addListener(SWT.FocusOut, this);
+ }
+
+ GridData summaryTextData;
+ newLayout(textComposite, 1, BugReportElement.ASSIGNED_TO.toString(), PROPERTY);
+ Label l = new Label(textComposite, SWT.NONE);
+ l.setText("(if email is incorrect submit will not proceed)");
+ summaryTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ summaryTextData.horizontalSpan = 1;
+ l.setLayoutData(summaryTextData);
+ assignedToText = new Text(textComposite, SWT.BORDER | SWT.SINGLE | SWT.WRAP);
+ summaryTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+
+ summaryTextData.horizontalSpan = 1;
+ summaryTextData.widthHint = 200;
+ assignedToText.setLayoutData(summaryTextData);
+ assignedToText.setText("");
+
+ // add the summary text field
+ newLayout(textComposite, 1, BugReportElement.SHORT_DESC.toString(), PROPERTY);
+ summaryText = new Text(textComposite, SWT.BORDER | SWT.SINGLE | SWT.WRAP);
+ summaryTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+
+ summaryTextData.horizontalSpan = 2;
+ summaryTextData.widthHint = 200;
+ summaryText.setLayoutData(summaryTextData);
+ summaryText.setText(nbm.getSummary());
+ summaryText.addListener(SWT.Modify, this);
+
+ // Description Text
+ Composite descriptionComposite = new Composite(attributesComposite, SWT.NONE);
+
+ descriptionComposite.setLayout(attributesTitleLayout);
+
+ GridData descriptionData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ descriptionData.horizontalSpan = 4;
+ descriptionData.grabExcessVerticalSpace = false;
+ descriptionComposite.setLayoutData(descriptionData);
+ newLayout(descriptionComposite, 4, "Description:", HEADER);
+
+ // add the description text field
+ descriptionText = new Text(attributesComposite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.WRAP);
+
+ descriptionText.setFont(AbstractBugEditor.COMMENT_FONT);
+ GridData descriptionTextData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ descriptionTextData.horizontalSpan = 4;
+ descriptionTextData.widthHint = AbstractBugEditor.DESCRIPTION_WIDTH;
+ descriptionTextData.heightHint = AbstractBugEditor.DESCRIPTION_HEIGHT;
+ descriptionText.setLayoutData(descriptionTextData);
+ descriptionText.addListener(SWT.Modify, this);
+
+ // serverButton = new Button(attributesComposite, SWT.RADIO);
+ // serverButton.setText("Submit bug report to the server.");
+ // GridData toServerButtonData = new
+ // GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // toServerButtonData.horizontalSpan = 4;
+ // serverButton.setLayoutData(toServerButtonData);
+ // serverButton.setSelection(true);
+ //
+ // offlineButton = new Button(attributesComposite, SWT.RADIO);
+ // offlineButton.setText("Save bug report offline.");
+ // GridData offlineButtonData = new
+ // GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // offlineButtonData.horizontalSpan = 4;
+ // offlineButton.setLayoutData(offlineButtonData);
+ // offlineButton.setSelection(false);
+
+ // if (wizard.fromDialog)
+ // offlineButton.setEnabled(false);
+
+ setControl(attributesComposite);
+ return;
+ }
+
+ // /**
+ // * @return <code>true</code> if the radio button to submit the bug to the
+ // * server is selected.
+ // */
+ // public boolean serverSelected() {
+ // return (serverButton == null) ? false : serverButton.getSelection();
+ // }
+ //
+ // /**
+ // * @return <code>true</code> if the radio button to save the bug offline
+ // * is selected.
+ // */
+ // public boolean offlineSelected() {
+ // return (offlineButton == null) ? false : offlineButton.getSelection();
+ // }
+
+ /*
+ * The following are Bugzilla's: OS's All AIX Windows 95 Windows 98 Windows
+ * CE Windows Mobile 2003 Windows Mobile 2005 Windows ME Windows 2000
+ * Windows NT Windows XP Windows 2003 Server Windows All MacOS X Linux
+ * Linux-GTK Linux-Motif HP-UX Neutrino QNX-Photon Solaris Solaris-GTK
+ * Solaris-Motif SymbianOS-Series 80 Unix All other
+ *
+ * The following are the platforsm in Bugzilla: All Macintosh PC Power PC
+ * Sun Other
+ *
+ * The following are Java's Archictures: [PA_RISC, ppc, sparc, x86, x86_64,
+ * ia64, ia64_32]
+ *
+ * The following are Java's OS's: [aix, hpux, linux, macosx, qnx, solaris,
+ * win32]
+ */
+ /**
+ * Sets the OS and Platform for the new bug
+ *
+ * @param newBugModel
+ * The bug to set the options for
+ */
+ public void setPlatformOptions(NewBugModel newBugModel) {
+ try {
+ // A Map from Java's OS and Platform to Buzilla's
+ Map<String, String> java2buzillaOSMap = new HashMap<String, String>();
+ Map<String, String> java2buzillaPlatformMap = new HashMap<String, String>();
+
+ java2buzillaPlatformMap.put("x86", "PC");
+ java2buzillaPlatformMap.put("x86_64", "PC");
+ java2buzillaPlatformMap.put("ia64", "PC");
+ java2buzillaPlatformMap.put("ia64_32", "PC");
+ java2buzillaPlatformMap.put("sparc", "Sun");
+ java2buzillaPlatformMap.put("ppc", "Power");
+
+ java2buzillaOSMap.put("aix", "AIX");
+ java2buzillaOSMap.put("hpux", "HP-UX");
+ java2buzillaOSMap.put("linux", "Linux");
+ java2buzillaOSMap.put("macosx", "MacOS X");
+ java2buzillaOSMap.put("qnx", "QNX-Photon");
+ java2buzillaOSMap.put("solaris", "Solaris");
+ java2buzillaOSMap.put("win32", "Windows All");
+
+ // Get OS Lookup Map
+ // Check that the result is in Values, if it is not, set it to other
+ Attribute opSysAttribute = newBugModel.getAttribute(BugReportElement.OP_SYS.toString());
+ Attribute platformAttribute = newBugModel.getAttribute(BugReportElement.REP_PLATFORM.toString());
+
+ String OS = Platform.getOS();
+ String platform = Platform.getOSArch();
+
+ String bugzillaOS = null; // Bugzilla String for OS
+ String bugzillaPlatform = null; // Bugzilla String for Platform
+
+ if (java2buzillaOSMap != null && java2buzillaOSMap.containsKey(OS) && opSysAttribute != null
+ && opSysAttribute.getOptionValues() != null) {
+ bugzillaOS = java2buzillaOSMap.get(OS);
+ if (opSysAttribute != null && !opSysAttribute.getOptionValues().values().contains(bugzillaOS)) {
+ // If the OS we found is not in the list of available
+ // options, set bugzillaOS
+ // to null, and just use "other"
+ bugzillaOS = null;
+ }
+ } else {
+ // If we have a strangeOS, then just set buzillaOS to null, and
+ // use "other"
+ bugzillaOS = null;
+ }
+
+ if (platform != null && java2buzillaPlatformMap.containsKey(platform)) {
+ bugzillaPlatform = java2buzillaPlatformMap.get(platform);
+
+ if (platformAttribute != null
+ && !platformAttribute.getOptionValues().values().contains(bugzillaPlatform)) {
+ // If the platform we found is not int the list of available
+ // optinos, set the
+ // Bugzilla Platform to null, and juse use "other"
+ bugzillaPlatform = null;
+ }
+ } else {
+ // If we have a strange platform, then just set bugzillaPatforrm
+ // to null, and use "other"
+ bugzillaPlatform = null;
+ }
+
+ // Set the OS and the Platform in the model
+ if (bugzillaOS != null && opSysAttribute != null)
+ opSysAttribute.setValue(bugzillaOS);
+ if (bugzillaPlatform != null && platformAttribute != null)
+ platformAttribute.setValue(bugzillaPlatform);
+
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, "could not set platform options", false);
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/BugzillaProductPage.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/BugzillaProductPage.java
new file mode 100644
index 000000000..d63e669bb
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/wizard/BugzillaProductPage.java
@@ -0,0 +1,260 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylar.internal.bugzilla.ui.wizard;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.internal.bugzilla.core.BugzillaRepositoryUtil;
+import org.eclipse.mylar.internal.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.internal.bugzilla.core.NewBugModel;
+import org.eclipse.mylar.internal.bugzilla.ui.BugzillaUiPlugin;
+import org.eclipse.mylar.internal.tasklist.ui.views.TaskRepositoriesView;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Shawn Minto
+ *
+ * The first page of the new bug wizard where the user chooses the bug's product
+ */
+public class BugzillaProductPage extends AbstractWizardListPage {
+
+ private static final String NEW_BUGZILLA_TASK_ERROR_TITLE = "New Bugzilla Task Error";
+
+ private static final String DESCRIPTION = "Pick a product on which to enter a bug.\n"
+ + "Press the Update button if you do not see the desired product.";
+
+ private static final String LABEL_UPDATE = "Update Products from Repository";
+
+ /** The list of products to submit a bug report for */
+ static List<String> products = null;
+
+ /**
+ * Reference to the bug wizard which created this page so we can create the
+ * second page
+ */
+ NewBugzillaReportWizard bugWizard;
+
+ /**
+ * String to hold previous product; determines if attribute option values
+ * need to be updated
+ */
+ private String prevProduct;
+
+ private final TaskRepository repository;
+
+ /**
+ * Constructor for BugzillaProductPage
+ *
+ * @param workbench
+ * The instance of the workbench
+ * @param bugWiz
+ * The bug wizard which created this page
+ * @param repository
+ * The repository the data is coming from
+ */
+ public BugzillaProductPage(IWorkbench workbench, NewBugzillaReportWizard bugWiz, TaskRepository repository) {
+ super("Page1", IBugzillaConstants.TITLE_NEW_BUG, DESCRIPTION, workbench);
+ this.bugWizard = bugWiz;
+ this.repository = repository;
+ setImageDescriptor(BugzillaUiPlugin.imageDescriptorFromPlugin("org.eclipse.mylar.bugzilla.ui",
+ "icons/wizban/bug-wizard.gif"));
+ }
+
+ protected ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(BugzillaPlugin.getDefault()
+ .getWorkbench().getActiveWorkbenchWindow().getShell());
+
+ protected IPreferenceStore prefs = BugzillaPlugin.getDefault().getPreferenceStore();
+
+ @Override
+ public void createAdditionalControls(Composite parent) {
+ Button updateButton = new Button(parent, SWT.LEFT | SWT.PUSH);
+ updateButton.setText(LABEL_UPDATE);
+
+ updateButton.setLayoutData(new GridData());
+
+ updateButton.addMouseListener(new MouseAdapter() {
+
+