Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Green2012-01-26 18:48:01 -0500
committerDavid Green2012-01-26 18:48:01 -0500
commit829aa2877b332f9547a816e91b3fdf899304b497 (patch)
tree61cf485cc3a14347edae8a70a8c96218250c075a /org.eclipse.mylyn.tasks.index.ui/src/org
parent77b27ed8d525c7f83677544a349bea967f5286bf (diff)
downloadorg.eclipse.mylyn.tasks-829aa2877b332f9547a816e91b3fdf899304b497.tar.gz
org.eclipse.mylyn.tasks-829aa2877b332f9547a816e91b3fdf899304b497.tar.xz
org.eclipse.mylyn.tasks-829aa2877b332f9547a816e91b3fdf899304b497.zip
191522: provide full text search functionality over task comments
https://bugs.eclipse.org/bugs/show_bug.cgi?id=191522 Change-Id: I93be38a91d657ea1df488dd56cad43c4c5505e3e
Diffstat (limited to 'org.eclipse.mylyn.tasks.index.ui/src/org')
-rw-r--r--org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/ContentProposal.java56
-rw-r--r--org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexSearchHandler.java256
-rw-r--r--org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexedSubstringPatternFilter.java56
-rw-r--r--org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/Messages.java42
-rw-r--r--org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/TasksIndexUi.java23
-rw-r--r--org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/messages.properties17
6 files changed, 450 insertions, 0 deletions
diff --git a/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/ContentProposal.java b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/ContentProposal.java
new file mode 100644
index 000000000..0045e4b7a
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/ContentProposal.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.index.ui;
+
+import org.eclipse.jface.fieldassist.IContentProposal;
+
+/**
+ * @author David Green
+ */
+class ContentProposal implements IContentProposal {
+
+ private final String content;
+
+ private final int cursorPosition;
+
+ private final String label;
+
+ private final String description;
+
+ public ContentProposal(String content, String label, String description) {
+ this(content, label, description, content.length());
+ }
+
+ public ContentProposal(String content, String label, String description, int cursorPosition) {
+ this.content = content;
+ this.cursorPosition = cursorPosition;
+ this.label = label;
+ this.description = description;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public int getCursorPosition() {
+ return cursorPosition;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexSearchHandler.java b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexSearchHandler.java
new file mode 100644
index 000000000..cca957b67
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexSearchHandler.java
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Tasktop Technologies.
+ * 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.index.ui;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.IContentProposal;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
+import org.eclipse.mylyn.internal.tasks.index.core.TaskListIndex;
+import org.eclipse.mylyn.internal.tasks.index.core.TaskListIndex.IndexField;
+import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
+import org.eclipse.mylyn.internal.tasks.ui.search.AbstractSearchHandler;
+import org.eclipse.mylyn.tasks.core.IRepositoryManager;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
+
+/**
+ * @author David Green
+ */
+public class IndexSearchHandler extends AbstractSearchHandler {
+
+ private class ContentProposalProvider implements IContentProposalProvider {
+ public IContentProposal[] getProposals(String contents, int position) {
+ List<IContentProposal> proposals = new ArrayList<IContentProposal>(10);
+
+ String fieldPrefix = ""; //$NON-NLS-1$
+ String prefix = ""; //$NON-NLS-1$
+ if (position >= 0 && position <= contents.length()) {
+ int i = position;
+ while (i > 0 && !Character.isWhitespace(contents.charAt(i - 1)) && contents.charAt(i - 1) != ':') {
+ --i;
+ }
+ if (i > 0 && contents.charAt(i - 1) == ':') {
+ int fieldEnd = i - 1;
+ int fieldStart = i - 1;
+ while (fieldStart > 0 && Character.isLetter(contents.charAt(fieldStart - 1))) {
+ --fieldStart;
+ }
+ fieldPrefix = contents.substring(fieldStart, fieldEnd);
+ }
+
+ prefix = contents.substring(i, position);
+ }
+
+ // if we have a field prefix
+ if (fieldPrefix.length() > 0) {
+ IndexField indexField = null;
+ try {
+ indexField = IndexField.fromFieldName(fieldPrefix);
+ } catch (IllegalArgumentException e) {
+ }
+
+ // if it's a person field then suggest
+ // people from the task list
+ if (indexField != null && indexField.isPersonField()) {
+ computePersonProposals(proposals, prefix);
+ }
+
+ } else {
+
+ // suggest field name prefixes
+ for (IndexField field : IndexField.values()) {
+
+ // searching on URL is not useful
+ if (!field.isUserVisible()) {
+ continue;
+ }
+
+ if (field.fieldName().startsWith(prefix)) {
+ String description;
+ switch (field) {
+ case CONTENT:
+ description = Messages.IndexSearchHandler_hint_content;
+ break;
+ case PERSON:
+ description = Messages.IndexSearchHandler_hint_person;
+ break;
+ default:
+ description = NLS.bind(Messages.IndexSearchHandler_hint_generic, field.fieldName());
+ }
+ proposals.add(new ContentProposal(field.fieldName().substring(prefix.length()) + ":", //$NON-NLS-1$
+ field.fieldName(), description));
+
+ if (field.isTypeDate()) {
+ computeDateRangeProposals(proposals, field);
+ }
+ }
+ }
+ }
+
+ return proposals.toArray(new IContentProposal[proposals.size()]);
+ }
+
+ public void computeDateRangeProposals(List<IContentProposal> proposals, IndexField field) {
+ // for date fields give suggestion of date range search
+ String description;
+ final Date now = new Date();
+ final Date dateSearchUpperBound;
+ final Date dateSearchOneWeekLowerBound;
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+
+ calendar.setTime(now);
+ calendar.add(Calendar.DAY_OF_WEEK, 1); // one day in future due to GMT conversion in index
+ dateSearchUpperBound = calendar.getTime();
+
+ calendar.setTime(now);
+ calendar.add(Calendar.DAY_OF_WEEK, -7);
+ dateSearchOneWeekLowerBound = calendar.getTime();
+ }
+
+ description = NLS.bind(Messages.IndexSearchHandler_Generic_date_range_search_1_week, field.fieldName());
+
+ String label = NLS.bind(Messages.IndexSearchHandler_Past_week_date_range_label, field.fieldName());
+
+ String queryText = index.computeQueryFieldDateRange(field, dateSearchOneWeekLowerBound,
+ dateSearchUpperBound);
+ proposals.add(new ContentProposal(queryText, label, description));
+ }
+
+ public void computePersonProposals(List<IContentProposal> proposals, String prefix) {
+ Set<String> addresses = new TreeSet<String>();
+
+ Collection<AbstractTask> allTasks = TasksUiPlugin.getTaskList().getAllTasks();
+ for (AbstractTask task : allTasks) {
+ addAddresses(addresses, task);
+ }
+
+ for (String address : addresses) {
+ if (address.startsWith(prefix)) {
+ proposals.add(new ContentProposal(address.substring(prefix.length()), address, null));
+ }
+ }
+ }
+
+ private void addAddresses(Set<String> addresses, AbstractTask task) {
+ String name = task.getOwner();
+ if (name != null && name.trim().length() > 0) {
+ addresses.add(name.trim());
+ }
+ }
+ }
+
+ private static TaskListIndex theIndex;
+
+ private static AtomicInteger referenceCount = new AtomicInteger();
+
+ /**
+ * When not null serves as flag indicating that theIndex is referenced, thus preventing bad behaviour if dispose is
+ * called multiple times.
+ */
+ private TaskListIndex index;
+
+ public IndexSearchHandler() {
+ }
+
+ @Override
+ public Composite createSearchComposite(Composite parent) {
+ Composite container = new Composite(parent, SWT.NULL);
+ GridLayoutFactory.swtDefaults().applyTo(container);
+
+ final Button button = new Button(container, SWT.CHECK);
+ button.setText(Messages.IndexSearchHandler_summaryOnly);
+ button.setToolTipText(Messages.IndexSearchHandler_summaryOnly_tooltip);
+ button.setSelection(true);
+
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ IndexField newDefaultField = button.getSelection() ? IndexField.SUMMARY : IndexField.CONTENT;
+ index.setDefaultField(newDefaultField);
+ fireFilterChanged();
+ }
+ });
+
+ return container;
+ }
+
+ @Override
+ public PatternFilter createFilter() {
+ synchronized (IndexSearchHandler.class) {
+ if (index == null) {
+ if (theIndex == null) {
+ final IRepositoryManager repositoryManager = TasksUiPlugin.getRepositoryManager();
+ final File indexLocation = new File(TasksUiPlugin.getDefault().getDataDirectory(), ".taskListIndex"); //$NON-NLS-1$
+
+ theIndex = new TaskListIndex(TasksUiPlugin.getTaskList(), TasksUiPlugin.getTaskDataManager(),
+ repositoryManager, indexLocation);
+
+ }
+ index = theIndex;
+ referenceCount.incrementAndGet();
+ }
+ }
+ return new IndexedSubstringPatternFilter(index);
+ }
+
+ @Override
+ public void adaptTextSearchControl(Text textControl) {
+ IContentProposalProvider proposalProvider = new ContentProposalProvider();
+ ContentAssistCommandAdapter adapter = new ContentAssistCommandAdapter(textControl, new TextContentAdapter(),
+ proposalProvider, null, new char[0]);
+ adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_INSERT);
+
+ // if we decorate the control it lets the user know that they can use content assist...
+ // BUT it looks pretty bad.
+// ControlDecoration controlDecoration = new ControlDecoration(textControl, (SWT.TOP | SWT.LEFT));
+// controlDecoration.setShowOnlyOnFocus(true);
+// FieldDecoration contentProposalImage = FieldDecorationRegistry.getDefault().getFieldDecoration(
+// FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
+// controlDecoration.setImage(contentProposalImage.getImage());
+ }
+
+ @Override
+ public void dispose() {
+ synchronized (IndexSearchHandler.class) {
+ if (index != null) {
+ index = null;
+
+ if (referenceCount.decrementAndGet() == 0) {
+ theIndex.close();
+ theIndex = null;
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexedSubstringPatternFilter.java b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexedSubstringPatternFilter.java
new file mode 100644
index 000000000..ab0379efc
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/IndexedSubstringPatternFilter.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tasktop Technologies.
+ * 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.index.ui;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylyn.commons.workbench.SubstringPatternFilter;
+import org.eclipse.mylyn.internal.tasks.index.core.TaskListIndex;
+import org.eclipse.mylyn.tasks.core.ITask;
+
+/**
+ * A pattern filter that uses a {@link TaskListIndex} to support ITask matching.
+ *
+ * @author David Green
+ */
+public class IndexedSubstringPatternFilter extends SubstringPatternFilter {
+
+ private final TaskListIndex index;
+
+ private String patternString;
+
+ public IndexedSubstringPatternFilter(TaskListIndex index) {
+ this.index = index;
+ }
+
+ @Override
+ public void setPattern(String patternString) {
+ if (patternString != null) {
+ patternString = patternString.trim();
+ }
+ this.patternString = patternString;
+ super.setPattern(patternString);
+ }
+
+ @Override
+ protected boolean isLeafMatch(Viewer viewer, Object element) {
+ if (patternString != null && patternString.length() > 0) {
+ if (element instanceof ITask) {
+ ITask task = (ITask) element;
+ if (index.matches(task, patternString)) {
+ return true;
+ } else {
+ // fall through so that we get non-indexed matching semantics
+ }
+ }
+ }
+ return super.isLeafMatch(viewer, element);
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/Messages.java b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/Messages.java
new file mode 100644
index 000000000..8f051f68a
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/Messages.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.index.ui;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author David Green
+ */
+class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.tasks.index.ui.messages"; //$NON-NLS-1$
+
+ public static String IndexSearchHandler_Generic_date_range_search_1_week;
+
+ public static String IndexSearchHandler_hint_content;
+
+ public static String IndexSearchHandler_hint_generic;
+
+ public static String IndexSearchHandler_hint_person;
+
+ public static String IndexSearchHandler_Past_week_date_range_label;
+
+ public static String IndexSearchHandler_summaryOnly;
+
+ public static String IndexSearchHandler_summaryOnly_tooltip;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/TasksIndexUi.java b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/TasksIndexUi.java
new file mode 100644
index 000000000..f1123fb98
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/TasksIndexUi.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.index.ui;
+
+/**
+ * @author David Green
+ */
+public class TasksIndexUi {
+
+ /**
+ * the symbolic name of the tasks index UI bundle
+ */
+ public static final String ID_PLUGIN = "org.eclipse.mylyn.tasks.index.ui"; //$NON-NLS-1$
+}
diff --git a/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/messages.properties b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/messages.properties
new file mode 100644
index 000000000..c317226b1
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.index.ui/src/org/eclipse/mylyn/internal/tasks/index/ui/messages.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2011 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
+###############################################################################
+IndexSearchHandler_Generic_date_range_search_1_week=Search for tasks where the {0} field value\noccurs in the past week
+IndexSearchHandler_hint_content=Search for a term in the summary, description and comments
+IndexSearchHandler_hint_generic=Search on a term in the {0} field
+IndexSearchHandler_hint_person=Search for a user (reporter, assignee, watcher, commenter)
+IndexSearchHandler_Past_week_date_range_label={0} (past week)
+IndexSearchHandler_summaryOnly=Summary only
+IndexSearchHandler_summaryOnly_tooltip=Search only the summary when checked

Back to the top