Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorspingel2010-02-26 20:59:37 +0000
committerspingel2010-02-26 20:59:37 +0000
commitbb5338f9e590a61562eda85cebc636f194b5f39f (patch)
tree600ff45fd0e49b8ed596fb1c908eabed1b77f4cc /org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui
parentf67d195914c9eb65d11ef17af5015bf70b1dada4 (diff)
downloadorg.eclipse.mylyn.tasks-bb5338f9e590a61562eda85cebc636f194b5f39f.tar.gz
org.eclipse.mylyn.tasks-bb5338f9e590a61562eda85cebc636f194b5f39f.tar.xz
org.eclipse.mylyn.tasks-bb5338f9e590a61562eda85cebc636f194b5f39f.zip
bug 304086: [api] decouple tasks.ui from org.eclipse.search
https://bugs.eclipse.org/bugs/show_bug.cgi?id=304086
Diffstat (limited to 'org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui')
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/TaskSearchPage.java646
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/actions/OpenTaskSearchAction.java53
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/messages.properties86
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/CreateQueryFromSearchAction.java91
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/Messages.java71
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/OpenSearchResultAction.java64
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResult.java97
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResultView.java431
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchHitCollector.java138
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultContentProvider.java63
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSortAction.java38
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSorter.java50
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultTreeContentProvider.java144
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultsLabelProvider.java67
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchScoreComputerAdapterFactory.java55
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/StackTraceDuplicateDetector.java111
-rw-r--r--org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/messages.properties36
17 files changed, 2241 insertions, 0 deletions
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/TaskSearchPage.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/TaskSearchPage.java
new file mode 100644
index 000000000..4f1b0a3b9
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/TaskSearchPage.java
@@ -0,0 +1,646 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.mylyn.commons.core.StatusHandler;
+import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages;
+import org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager;
+import org.eclipse.mylyn.internal.tasks.ui.search.SearchHitCollector;
+import org.eclipse.mylyn.internal.tasks.ui.views.TaskListView;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi;
+import org.eclipse.mylyn.tasks.ui.TasksUi;
+import org.eclipse.mylyn.tasks.ui.TasksUiUtil;
+import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage;
+import org.eclipse.mylyn.tasks.ui.wizards.ITaskSearchPage;
+import org.eclipse.mylyn.tasks.ui.wizards.ITaskSearchPageContainer;
+import org.eclipse.search.internal.ui.SearchPlugin;
+import org.eclipse.search.ui.ISearchPage;
+import org.eclipse.search.ui.ISearchPageContainer;
+import org.eclipse.search.ui.ISearchQuery;
+import org.eclipse.search.ui.ISearchResultViewPart;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+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.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.eclipse.ui.forms.widgets.ImageHyperlink;
+
+/**
+ * @author Rob Elves
+ * @author Mik Kersten
+ * @author Steffen Pingel
+ */
+public class TaskSearchPage extends DialogPage implements ISearchPage {
+
+ public static final String ID = "org.eclipse.mylyn.tasks.ui.search.page"; //$NON-NLS-1$
+
+ private static final String PAGE_KEY = "page"; //$NON-NLS-1$
+
+ private static final String PAGE_NAME = "TaskSearchPage"; //$NON-NLS-1$
+
+ private static final String STORE_REPO_ID = PAGE_NAME + ".REPO"; //$NON-NLS-1$
+
+ private Combo repositoryCombo;
+
+ private Text keyText;
+
+ private TaskRepository repository;
+
+ private Composite fParentComposite;
+
+ private IDialogSettings fDialogSettings;
+
+ private int currentPageIndex = -1;
+
+ private boolean firstView = true;
+
+ private Control[] queryPages;
+
+ private ISearchPageContainer pageContainer;
+
+ private ITaskSearchPageContainer taskSearchPageContainer;
+
+ public boolean performAction() {
+ saveDialogSettings();
+ String key = keyText.getText();
+ if (key != null && key.trim().length() > 0) {
+ key = key.trim();
+ boolean openSuccessful = TasksUiUtil.openTask(repository, key);
+ if (!openSuccessful) {
+ MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ Messages.TaskSearchPage_Task_Search, Messages.TaskSearchPage_No_task_found_matching_key_ + key);
+ }
+ return openSuccessful;
+ } else {
+ ITaskSearchPage page = (ITaskSearchPage) queryPages[currentPageIndex].getData(PAGE_KEY);
+ return page.performSearch();
+ }
+ }
+
+ public void setContainer(ISearchPageContainer container) {
+ this.pageContainer = container;
+ this.taskSearchPageContainer = new ITaskSearchPageContainer() {
+ public IRunnableContext getRunnableContext() {
+ return pageContainer.getRunnableContext();
+ }
+
+ public void setPerformActionEnabled(boolean enabled) {
+ pageContainer.setPerformActionEnabled(enabled);
+ }
+ };
+ }
+
+ public void createControl(Composite parent) {
+ fParentComposite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, false);
+ // layout.marginHeight = 0;
+ // layout.marginWidth = 0;
+ fParentComposite.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ fParentComposite.setLayoutData(gd);
+
+ createRepositoryGroup(fParentComposite);
+ createSeparator(fParentComposite);
+ this.setControl(fParentComposite);
+
+ Dialog.applyDialogFont(fParentComposite);
+ }
+
+ private void createSeparator(Composite parent) {
+ Label separator = new Label(parent, SWT.NONE);
+ separator.setVisible(false);
+ GridData data = new GridData(GridData.FILL, GridData.FILL, false, false, 2, 1);
+ data.heightHint = convertHeightInCharsToPixels(1) / 3;
+ separator.setLayoutData(data);
+ }
+
+ private void createRepositoryGroup(Composite control) {
+ Composite group = new Composite(control, SWT.NONE);
+ GridLayout layout = new GridLayout(6, false);
+ group.setLayout(layout);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ group.setLayoutData(gd);
+
+ Label label = new Label(group, SWT.NONE);
+ label.setText(Messages.TaskSearchPage_Select_Repository_);
+
+ repositoryCombo = new Combo(group, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
+ repositoryCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ displayQueryPage(repositoryCombo.getSelectionIndex());
+ }
+ });
+ label = new Label(group, SWT.NONE);
+ label.setText(" "); //$NON-NLS-1$
+
+ Label labelKey = new Label(group, SWT.NONE);
+ labelKey.setText(Messages.TaskSearchPage_Task_Key_ID);
+ keyText = new Text(group, SWT.BORDER);
+ keyText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+ String findText = null;
+ TaskListView taskListView = TaskListView.getFromActivePerspective();
+ if (taskListView != null) {
+ findText = taskListView.getFilteredTree().getFilterControl().getText();
+ if (findText != null && findText.trim().length() > 0 && isTaskKeyCandidate(findText.trim())) {
+ pageContainer.setPerformActionEnabled(true);
+ keyText.setText(findText.trim());
+ keyText.setFocus();
+ }
+ }
+
+ keyText.addKeyListener(new KeyListener() {
+
+ public void keyPressed(KeyEvent e) {
+ // ignore
+ }
+
+ public void keyReleased(KeyEvent e) {
+ updatePageEnablement();
+ }
+ });
+
+ ImageHyperlink clearKey = new ImageHyperlink(group, SWT.NONE);
+ clearKey.setImage(CommonImages.getImage(CommonImages.REMOVE));
+ clearKey.addHyperlinkListener(new HyperlinkAdapter() {
+
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ keyText.setText(""); //$NON-NLS-1$
+ updatePageEnablement();
+ }
+ });
+ }
+
+ private void updatePageEnablement() {
+ if (keyText.getText() != null && keyText.getText().trim().length() > 0) {
+ //setControlsEnabled(queryPages[currentPageIndex], false);
+ if (queryPages != null && queryPages[currentPageIndex] != null
+ && queryPages[currentPageIndex].getData(PAGE_KEY) instanceof AbstractRepositoryQueryPage) {
+ ((AbstractRepositoryQueryPage) queryPages[currentPageIndex].getData(PAGE_KEY)).setControlsEnabled(false);
+ }
+ if (repositoryCombo.getSelectionIndex() > -1) {
+ pageContainer.setPerformActionEnabled(true);
+ }
+ } else {
+ //setControlsEnabled(queryPages[currentPageIndex], true);
+ if (queryPages != null && queryPages[currentPageIndex] != null
+ && queryPages[currentPageIndex].getData(PAGE_KEY) instanceof AbstractRepositoryQueryPage) {
+ ((AbstractRepositoryQueryPage) queryPages[currentPageIndex].getData(PAGE_KEY)).setControlsEnabled(true);
+ }
+ //setControlsEnabled(queryPages[currentPageIndex], true);
+ //pageContainer.setPerformActionEnabled(false);
+ }
+ }
+
+ private Control createPage(TaskRepository repository, ITaskSearchPage searchPage) {
+ // Page wrapper
+ final Composite pageWrapper = new Composite(fParentComposite, SWT.NONE);
+ pageWrapper.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ pageWrapper.setLayout(layout);
+
+ try {
+ searchPage.setContainer(taskSearchPageContainer);
+ searchPage.createControl(pageWrapper);
+ } catch (Exception e) {
+ pageWrapper.dispose();
+ searchPage.dispose();
+
+ searchPage = createErrorPage(repository, e);
+ return searchPage.getControl();
+ }
+
+ // XXX: work around for initial search page size issue bug#198493
+ IDialogSettings searchDialogSettings = SearchPlugin.getDefault().getDialogSettingsSection(
+ "DialogBounds_SearchDialog"); //$NON-NLS-1$
+ if (searchDialogSettings.get("DIALOG_WIDTH") == null) { //$NON-NLS-1$
+ fParentComposite.getParent().getShell().pack();
+ }
+ pageWrapper.setData(PAGE_KEY, searchPage);
+ return pageWrapper;
+ }
+
+ private ITaskSearchPage createErrorPage(TaskRepository repository, Throwable e) {
+ ITaskSearchPage searchPage;
+ Status status = new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN,
+ "Error occurred while constructing search page for " + repository.getRepositoryUrl() + " [" //$NON-NLS-1$ //$NON-NLS-2$
+ + repository.getConnectorKind() + "]", e);//$NON-NLS-1$
+ StatusHandler.log(status);
+
+ searchPage = new DeadSearchPage(repository, status);
+ searchPage.setContainer(taskSearchPageContainer);
+ searchPage.createControl(fParentComposite);
+ searchPage.getControl().setData(PAGE_KEY, searchPage);
+ return searchPage;
+ }
+
+ private void displayQueryPage(final int pageIndex) {
+ if (currentPageIndex == pageIndex || pageIndex < 0) {
+ return;
+ }
+
+ // TODO: if repository == null display invalid page?
+ if (currentPageIndex != -1 && queryPages[currentPageIndex] != null) {
+ queryPages[currentPageIndex].setVisible(false);
+ ITaskSearchPage page = (ITaskSearchPage) queryPages[currentPageIndex].getData(PAGE_KEY);
+ page.setVisible(false);
+ GridData data = (GridData) queryPages[currentPageIndex].getLayoutData();
+ data.exclude = true;
+ queryPages[currentPageIndex].setLayoutData(data);
+ }
+
+ String repositoryLabel = repositoryCombo.getItem(pageIndex);
+ repository = (TaskRepository) repositoryCombo.getData(repositoryLabel);
+
+ if (queryPages[pageIndex] == null) {
+ if (repository != null) {
+ final AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(repository.getConnectorKind());
+ if (connectorUi != null) {
+ SafeRunner.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ ITaskSearchPage searchPage = getSearchPage(connectorUi);
+ if (searchPage != null) {
+ queryPages[pageIndex] = createPage(repository, searchPage);
+ } else {
+ AbstractRepositoryConnector connector = TasksUi.getRepositoryManager()
+ .getRepositoryConnector(repository.getConnectorKind());
+ if (connector.canCreateTaskFromKey(repository)) {
+ queryPages[pageIndex] = createPage(repository, new NoSearchPage(repository));
+ }
+ }
+ }
+
+ public void handleException(Throwable e) {
+ ITaskSearchPage page = createErrorPage(repository, e);
+ queryPages[pageIndex] = page.getControl();
+ }
+ });
+ }
+
+ }
+ }
+
+ // update enablement of the task id field
+ if (repository != null) {
+ AbstractRepositoryConnector connector = TasksUi.getRepositoryManager().getRepositoryConnector(
+ repository.getConnectorKind());
+ if (connector.canCreateTaskFromKey(repository)) {
+ keyText.setEnabled(true);
+ } else {
+ keyText.setEnabled(false);
+ }
+ }
+
+ if (queryPages[pageIndex] != null) {
+ GridData data = (GridData) queryPages[pageIndex].getLayoutData();
+ if (data == null) {
+ data = new GridData();
+ }
+ data.exclude = false;
+ queryPages[pageIndex].setLayoutData(data);
+ queryPages[pageIndex].setVisible(true);
+ ITaskSearchPage page = (ITaskSearchPage) queryPages[pageIndex].getData(PAGE_KEY);
+ page.setVisible(true);
+ }
+
+ currentPageIndex = pageIndex;
+ fParentComposite.getParent().layout(true, true);
+ updatePageEnablement();
+
+ }
+
+ private ITaskSearchPage getSearchPage(AbstractRepositoryConnectorUi connectorUi) {
+ if (connectorUi.hasSearchPage()) {
+ return connectorUi.getSearchPage(repository, null);
+ }
+ return null;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (firstView) {
+ firstView = false;
+ getControl().setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
+
+ List<TaskRepository> repositories = TasksUi.getRepositoryManager().getAllRepositories();
+ List<TaskRepository> searchableRepositories = new ArrayList<TaskRepository>();
+ for (TaskRepository repository : repositories) {
+ AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(repository.getConnectorKind());
+ AbstractRepositoryConnector connector = TasksUi.getRepositoryManager().getRepositoryConnector(
+ repository.getConnectorKind());
+ if ((connectorUi != null && connectorUi.hasSearchPage() && !repository.isOffline())
+ || connector.canCreateTaskFromKey(repository)) {
+ searchableRepositories.add(repository);
+ }
+ }
+
+ Collections.sort(searchableRepositories, new TaskRepositoryComparator());
+
+ String[] repositoryUrls = new String[searchableRepositories.size()];
+ int i = 0;
+ int indexToSelect = 0;
+ for (TaskRepository currRepsitory : searchableRepositories) {
+ if (repository != null && repository.equals(currRepsitory)) {
+ indexToSelect = i;
+ }
+ repositoryUrls[i] = currRepsitory.getRepositoryUrl();
+ i++;
+ }
+
+ IDialogSettings settings = getDialogSettings();
+ if (repositoryCombo != null) {
+ for (int x = 0; x < searchableRepositories.size(); x++) {
+ repositoryCombo.add(searchableRepositories.get(x).getRepositoryLabel());
+ repositoryCombo.setData(searchableRepositories.get(x).getRepositoryLabel(),
+ searchableRepositories.get(x));
+ }
+ if (repositoryUrls.length == 0) {
+ MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
+ Messages.TaskSearchPage_Repository_Search, TaskRepositoryManager.MESSAGE_NO_REPOSITORY);
+ } else {
+ String selectRepo = settings.get(STORE_REPO_ID);
+ if (selectRepo != null && repositoryCombo.indexOf(selectRepo) > -1) {
+ repositoryCombo.select(repositoryCombo.indexOf(selectRepo));
+ repository = (TaskRepository) repositoryCombo.getData(selectRepo);
+ if (repository == null) {
+ // TODO: Display no repository error
+ }
+ } else {
+ repositoryCombo.select(indexToSelect);
+ }
+
+ // TODO: Create one page per connector and repopulate based on repository
+ queryPages = new Control[repositoryUrls.length];
+ displayQueryPage(repositoryCombo.getSelectionIndex());
+ // updateAttributesFromRepository(repositoryCombo.getText(),
+ // null, false);
+ }
+ }
+ }
+
+ if (queryPages == null) {
+ pageContainer.setPerformActionEnabled(false);
+ }
+
+ super.setVisible(visible);
+
+ setDefaultValuesAndFocus();
+ }
+
+ private void setDefaultValuesAndFocus() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ IWorkbenchPage page = window.getActivePage();
+ if (page != null) {
+ String repositoryUrl = null;
+ IWorkbenchPart part = page.getActivePart();
+ if (part instanceof ISearchResultViewPart) {
+ ISearchQuery[] queries = NewSearchUI.getQueries();
+ if (queries.length > 0) {
+ if (queries[0] instanceof SearchHitCollector) {
+ repositoryUrl = ((SearchHitCollector) queries[0]).getRepositoryQuery().getRepositoryUrl();
+ }
+ }
+ }
+// if (repositoryUrl == null) {
+// IEditorPart editor = page.getActiveEditor();
+// if (editor instanceof TaskEditor) {
+// repositoryUrl = ((TaskEditor) editor).getTaskEditorInput().getTask().getRepositoryUrl();
+// }
+// }
+// if (repositoryUrl == null) {
+// TaskListView taskListView = TaskListView.getFromActivePerspective();
+// if (taskListView != null) {
+// AbstractTask selectedTask = taskListView.getSelectedTask();
+// if (selectedTask != null) {
+// repositoryUrl = selectedTask.getRepositoryUrl();
+// }
+// }
+// }
+ if (repositoryUrl != null) {
+ TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(repositoryUrl);
+ if (repository != null) {
+ int index = 0;
+ for (String repositoryLabel : repositoryCombo.getItems()) {
+ if (repositoryLabel.equals(repository.getRepositoryLabel())) {
+ repositoryCombo.select(index);
+ }
+ index++;
+ }
+ displayQueryPage(repositoryCombo.getSelectionIndex());
+ }
+ }
+ }
+ }
+
+ if (keyText.getText() != null && keyText.getText().trim().length() > 0) {
+ keyText.setFocus();
+ keyText.setSelection(0, keyText.getText().length());
+ } else {
+ Clipboard clipboard = new Clipboard(Display.getDefault());
+ TextTransfer transfer = TextTransfer.getInstance();
+ String contents = (String) clipboard.getContents(transfer);
+ if (contents != null) {
+ if (isTaskKeyCandidate(contents.trim())) {
+ keyText.setText(contents.trim());
+ keyText.setFocus();
+ keyText.setSelection(0, keyText.getText().length());
+ }
+ }
+ }
+ updatePageEnablement();
+ }
+
+ private boolean isTaskKeyCandidate(String contents) {
+ boolean looksLikeKey = false;
+ try {
+ Integer.parseInt(contents);
+ looksLikeKey = true;
+ } catch (NumberFormatException nfe) {
+ }
+ if (!looksLikeKey) {
+ try {
+ Integer.parseInt(contents.substring(contents.lastIndexOf('-')));
+ looksLikeKey = true;
+ } catch (Exception e) {
+ }
+ }
+ return looksLikeKey;
+ }
+
+ public IDialogSettings getDialogSettings() {
+ IDialogSettings settings = TasksUiPlugin.getDefault().getDialogSettings();
+ fDialogSettings = settings.getSection(PAGE_NAME);
+ if (fDialogSettings == null) {
+ fDialogSettings = settings.addNewSection(PAGE_NAME);
+ }
+ return fDialogSettings;
+ }
+
+ private void saveDialogSettings() {
+ IDialogSettings settings = getDialogSettings();
+ settings.put(STORE_REPO_ID, repositoryCombo.getText());
+ }
+
+ @Override
+ public void dispose() {
+ if (queryPages != null) {
+ for (Control control : queryPages) {
+ if (control != null) {
+ ITaskSearchPage page = (ITaskSearchPage) control.getData(PAGE_KEY);
+ page.dispose();
+ }
+ }
+ }
+ super.dispose();
+ }
+
+ private class DeadSearchPage extends AbstractRepositoryQueryPage {
+
+ private final Status status;
+
+ public DeadSearchPage(TaskRepository rep, Status status) {
+ super("Search page error", rep); //$NON-NLS-1$
+ this.status = status;
+ }
+
+ public void createControl(Composite parent) {
+ Hyperlink hyperlink = new Hyperlink(parent, SWT.NONE);
+ hyperlink.setText(Messages.TaskSearchPage_ERROR_Unable_to_present_query_page);
+ hyperlink.setUnderlined(true);
+ hyperlink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ TaskSearchPage.this.getControl().getShell().close();
+ TasksUiUtil.openEditRepositoryWizard(getTaskRepository());
+ // TODO: Re-construct this page with new
+ // repository data
+ }
+
+ });
+
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(hyperlink);
+ setControl(hyperlink);
+ }
+
+ @Override
+ public IRepositoryQuery getQuery() {
+ return null;
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ return false;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible) {
+ getSearchContainer().setPerformActionEnabled(false);
+ }
+ }
+
+ @Override
+ public String getQueryTitle() {
+ return null;
+ }
+
+ @Override
+ public void applyTo(IRepositoryQuery query) {
+ // ignore
+ }
+
+ }
+
+ private class NoSearchPage extends AbstractRepositoryQueryPage {
+
+ public NoSearchPage(TaskRepository rep) {
+ super("No search page", rep); //$NON-NLS-1$
+ }
+
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout());
+ Dialog.applyDialogFont(composite);
+ setControl(composite);
+ }
+
+ @Override
+ public IRepositoryQuery getQuery() {
+ return null;
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ return false;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (visible) {
+ getSearchContainer().setPerformActionEnabled(false);
+ }
+ }
+
+ @Override
+ public String getQueryTitle() {
+ return null;
+ }
+
+ @Override
+ public void applyTo(IRepositoryQuery query) {
+ // ignore
+ }
+
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/actions/OpenTaskSearchAction.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/actions/OpenTaskSearchAction.java
new file mode 100644
index 000000000..0c6f858b6
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/actions/OpenTaskSearchAction.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.mylyn.internal.tasks.ui.TaskSearchPage;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Mik Kersten
+ * @author Steffen Pingel
+ */
+public class OpenTaskSearchAction extends Action implements IViewActionDelegate {
+
+ public OpenTaskSearchAction() {
+ }
+
+ public void init(IViewPart view) {
+ // ignore
+ }
+
+ @Override
+ public void run() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ NewSearchUI.openSearchDialog(window, TaskSearchPage.ID);
+ }
+ }
+
+ public void run(IAction action) {
+ run();
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ // ignore
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/messages.properties b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/messages.properties
new file mode 100644
index 000000000..6cfd0b7de
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/messages.properties
@@ -0,0 +1,86 @@
+###############################################################################
+# Copyright (c) 2009 Tasktop Technologies 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:
+# Tasktop Technologies - initial API and implementation
+###############################################################################
+ActiveContextExternalizationParticipant_Active_Task_Context=Active Task Context
+ActivityExternalizationParticipant_Activity_Context=Activity Context
+
+ChangeActivityHandleOperation_Activity_migration=Activity migration
+
+DialogErrorReporter_Mylyn_Error=Mylyn Error
+DialogErrorReporter_Please_report_the_following_error_at=Please report the following error at:\n\
+\n\
+http://bugs.eclipse.org/bugs/enter_bug.cgi?product=Mylyn\n\
+\n\
+Or via the popup menu in the Error Log view (see Window -> Show View)
+
+MoveToCategoryMenuContributor_Move_to=Move to
+
+OpenRepositoryTaskJob_Could_not_find_repository_configuration_for_X=Could not find repository configuration for {0}.
+OpenRepositoryTaskJob_Opening_Remote_Task=Opening Remote Task
+OpenRepositoryTaskJob_Opening_repository_task_X=Opening repository task {0}
+OpenRepositoryTaskJob_Please_set_up_repository_via_X=Please set up repository via {0}.
+OpenRepositoryTaskJob_Repository_Not_Found=Repository Not Found
+OpenRepositoryTaskJob_Unable_to_open_task=Unable to open task
+
+RefactorRepositoryUrlOperation_Repository_URL_update=Repository URL update
+
+ScheduleDatePicker_Clear=Clear
+ScheduleTaskMenuContributor_Cannot_schedule_completed_tasks=Cannot schedule completed tasks
+ScheduleTaskMenuContributor_Choose_Date_=Choose Date...
+ScheduleTaskMenuContributor_Future=Future
+ScheduleTaskMenuContributor_Not_Scheduled=Not Scheduled
+ScheduleTaskMenuContributor_Schedule_for=Schedule for
+
+TaskActivationExternalizationParticipant_Task_Activation_History=Task Activation History
+TaskHistoryDropDown_Activate_Task_=Activate Task...
+TaskHistoryDropDown_Deactivate_Task=Deactivate Task
+
+TaskJobFactory_Receiving_configuration=Receiving configuration
+TaskJobFactory_Refreshing_repository_configuration=Refreshing repository configuration
+
+TaskListBackupManager_Error_occured_during_scheduled_tasklist_backup=Error occured during scheduled tasklist backup.\nCheck settings on Tasklist preferences page.
+TaskListBackupManager_Scheduled_task_data_backup=Scheduled task data backup
+
+TaskListNotificationManager_Open_Notification_Job=Open Notification Job
+
+TaskRepositoryLocationUi_Enter_HTTP_password=Enter HTTP password
+TaskRepositoryLocationUi_Enter_proxy_password=Enter proxy password
+TaskRepositoryLocationUi_Enter_repository_password=Enter repository password
+
+TaskSearchPage_ERROR_Unable_to_present_query_page=ERROR: Unable to present query page, ensure repository configuration is valid and retry
+
+TaskSearchPage_No_task_found_matching_key_=No task found matching key:
+TaskSearchPage_Repository_Search=Repository Search
+TaskSearchPage_Select_Repository_=Se&lect Repository:
+TaskSearchPage_Task_Key_ID=Task Key/ID:
+TaskSearchPage_Task_Search=Task Search
+
+TasksReminderDialog_Description=Description
+TasksReminderDialog_Dismiss_All=Dismiss All
+TasksReminderDialog_Dismiss_Selected=Dismiss Selected
+TasksReminderDialog_Priority=Priority
+TasksReminderDialog_Remind_tommorrow=Remind tomorrow
+TasksReminderDialog_Reminder_Day=Reminder Day
+TasksReminderDialog_Reminders=Reminders
+
+TasksUiPlugin_Initializing_Task_List=Initializing Task List
+TasksUiPlugin_Task_Repositories=Task Repositories
+TasksUiPlugin_Load_Data_Directory=Load Data Directory
+
+TaskTrimWidget__no_active_task_=<no active task>
+TaskTrimWidget__no_task_active_=<no task active>
+
+AbstractRepositoryConnectorUi_Task=Task
+
+TaskElementLabelProvider__no_summary_available_=: <no summary available>
+TaskHyperlink_Could_not_determine_repository_for_report=Could not determine repository for report
+TaskHyperlink_Open_Task_X_in_X=Open Task {0} in {1}
+
+AbstractRetrieveTitleFromUrlJob_Retrieving_summary_from_URL=Retrieving summary from URL
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/CreateQueryFromSearchAction.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/CreateQueryFromSearchAction.java
new file mode 100644
index 000000000..cd9dcbb1c
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/CreateQueryFromSearchAction.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Balazs Brinkus - initial API and implementation
+ * Tasktop Technologies - improvements
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.mylyn.internal.tasks.core.RepositoryQuery;
+import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
+import org.eclipse.mylyn.internal.tasks.ui.views.TaskListView;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.ui.TasksUi;
+import org.eclipse.mylyn.tasks.ui.TasksUiImages;
+import org.eclipse.search.ui.ISearchQuery;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Used for add the last search result to the Task List.
+ *
+ * @author Balazs Brinkus (bug 172699)
+ * @author Mik Kersten
+ */
+public class CreateQueryFromSearchAction extends Action {
+
+ /** The view this action works on */
+ private final RepositorySearchResultView resultView;
+
+ /**
+ * Constructor
+ *
+ * @param text
+ * The text for this action
+ * @param resultView
+ * The <code>RepositorySearchResultView</code> this action works on
+ */
+ public CreateQueryFromSearchAction(String text, RepositorySearchResultView resultView) {
+ setText(text);
+ setImageDescriptor(TasksUiImages.QUERY_NEW);
+ this.resultView = resultView;
+ }
+
+ /**
+ * Add the search result to the Task List.
+ */
+ @Override
+ public void run() {
+ ISelection selection = resultView.getViewer().getSelection();
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+ if (structuredSelection.getFirstElement() instanceof ITask) {
+ ISearchQuery[] queries = NewSearchUI.getQueries();
+ ITask task = (ITask) structuredSelection.getFirstElement();
+ AbstractRepositoryConnector connector = TasksUi.getRepositoryManager().getRepositoryConnector(
+ task.getConnectorKind());
+ if (queries.length != 0 && connector != null) {
+ SearchHitCollector searchHitCollector = (SearchHitCollector) queries[0];
+ IRepositoryQuery query = searchHitCollector.getRepositoryQuery();
+ InputDialog dialog = new InputDialog(PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow()
+ .getShell(), Messages.CreateQueryFromSearchAction_CLEAR_QUERY, MessageFormat.format(
+ Messages.CreateQueryFromSearchAction_Name_of_query_to_be_added_to_the_X, TaskListView.LABEL_VIEW)
+ + ": ", "", null); //$NON-NLS-1$ //$NON-NLS-2$
+ int dialogResult = dialog.open();
+ if (dialogResult == Window.OK) {
+ query.setSummary(dialog.getValue());
+ TasksUiInternal.getTaskList().addQuery((RepositoryQuery) query);
+ TasksUiInternal.synchronizeQuery(connector, (RepositoryQuery) query, null, true);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/Messages.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/Messages.java
new file mode 100644
index 000000000..2aa243994
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/Messages.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.tasks.ui.search.messages"; //$NON-NLS-1$
+
+ static {
+ // load message values from bundle file
+ reloadMessages();
+ }
+
+ public static void reloadMessages() {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ public static String CreateQueryFromSearchAction_CLEAR_QUERY;
+
+ public static String CreateQueryFromSearchAction_Name_of_query_to_be_added_to_the_X;
+
+ public static String RepositorySearchResult_Task_search_X_matches;
+
+ public static String RepositorySearchResult_Task_search_1_match;
+
+ public static String RepositorySearchResultView_Add_to_X_Category;
+
+ public static String RepositorySearchResultView_Create_Query_from_Search_;
+
+ public static String RepositorySearchResultView_Filter_Completed_Tasks;
+
+ public static String RepositorySearchResultView_Group_By_Owner;
+
+ public static String RepositorySearchResultView_Open_in_Editor;
+
+ public static String RepositorySearchResultView_Open_Search_with_Browser_Label;
+
+ public static String RepositorySearchResultView_Refine_Search_;
+
+ public static String SearchHitCollector_Max_allowed_number_of_hits_returned_exceeded;
+
+ public static String SearchHitCollector_Querying_Repository_;
+
+ public static String SearchHitCollector_Repository_connector_could_not_be_found;
+
+ public static String SearchHitCollector_Search_failed;
+
+ public static String SearchHitCollector_Search_cancelled;
+
+ public static String SearchHitCollector_Search_returned_maximum_number_of_hits;
+
+ public static String SearchResultsLabelProvider_OF;
+
+ public static String SearchResultTreeContentProvider_Complete;
+
+ public static String SearchResultTreeContentProvider_Incomplete;
+
+ public static String SearchResultTreeContentProvider__unknown_;
+
+ public static String SearchResultSortAction_Sort_Label;
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/OpenSearchResultAction.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/OpenSearchResultAction.java
new file mode 100644
index 000000000..99b007a01
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/OpenSearchResultAction.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
+import org.eclipse.mylyn.tasks.ui.TasksUiUtil;
+
+/**
+ * This class is used to open a bug report in an editor.
+ */
+public class OpenSearchResultAction extends Action {
+
+ /** The view this action works on */
+ private final RepositorySearchResultView resultView;
+
+ /**
+ * Constructor
+ *
+ * @param text
+ * The text for this action
+ * @param resultView
+ * The <code>RepositorySearchResultView</code> this action works on
+ */
+ public OpenSearchResultAction(String text, RepositorySearchResultView resultView) {
+ setText(text);
+ this.resultView = resultView;
+ }
+
+ /**
+ * Open the selected bug reports in their own editors.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void run() {
+ // Get the selected items
+ ISelection s = resultView.getViewer().getSelection();
+ if (s instanceof IStructuredSelection) {
+ IStructuredSelection selection = (IStructuredSelection) s;
+
+ // go through each of the selected items and show it in an editor
+ for (Iterator<AbstractTask> it = selection.iterator(); it.hasNext();) {
+ AbstractTask repositoryHit = it.next();
+ TasksUiUtil.openTask(repositoryHit.getRepositoryUrl(), repositoryHit.getTaskId(),
+ repositoryHit.getUrl());
+ }
+
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResult.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResult.java
new file mode 100644
index 000000000..4de34d9ca
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResult.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.search.internal.ui.SearchPluginImages;
+import org.eclipse.search.ui.ISearchQuery;
+import org.eclipse.search.ui.text.AbstractTextSearchResult;
+import org.eclipse.search.ui.text.IEditorMatchAdapter;
+import org.eclipse.search.ui.text.IFileMatchAdapter;
+
+/**
+ * Captures the results of a task repository search.
+ *
+ * @author Rob Elves
+ * @see org.eclipse.search.ui.text.AbstractTextSearchResult
+ * @since 2.0
+ */
+public class RepositorySearchResult extends AbstractTextSearchResult {
+
+ /**
+ * The query producing this result.
+ */
+ private final ISearchQuery repositoryQuery;
+
+ /**
+ * Constructor for <code>RepositorySearchResult</code> class.
+ *
+ * @param query
+ * <code>AbstractRepositorySearchQuery</code> that is producing this result.
+ */
+ public RepositorySearchResult(ISearchQuery query) {
+ repositoryQuery = query;
+ }
+
+ @Override
+ public IEditorMatchAdapter getEditorMatchAdapter() {
+ return null;
+ }
+
+ /**
+ * This function always returns <code>null</code>, as the matches for this implementation of
+ * <code>AbstractTextSearchResult</code> never contain files.
+ *
+ * @see org.eclipse.search.ui.text.AbstractTextSearchResult#getFileMatchAdapter()
+ */
+ @Override
+ public IFileMatchAdapter getFileMatchAdapter() {
+ return null;
+ }
+
+ public String getLabel() {
+ return getMatchCount() == 1 ? getSingularLabel() : getPluralLabel();
+ }
+
+ /**
+ * Get the singular label for the number of results
+ *
+ * @return The singular label
+ */
+ protected String getSingularLabel() {
+ return Messages.RepositorySearchResult_Task_search_1_match;
+ }
+
+ /**
+ * Get the plural label for the number of results
+ *
+ * @return The plural label
+ */
+ protected String getPluralLabel() {
+ return MessageFormat.format(Messages.RepositorySearchResult_Task_search_X_matches, getMatchCount());
+ }
+
+ public String getTooltip() {
+ return getLabel();
+ }
+
+ public ImageDescriptor getImageDescriptor() {
+ return SearchPluginImages.DESC_OBJ_TSEARCH_DPDN;
+ }
+
+ public ISearchQuery getQuery() {
+ return repositoryQuery;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResultView.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResultView.java
new file mode 100644
index 000000000..cb7487522
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/RepositorySearchResultView.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ * Frank Becker - improvements
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.DecoratingLabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.mylyn.internal.provisional.commons.ui.EnhancedFilteredTree;
+import org.eclipse.mylyn.internal.provisional.commons.ui.SubstringPatternFilter;
+import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
+import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory;
+import org.eclipse.mylyn.internal.tasks.core.TaskGroup;
+import org.eclipse.mylyn.internal.tasks.core.UnmatchedTaskContainer;
+import org.eclipse.mylyn.internal.tasks.ui.actions.OpenTaskSearchAction;
+import org.eclipse.mylyn.internal.tasks.ui.actions.OpenWithBrowserAction;
+import org.eclipse.mylyn.internal.tasks.ui.search.SearchResultTreeContentProvider.GroupBy;
+import org.eclipse.mylyn.internal.tasks.ui.util.TaskDragSourceListener;
+import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
+import org.eclipse.mylyn.internal.tasks.ui.views.TaskListToolTip;
+import org.eclipse.mylyn.internal.tasks.ui.views.TaskListView;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.ui.ITasksUiConstants;
+import org.eclipse.mylyn.tasks.ui.TasksUiImages;
+import org.eclipse.search.ui.IContextMenuConstants;
+import org.eclipse.search.ui.ISearchQuery;
+import org.eclipse.search.ui.ISearchResult;
+import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
+import org.eclipse.search.ui.text.Match;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.FileTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.part.IShowInTargetList;
+
+/**
+ * Displays the results of a Repository search.
+ *
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage
+ * @author Rob Elves
+ * @author Mik Kersten
+ * @author Shawn Minto
+ * @author Frank Becker
+ * @author Steffen Pingel
+ */
+public class RepositorySearchResultView extends AbstractTextSearchViewPage implements IAdaptable {
+
+ private class GroupingAction extends Action {
+
+ private final GroupBy groupBy;
+
+ public GroupingAction(String text, GroupBy groupBy) {
+ super(text, IAction.AS_CHECK_BOX);
+ this.groupBy = groupBy;
+ groupingActions.add(this);
+ }
+
+ @Override
+ public void run() {
+ for (GroupingAction action : groupingActions) {
+ action.setChecked(false);
+ }
+
+ SearchResultTreeContentProvider contentProvider = (SearchResultTreeContentProvider) getViewer().getContentProvider();
+ if (contentProvider.getSelectedGroup() == groupBy) {
+ contentProvider.setSelectedGroup(GroupBy.NONE);
+ } else {
+ contentProvider.setSelectedGroup(groupBy);
+ setChecked(true);
+ }
+ getViewer().refresh();
+ }
+ }
+
+ private class FilteringAction extends Action {
+
+ private final ViewerFilter filter;
+
+ public FilteringAction(String text, ViewerFilter filter) {
+ super(text, IAction.AS_CHECK_BOX);
+ this.filter = filter;
+ filterActions.add(this);
+ }
+
+ @Override
+ public void runWithEvent(Event event) {
+ if (isChecked()) {
+ getViewer().addFilter(filter);
+ } else {
+ getViewer().removeFilter(filter);
+ }
+ }
+ }
+
+ private static final String MEMENTO_KEY_SORT = "sort"; //$NON-NLS-1$
+
+ private SearchResultContentProvider searchResultProvider;
+
+ private final OpenSearchResultAction openInEditorAction;
+
+ private final CreateQueryFromSearchAction createQueryAction;
+
+ private final Action refineSearchAction;
+
+ private static final String[] SHOW_IN_TARGETS = new String[] { ITasksUiConstants.ID_VIEW_TASKS };
+
+ private TaskListToolTip toolTip;
+
+ private final List<GroupingAction> groupingActions;
+
+ private final List<FilteringAction> filterActions;
+
+ private final OpenWithBrowserAction openSearchWithBrowserAction;
+
+ private final SearchResultSorter searchResultSorter;
+
+ private SearchResultSortAction sortByDialogAction;
+
+ private static final IShowInTargetList SHOW_IN_TARGET_LIST = new IShowInTargetList() {
+ public String[] getShowInTargetIds() {
+ return SHOW_IN_TARGETS;
+ }
+ };
+
+ public RepositorySearchResultView() {
+ // Only use the table layout.
+ super(FLAG_LAYOUT_TREE);
+
+ openInEditorAction = new OpenSearchResultAction(Messages.RepositorySearchResultView_Open_in_Editor, this);
+ createQueryAction = new CreateQueryFromSearchAction(
+ Messages.RepositorySearchResultView_Create_Query_from_Search_, this);
+ refineSearchAction = new OpenTaskSearchAction();
+ refineSearchAction.setText(Messages.RepositorySearchResultView_Refine_Search_);
+ openSearchWithBrowserAction = new OpenWithBrowserAction();
+ openSearchWithBrowserAction.setText(Messages.RepositorySearchResultView_Open_Search_with_Browser_Label);
+
+ groupingActions = new ArrayList<GroupingAction>();
+ new GroupingAction(Messages.RepositorySearchResultView_Group_By_Owner, GroupBy.OWNER);
+// new GroupingAction(Messages.RepositorySearchResultView_Group_By_Complete, GroupBy.COMPLETION);
+
+ filterActions = new ArrayList<FilteringAction>();
+ new FilteringAction(Messages.RepositorySearchResultView_Filter_Completed_Tasks, new ViewerFilter() {
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof ITask) {
+ return !((ITask) element).isCompleted();
+ } else if (element instanceof TaskGroup) {
+ TaskGroup taskGroup = (TaskGroup) element;
+ return taskGroup.getHandleIdentifier().equals("group-incompleteIncomplete"); //$NON-NLS-1$
+ }
+ return true;
+ }
+ });
+
+ // construct early since to be ready when restoreState() is invoked
+ searchResultSorter = new SearchResultSorter();
+ }
+
+ @Override
+ protected void elementsChanged(Object[] objects) {
+ if (searchResultProvider != null) {
+ searchResultProvider.elementsChanged(objects);
+ getViewer().refresh();
+ }
+ }
+
+ @Override
+ protected void clear() {
+ if (searchResultProvider != null) {
+ searchResultProvider.clear();
+ getViewer().refresh();
+ }
+ }
+
+ // Allows the inherited method "getViewer" to be accessed publicly.
+ @Override
+ public StructuredViewer getViewer() {
+ return super.getViewer();
+ }
+
+ @Override
+ protected void configureTreeViewer(TreeViewer viewer) {
+ viewer.setUseHashlookup(true);
+ searchResultProvider = new SearchResultTreeContentProvider();
+ viewer.setContentProvider(searchResultProvider);
+
+ DecoratingLabelProvider labelProvider = new DecoratingLabelProvider(new SearchResultsLabelProvider(
+ searchResultProvider, viewer), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator());
+ viewer.setLabelProvider(labelProvider);
+ viewer.setSorter(searchResultSorter);
+
+ Transfer[] dragTypes = new Transfer[] { LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance() };
+
+ getViewer().addDragSupport(DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK, dragTypes,
+ new TaskDragSourceListener(getViewer()));
+
+ sortByDialogAction = new SearchResultSortAction(this);
+
+ toolTip = new TaskListToolTip(viewer.getControl());
+ }
+
+ @Override
+ protected TreeViewer createTreeViewer(Composite parent) {
+ // create a filtered tree
+ Composite treeComposite = parent;
+ Layout parentLayout = parent.getLayout();
+ if (!(parentLayout instanceof GridLayout)) {
+ treeComposite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ treeComposite.setLayout(layout);
+ }
+
+ FilteredTree searchTree = new EnhancedFilteredTree(treeComposite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL,
+ new SubstringPatternFilter(), true);
+ return searchTree.getViewer();
+ }
+
+ @Override
+ protected void configureTableViewer(TableViewer viewer) {
+// viewer.setUseHashlookup(true);
+// String[] columnNames = new String[] { "Summary" };
+// TableColumn[] columns = new TableColumn[columnNames.length];
+// int[] columnWidths = new int[] { 500 };
+// viewer.setColumnProperties(columnNames);
+//
+// viewer.getTable().setHeaderVisible(false);
+// for (int i = 0; i < columnNames.length; i++) {
+// columns[i] = new TableColumn(viewer.getTable(), 0, i); // SWT.LEFT
+// columns[i].setText(columnNames[i]);
+// columns[i].setWidth(columnWidths[i]);
+// columns[i].setData(new Integer(i));
+// columns[i].addSelectionListener(new SelectionAdapter() {
+//
+// @Override
+// public void widgetSelected(SelectionEvent e) {
+// TableColumn col = (TableColumn) e.getSource();
+// Integer integer = (Integer) col.getData();
+// setSortOrder(integer.intValue());
+// }
+// });
+// }
+//
+// IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
+// Color categoryBackground = themeManager.getCurrentTheme().getColorRegistry().get(
+// TaskListColorsAndFonts.THEME_COLOR_TASKLIST_CATEGORY);
+//
+// SearchViewTableLabelProvider taskListTableLabelProvider = new SearchViewTableLabelProvider(
+// new TaskElementLabelProvider(true),
+// PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(), categoryBackground);
+//
+// viewer.setLabelProvider(taskListTableLabelProvider);
+// viewer.setContentProvider(new SearchResultTableContentProvider(this));
+//
+// // Set the order when the search view is loading so that the items are
+// // sorted right away
+// setSortOrder(currentSortOrder);
+//
+// taskContentProvider = (SearchResultContentProvider) viewer.getContentProvider();
+ }
+
+ @Override
+ public void dispose() {
+ toolTip.dispose();
+ super.dispose();
+ }
+
+ @SuppressWarnings("rawtypes")
+ public Object getAdapter(Class adapter) {
+ return getAdapterDelegate(adapter);
+ }
+
+ private Object getAdapterDelegate(Class<?> adapter) {
+ if (IShowInTargetList.class.equals(adapter)) {
+ return SHOW_IN_TARGET_LIST;
+ }
+ return null;
+ }
+
+ @Override
+ protected void showMatch(Match match, int currentOffset, int currentLength, boolean activate)
+ throws PartInitException {
+ AbstractTask repositoryHit = (AbstractTask) match.getElement();
+ TasksUiInternal.refreshAndOpenTaskListElement(repositoryHit);
+ }
+
+ @Override
+ protected void fillContextMenu(IMenuManager menuManager) {
+ super.fillContextMenu(menuManager);
+
+ // open actions
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_OPEN, openInEditorAction);
+
+ // Add to Task List menu
+ // HACK: this should be a contribution
+ final MenuManager subMenuManager = new MenuManager(MessageFormat.format(
+ Messages.RepositorySearchResultView_Add_to_X_Category, TaskListView.LABEL_VIEW));
+ List<AbstractTaskCategory> categories = new ArrayList<AbstractTaskCategory>(TasksUiInternal.getTaskList()
+ .getCategories());
+ Collections.sort(categories);
+ for (final AbstractTaskCategory category : categories) {
+ if (!(category instanceof UnmatchedTaskContainer)) {//.equals(TasksUiPlugin.getTaskList().getArchiveContainer())) {
+ Action action = new Action() {
+ @Override
+ public void run() {
+ moveToCategory(category);
+ }
+ };
+ String text = category.getSummary();
+ action.setText(text);
+ action.setImageDescriptor(TasksUiImages.CATEGORY);
+ subMenuManager.add(action);
+ }
+ }
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_OPEN, subMenuManager);
+
+ // search actions
+
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_SEARCH, createQueryAction);
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_SEARCH, refineSearchAction);
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_SEARCH, openSearchWithBrowserAction);
+
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, sortByDialogAction);
+ for (Action action : groupingActions) {
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, action);
+ }
+ for (Action action : filterActions) {
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, action);
+ }
+
+ }
+
+ private void moveToCategory(AbstractTaskCategory category) {
+ StructuredSelection selection = (StructuredSelection) this.getViewer().getSelection();
+ for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) {
+ Object selectedObject = iterator.next();
+ if (selectedObject instanceof ITask) {
+ ITask task = (ITask) selectedObject;
+ TasksUiInternal.getTaskList().addTask(task, category);
+ }
+ }
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ super.createControl(parent);
+ IMenuManager menuManager = getSite().getActionBars().getMenuManager();
+ for (Action action : groupingActions) {
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, action);
+ }
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, new Separator());
+ for (Action action : filterActions) {
+ menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, action);
+ }
+ }
+
+ @Override
+ public void setInput(ISearchResult newSearch, Object viewState) {
+ super.setInput(newSearch, viewState);
+ if (newSearch != null) {
+ ISearchQuery query = ((RepositorySearchResult) newSearch).getQuery();
+ IRepositoryQuery repositoryQuery = ((SearchHitCollector) query).getRepositoryQuery();
+ openSearchWithBrowserAction.selectionChanged(new StructuredSelection(repositoryQuery));
+ } else {
+ openSearchWithBrowserAction.selectionChanged(StructuredSelection.EMPTY);
+ }
+ }
+
+ public SearchResultSorter getSorter() {
+ return searchResultSorter;
+ }
+
+ @Override
+ public void restoreState(IMemento memento) {
+ super.restoreState(memento);
+ if (memento != null) {
+ IMemento child = memento.getChild(MEMENTO_KEY_SORT);
+ if (child != null && searchResultSorter != null) {
+ searchResultSorter.getTaskComparator().restoreState(child);
+ }
+ }
+ }
+
+ @Override
+ public void saveState(IMemento memento) {
+ super.saveState(memento);
+ if (memento != null) {
+ IMemento child = memento.createChild(MEMENTO_KEY_SORT);
+ if (searchResultSorter != null) {
+ searchResultSorter.getTaskComparator().saveState(child);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchHitCollector.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchHitCollector.java
new file mode 100644
index 000000000..0da8723d9
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchHitCollector.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.commons.net.Policy;
+import org.eclipse.mylyn.internal.tasks.core.ITaskList;
+import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
+import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.core.RepositoryStatus;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
+import org.eclipse.mylyn.tasks.ui.TasksUi;
+import org.eclipse.search.ui.ISearchQuery;
+import org.eclipse.search.ui.ISearchResult;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.search.ui.text.Match;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Used for returning results from Eclipse Search view. Collects results of a repository search.
+ *
+ * @author Rob Elves
+ * @author Steffen Pingel
+ */
+public class SearchHitCollector extends TaskDataCollector implements ISearchQuery {
+
+ private final ITaskList taskList;
+
+ private final TaskRepository repository;
+
+ private final IRepositoryQuery repositoryQuery;
+
+ private final RepositorySearchResult searchResult;
+
+ private AbstractRepositoryConnector connector;
+
+ public SearchHitCollector(ITaskList tasklist, TaskRepository repository, IRepositoryQuery repositoryQuery) {
+ this.taskList = tasklist;
+ this.repository = repository;
+ this.repositoryQuery = repositoryQuery;
+ this.searchResult = new RepositorySearchResult(this);
+ }
+
+ public void aboutToStart() {
+ searchResult.removeAll();
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ NewSearchUI.activateSearchResultView();
+ }
+ });
+ }
+
+ @Override
+ public void accept(TaskData taskData) {
+ ITask task = taskList.getTask(repository.getRepositoryUrl(), taskData.getTaskId());
+ if (task == null) {
+ task = TasksUi.getRepositoryModel().createTask(repository, taskData.getTaskId());
+ if (connector != null) {
+ connector.updateTaskFromTaskData(repository, task, taskData);
+ }
+ }
+ searchResult.addMatch(new Match(task, 0, 0));
+ }
+
+ public String getLabel() {
+ return Messages.SearchHitCollector_Querying_Repository_;
+ }
+
+ public boolean canRerun() {
+ return true;
+ }
+
+ public boolean canRunInBackground() {
+ return true;
+ }
+
+ public ISearchResult getSearchResult() {
+ return searchResult;
+ }
+
+ public IStatus run(IProgressMonitor monitor) throws OperationCanceledException {
+ monitor = Policy.monitorFor(monitor);
+
+ aboutToStart();
+
+ if (monitor.isCanceled()) {
+ throw new OperationCanceledException(Messages.SearchHitCollector_Search_cancelled);
+ }
+ connector = TasksUi.getRepositoryManager().getRepositoryConnector(repositoryQuery.getConnectorKind());
+ if (connector != null) {
+ final IStatus status = connector.performQuery(repository, repositoryQuery, this, null, monitor);
+ if (!status.isOK()) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ TasksUiInternal.displayStatus(Messages.SearchHitCollector_Search_failed, status);
+ }
+ });
+ } else {
+ if (searchResult.getMatchCount() >= TaskDataCollector.MAX_HITS) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ TasksUiInternal.displayStatus(Messages.SearchHitCollector_Search_returned_maximum_number_of_hits,
+ RepositoryStatus.createStatus(repository.getRepositoryUrl(), IStatus.WARNING,
+ TasksUiPlugin.ID_PLUGIN, Messages.SearchHitCollector_Max_allowed_number_of_hits_returned_exceeded));
+ }
+ });
+ }
+ }
+ } else {
+ return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, IStatus.OK,
+ Messages.SearchHitCollector_Repository_connector_could_not_be_found, null);
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ public IRepositoryQuery getRepositoryQuery() {
+ return repositoryQuery;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultContentProvider.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultContentProvider.java
new file mode 100644
index 000000000..98cb03481
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultContentProvider.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * @author Rob Elves (moved into task.ui)
+ * @see org.eclipse.jface.viewers.IContentProvider
+ */
+public abstract class SearchResultContentProvider implements ITreeContentProvider {
+
+ /** An empty array of objects */
+ protected final Object[] EMPTY_ARR = new Object[0];
+
+ /** The search result for this content provider */
+ protected RepositorySearchResult searchResult;
+
+ public void dispose() {
+ // nothing to do
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ if (newInput instanceof RepositorySearchResult) {
+ initialize((RepositorySearchResult) newInput);
+ }
+ }
+
+ /**
+ * Initializes the content provider with the given search result.
+ *
+ * @param result
+ * The search result to use with this content provider
+ */
+ protected void initialize(RepositorySearchResult result) {
+ searchResult = result;
+ }
+
+ /**
+ * This method is called whenever the set of matches for the given elements changes.
+ *
+ * @param updatedElements
+ * The array of objects that has to be refreshed
+ * @see
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#elementsChanged(java.lang.Object[])
+ */
+ public abstract void elementsChanged(Object[] updatedElements);
+
+ /**
+ * Clears the viewer.
+ */
+ public abstract void clear();
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSortAction.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSortAction.java
new file mode 100644
index 000000000..46a66fcb2
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSortAction.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.window.Window;
+import org.eclipse.mylyn.internal.tasks.ui.dialogs.TaskCompareDialog;
+
+/**
+ * @author Steffen Pingel
+ */
+public class SearchResultSortAction extends Action {
+
+ private final RepositorySearchResultView view;
+
+ public SearchResultSortAction(RepositorySearchResultView view) {
+ super(Messages.SearchResultSortAction_Sort_Label);
+ this.view = view;
+ setEnabled(true);
+ }
+
+ @Override
+ public void run() {
+ TaskCompareDialog dialog = new TaskCompareDialog(view.getSite(), view.getSorter().getTaskComparator());
+ if (dialog.open() == Window.OK) {
+ view.getViewer().refresh();
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSorter.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSorter.java
new file mode 100644
index 000000000..07d72c226
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultSorter.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ * Frank Becker - fix for bug 216150
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.mylyn.internal.tasks.ui.util.TaskComparator;
+import org.eclipse.mylyn.tasks.core.ITask;
+
+/**
+ * Sorts search results.
+ *
+ * @see TaskComparator
+ * @author Rob Elves
+ * @author Frank Becker
+ */
+public class SearchResultSorter extends ViewerSorter {
+
+ private final TaskComparator taskComparator;
+
+ public SearchResultSorter() {
+ taskComparator = new TaskComparator();
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if (e1 instanceof ITask && e2 instanceof ITask) {
+ ITask entry1 = (ITask) e1;
+ ITask entry2 = (ITask) e2;
+ return taskComparator.compare(entry1, entry2);
+ } else {
+ return super.compare(viewer, e1, e2);
+ }
+ }
+
+ public TaskComparator getTaskComparator() {
+ return taskComparator;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultTreeContentProvider.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultTreeContentProvider.java
new file mode 100644
index 000000000..0afc59d6f
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultTreeContentProvider.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ * Frank Becker - improvements
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
+import org.eclipse.mylyn.internal.tasks.core.Person;
+import org.eclipse.mylyn.internal.tasks.core.TaskGroup;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.core.ITaskContainer;
+
+/**
+ * This implementation of <code>SearchResultContentProvider</code> is used for the table view of a Bugzilla search
+ * result.
+ *
+ * @author Rob Elves (moved into task.ui)
+ * @author Mik Kersten
+ */
+public class SearchResultTreeContentProvider extends SearchResultContentProvider {
+
+ private final Set<Object> elements = new LinkedHashSet<Object>();
+
+ private final Map<String, Person> owners = new HashMap<String, Person>();
+
+ private final Map<String, TaskGroup> completeState = new HashMap<String, TaskGroup>();
+
+ public enum GroupBy {
+ NONE, OWNER, COMPLETION;
+ }
+
+ private GroupBy selectedGroup;
+
+ public SearchResultTreeContentProvider() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ if (newInput instanceof RepositorySearchResult) {
+ searchResult = (RepositorySearchResult) newInput;
+ clear();
+ elementsChanged(searchResult.getElements());
+ }
+ }
+
+ /**
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(Object inputElement) {
+ if (inputElement == searchResult) {
+ if (selectedGroup == GroupBy.OWNER) {
+ return owners.values().toArray();
+ } else if (selectedGroup == GroupBy.COMPLETION) {
+ return completeState.values().toArray();
+ } else {
+ return elements.toArray();
+ }
+ } else {
+ return EMPTY_ARR;
+ }
+ }
+
+ public Object[] getChildren(Object parent) {
+ if (parent instanceof TaskGroup || parent instanceof Person) {
+ return ((ITaskContainer) parent).getChildren().toArray();
+ } else {
+ return EMPTY_ARR;
+ }
+ }
+
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ public boolean hasChildren(Object element) {
+ return getChildren(element).length > 0;
+ }
+
+ @Override
+ public void elementsChanged(Object[] updatedElements) {
+ for (Object object : updatedElements) {
+ boolean added = elements.add(object);
+ if (added && object instanceof ITask) {
+ AbstractTask task = ((AbstractTask) object);
+ String owner = task.getOwner();
+ if (owner == null) {
+ owner = Messages.SearchResultTreeContentProvider__unknown_;
+ }
+ Person person = owners.get(owner);
+ if (person == null) {
+ person = new Person(owner, task.getConnectorKind(), task.getRepositoryUrl());
+ owners.put(owner, person);
+ }
+ person.internalAddChild(task);
+
+ TaskGroup completeIncomplete = null;
+ if (task.isCompleted()) {
+ completeIncomplete = completeState.get(Messages.SearchResultTreeContentProvider_Complete);
+ if (completeIncomplete == null) {
+ completeIncomplete = new TaskGroup("group-complete", Messages.SearchResultTreeContentProvider_Complete, GroupBy.COMPLETION.name()); //$NON-NLS-1$
+ completeState.put(Messages.SearchResultTreeContentProvider_Complete, completeIncomplete);
+ }
+ } else {
+ completeIncomplete = completeState.get(Messages.SearchResultTreeContentProvider_Incomplete);
+ if (completeIncomplete == null) {
+ completeIncomplete = new TaskGroup("group-incomplete", Messages.SearchResultTreeContentProvider_Incomplete, GroupBy.COMPLETION.name()); //$NON-NLS-1$
+ completeState.put(Messages.SearchResultTreeContentProvider_Incomplete, completeIncomplete);
+ }
+ }
+ completeIncomplete.internalAddChild(task);
+ }
+ }
+ }
+
+ @Override
+ public void clear() {
+ elements.clear();
+ owners.clear();
+ completeState.clear();
+ }
+
+ public GroupBy getSelectedGroup() {
+ return selectedGroup;
+ }
+
+ public void setSelectedGroup(GroupBy selectedGroup) {
+ this.selectedGroup = selectedGroup;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultsLabelProvider.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultsLabelProvider.java
new file mode 100644
index 000000000..e8a462c55
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchResultsLabelProvider.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.mylyn.internal.tasks.core.Person;
+import org.eclipse.mylyn.internal.tasks.core.TaskGroup;
+import org.eclipse.mylyn.tasks.ui.TaskElementLabelProvider;
+
+/**
+ * @author Mik Kersten
+ * @author Steffen Pingel
+ */
+public class SearchResultsLabelProvider extends TaskElementLabelProvider {
+
+ private final SearchResultContentProvider contentProvider;
+
+ private final TreeViewer viewer;
+
+ public SearchResultsLabelProvider(SearchResultContentProvider contentProvider, TreeViewer viewer) {
+ super(true);
+ this.contentProvider = contentProvider;
+ this.viewer = viewer;
+ }
+
+ @Override
+ public String getText(Object object) {
+ if (object instanceof TaskGroup || object instanceof Person) {
+ Object[] children = contentProvider.getChildren(object);
+ ViewerFilter[] filters = viewer.getFilters();
+ int filtered = 0;
+ if (filters.length > 0) {
+ for (Object child : children) {
+ for (ViewerFilter filter : filters) {
+ if (!filter.select(viewer, object, child)) {
+ filtered++;
+ break; //don't count a child more the once
+ }
+ }
+ }
+ }
+ if (filtered > 0) {
+ return super.getText(object)
+ + " (" //$NON-NLS-1$
+ + MessageFormat.format(Messages.SearchResultsLabelProvider_OF, (children.length - filtered),
+ children.length) + ")"; //$NON-NLS-1$
+ } else {
+ return super.getText(object) + " (" + children.length + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ } else {
+ return super.getText(object);
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchScoreComputerAdapterFactory.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchScoreComputerAdapterFactory.java
new file mode 100644
index 000000000..35b900ae0
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/SearchScoreComputerAdapterFactory.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2009 Willian Mitsuda 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:
+ * Willian Mitsuda - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.mylyn.internal.tasks.core.AbstractTaskContainer;
+import org.eclipse.mylyn.internal.tasks.ui.TaskSearchPage;
+import org.eclipse.mylyn.tasks.core.IRepositoryElement;
+import org.eclipse.search.ui.ISearchPageScoreComputer;
+
+/**
+ * Implements a {@link IAdapterFactory} for {@link ISearchPageScoreComputer}s which ranks {@link AbstractTaskContainer}s
+ * high for the task search page
+ *
+ * @author Willian Mitsuda
+ */
+public class SearchScoreComputerAdapterFactory implements IAdapterFactory {
+
+ private final ISearchPageScoreComputer computer = new ISearchPageScoreComputer() {
+
+ public int computeScore(String pageId, Object input) {
+ if (!TaskSearchPage.ID.equals(pageId)) {
+ return ISearchPageScoreComputer.UNKNOWN;
+ }
+ if (input instanceof IRepositoryElement) {
+ return 100;
+ }
+ return ISearchPageScoreComputer.LOWEST;
+ }
+
+ };
+
+ @SuppressWarnings("rawtypes")
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ if (ISearchPageScoreComputer.class.equals(adapterType)) {
+ return computer;
+ }
+ return null;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public Class[] getAdapterList() {
+ return new Class[] { ISearchPageScoreComputer.class };
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/StackTraceDuplicateDetector.java b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/StackTraceDuplicateDetector.java
new file mode 100644
index 000000000..12af40934
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/StackTraceDuplicateDetector.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.tasks.ui.search;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.internal.tasks.core.AbstractSearchHandler;
+import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
+import org.eclipse.mylyn.tasks.core.AbstractDuplicateDetector;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+import org.eclipse.mylyn.tasks.ui.TasksUi;
+
+/**
+ * @author Gail Murphy
+ * @author Steffen Pingel
+ */
+public class StackTraceDuplicateDetector extends AbstractDuplicateDetector {
+
+ @Override
+ public boolean canQuery(TaskData taskData) {
+ return TasksUiPlugin.getDefault().getSearchHandler(taskData.getConnectorKind()) != null;
+ }
+
+ private String getDescription(TaskData taskData) {
+ TaskAttribute attribute = taskData.getRoot().getMappedAttribute(TaskAttribute.DESCRIPTION);
+ if (attribute == null) {
+ attribute = taskData.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW);
+ }
+ return (attribute != null) ? attribute.getTaskData().getAttributeMapper().getValueLabel(attribute) : ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public IRepositoryQuery getDuplicatesQuery(TaskRepository taskRepository, TaskData taskData) throws CoreException {
+ String description = getDescription(taskData);
+ String searchString = getStackTraceFromDescription(description);
+ if (searchString == null) {
+ throw new CoreException(new Status(IStatus.INFO, TasksUiPlugin.ID_PLUGIN,
+ "Unable to locate a stack trace in the description text.")); //$NON-NLS-1$
+ }
+
+ IRepositoryQuery query = TasksUi.getRepositoryModel().createRepositoryQuery(taskRepository);
+ AbstractSearchHandler searchHandler = TasksUiPlugin.getDefault().getSearchHandler(
+ taskRepository.getConnectorKind());
+ if (searchHandler.queryForText(taskRepository, query, taskData, searchString)) {
+ return query;
+ }
+ return null;
+ }
+
+ public static String getStackTraceFromDescription(String description) {
+ String stackTrace = null;
+
+ if (description == null) {
+ return null;
+ }
+
+ String punct = "!\"#$%&'\\(\\)*+,-./:;\\<=\\>?@\\[\\]^_`\\{|\\}~\n"; //$NON-NLS-1$
+ String lineRegex = " *at\\s+[\\w" + punct + "]+ ?\\(.*\\) *\n?"; //$NON-NLS-1$ //$NON-NLS-2$
+ Pattern tracePattern = Pattern.compile(lineRegex);
+ Matcher match = tracePattern.matcher(description);
+
+ if (match.find()) {
+ // record the index of the first stack trace line
+ int start = match.start();
+ int lastEnd = match.end();
+
+ // find the last stack trace line
+ while (match.find()) {
+ lastEnd = match.end();
+ }
+
+ // make sure there's still room to find the exception
+ if (start <= 0) {
+ return null;
+ }
+
+ // count back to the line before the stack trace to find the
+ // exception
+ int stackStart = 0;
+ int index = start - 1;
+ while (index > 1 && description.charAt(index) == ' ') {
+ index--;
+ }
+
+ // locate the exception line index
+ stackStart = description.substring(0, index - 1).lastIndexOf("\n"); //$NON-NLS-1$
+ stackStart = (stackStart == -1) ? 0 : stackStart + 1;
+
+ stackTrace = description.substring(stackStart, lastEnd);
+ }
+
+ return stackTrace;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/messages.properties b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/messages.properties
new file mode 100644
index 000000000..b3d004d74
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.search/src/org/eclipse/mylyn/internal/tasks/ui/search/messages.properties
@@ -0,0 +1,36 @@
+###############################################################################
+# Copyright (c) 2009 Tasktop Technologies 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:
+# Tasktop Technologies - initial API and implementation
+###############################################################################
+CreateQueryFromSearchAction_CLEAR_QUERY=Create Query
+CreateQueryFromSearchAction_Name_of_query_to_be_added_to_the_X=Name of query to be added to the {0}
+RepositorySearchResult_Task_search_X_matches=Task search - {0} matches
+RepositorySearchResult_Task_search_1_match=Task search - 1 match
+RepositorySearchResultView_Add_to_X_Category=Add to {0} Category
+RepositorySearchResultView_Create_Query_from_Search_=Create Query from Search...
+RepositorySearchResultView_Filter_Completed_Tasks=Filter Completed Tasks
+RepositorySearchResultView_Group_By_Owner=Group By Owner
+RepositorySearchResultView_Open_in_Editor=Open in Editor
+RepositorySearchResultView_Open_Search_with_Browser_Label=Open Search with Browser
+RepositorySearchResultView_Refine_Search_=Refine Search...
+
+SearchHitCollector_Max_allowed_number_of_hits_returned_exceeded=Max allowed number of hits returned exceeded. Some hits may not be displayed. Please narrow query scope.
+SearchHitCollector_Querying_Repository_=Querying Repository...
+SearchHitCollector_Repository_connector_could_not_be_found=Repository connector could not be found
+SearchHitCollector_Search_failed=Search failed
+SearchHitCollector_Search_cancelled=Search cancelled
+SearchHitCollector_Search_returned_maximum_number_of_hits=Search returned maximum number of hits
+
+SearchResultsLabelProvider_OF={0} of {1}
+
+SearchResultTreeContentProvider_Complete=Complete
+SearchResultTreeContentProvider_Incomplete=Incomplete
+SearchResultTreeContentProvider__unknown_=<unknown>
+
+SearchResultSortAction_Sort_Label=Sort...

Back to the top