blob: 95ed3f364a64ad98baf2976bbb7a0f7750a987bd [file] [log] [blame]
/*******************************************************************************
* 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 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.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 static TaskListIndex theIndex;
private static AtomicInteger referenceCount = new AtomicInteger();
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) {
theIndex = new TaskListIndex(TasksUiPlugin.getTaskList(), TasksUiPlugin.getTaskDataManager(),
new File(TasksUiPlugin.getDefault().getDataDirectory(), ".taskListIndex")); //$NON-NLS-1$
}
index = theIndex;
referenceCount.incrementAndGet();
}
}
return new IndexedSubstringPatternFilter(index);
}
@Override
public void adaptTextSearchControl(Text textControl) {
IContentProposalProvider proposalProvider = new 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()) {
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));
}
}
}
} else {
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();
}
// 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));
// for date fields give suggestion of date range search
if (field.isDateTime()) {
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));
}
}
}
}
return proposals.toArray(new IContentProposal[proposals.size()]);
}
private void addAddresses(Set<String> addresses, AbstractTask task) {
String name = task.getOwner();
if (name != null && name.trim().length() > 0) {
addresses.add(name.trim());
}
}
};
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;
}
}
}
}
}