blob: 18553c803bfe32cc10a237fbab2bf11fe123b7d6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2008 Steffen Pingel 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.trac.ui.wizard;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.trac.core.client.ITracClient;
import org.eclipse.mylyn.internal.trac.core.model.TracSearch;
import org.eclipse.mylyn.internal.trac.core.model.TracSearchFilter;
import org.eclipse.mylyn.internal.trac.core.model.TracSearchFilter.CompareOperator;
import org.eclipse.mylyn.internal.trac.core.util.TracUtil;
import org.eclipse.mylyn.internal.trac.ui.TracUiPlugin;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
/**
* @author Steffen Pingel
*/
public class TracFilterQueryPage extends AbstractRepositoryQueryPage {
private static final String TITLE = Messages.TracFilterQueryPage_New_Trac_Query;
private static final String DESCRIPTION = Messages.TracFilterQueryPage_Add_search_filters_to_define_query;
private static final String TITLE_QUERY_TITLE = Messages.TracFilterQueryPage_Query_Title;
private Text titleText;
private Composite scrollComposite;
/* Maintain order of criterions in order to be able to restore this later. */
private final Set<SearchField> visibleSearchFields = new LinkedHashSet<SearchField>();
private List<SearchField> searchFields;
public TracFilterQueryPage(TaskRepository repository, IRepositoryQuery query) {
super(TITLE, repository, query);
setTitle(TITLE);
setDescription(DESCRIPTION);
}
@Override
public void applyTo(IRepositoryQuery query) {
query.setUrl(getQueryUrl(getTaskRepository().getRepositoryUrl()));
query.setSummary(getQueryTitle());
}
public void createControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData());
composite.setLayout(new GridLayout(1, false));
createTitleGroup(composite);
ScrolledComposite scrolledComposite = new ScrolledComposite(composite, SWT.V_SCROLL | SWT.BORDER);
GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setLayoutData(gd);
scrollComposite = new Composite(scrolledComposite, SWT.None);
scrolledComposite.setContent(scrollComposite);
scrollComposite.setLayout(new GridLayout(4, false));
createAddFilterGroup(composite);
if (getQuery() != null) {
titleText.setText(getQuery().getSummary());
TracSearch search = TracUtil.toTracSearch(getQuery());
if (search != null) {
restoreWidgetValues(search);
}
}
Dialog.applyDialogFont(composite);
setControl(composite);
}
@Override
public String getQueryTitle() {
return (titleText != null) ? titleText.getText() : null;
}
private void restoreWidgetValues(TracSearch search) {
List<TracSearchFilter> filters = search.getFilters();
for (TracSearchFilter filter : filters) {
SearchField field = getSearchField(filter.getFieldName());
if (field != null) {
showSearchField(field, filter);
} else {
StatusHandler.log(new Status(IStatus.WARNING, TracUiPlugin.ID_PLUGIN,
"Ignoring invalid search filter: " + filter)); //$NON-NLS-1$
}
}
}
private SearchField getSearchField(String fieldName) {
for (SearchField searchField : searchFields) {
if (searchField.getFieldName().equals(fieldName)) {
return searchField;
}
}
return null;
}
private void createAddFilterGroup(Composite parent) {
GridLayout layout;
GridData gd;
Composite composite = new Composite(parent, SWT.NONE);
layout = new GridLayout(2, false);
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
gd = new GridData(GridData.BEGINNING | GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
composite.setLayoutData(gd);
Label label = new Label(composite, SWT.LEFT);
label.setText(Messages.TracFilterQueryPage_Select_to_add_filter);
// condition
final Combo filterCombo = new Combo(composite, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
searchFields = new ArrayList<SearchField>();
searchFields.add(new TextSearchField("summary", Messages.TracFilterQueryPage_Summary)); //$NON-NLS-1$
searchFields.add(new TextSearchField("reporter", Messages.TracFilterQueryPage_Reporter)); //$NON-NLS-1$
searchFields.add(new TextSearchField("owner", Messages.TracFilterQueryPage_Owner)); //$NON-NLS-1$
searchFields.add(new TextSearchField("type", Messages.TracFilterQueryPage_Type)); //$NON-NLS-1$
searchFields.add(new TextSearchField("status", Messages.TracFilterQueryPage_Status)); //$NON-NLS-1$
searchFields.add(new TextSearchField("priority", Messages.TracFilterQueryPage_Priority)); //$NON-NLS-1$
searchFields.add(new TextSearchField("milestone", Messages.TracFilterQueryPage_Milestone)); //$NON-NLS-1$
searchFields.add(new TextSearchField("component", Messages.TracFilterQueryPage_Component)); //$NON-NLS-1$
searchFields.add(new TextSearchField("version", Messages.TracFilterQueryPage_Version)); //$NON-NLS-1$
searchFields.add(new TextSearchField("resoution", Messages.TracFilterQueryPage_Resolution)); //$NON-NLS-1$
searchFields.add(new TextSearchField("keywords", Messages.TracFilterQueryPage_Keywords)); //$NON-NLS-1$
searchFields.add(new TextSearchField("cc", Messages.TracFilterQueryPage_CC)); //$NON-NLS-1$
filterCombo.add(""); //$NON-NLS-1$
for (SearchField field : searchFields) {
filterCombo.add(field.getDisplayName());
}
filterCombo.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (filterCombo.getText().length() > 0) {
SearchField field = searchFields.get(filterCombo.getSelectionIndex() - 1);
showSearchField(field, null);
filterCombo.setText(""); //$NON-NLS-1$
}
}
});
}
private void createTitleGroup(Composite composite) {
Group group = new Group(composite, SWT.NONE);
group.setText(TITLE_QUERY_TITLE);
group.setLayout(new GridLayout(1, false));
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
group.setLayoutData(gd);
titleText = new Text(group, SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
titleText.setLayoutData(gd);
titleText.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
// ignore
}
public void keyReleased(KeyEvent e) {
getContainer().updateButtons();
}
});
}
@Override
public boolean isPageComplete() {
if (titleText != null && titleText.getText().length() > 0) {
return true;
}
return false;
}
private void showSearchField(SearchField field, TracSearchFilter filter) {
assert filter == null || !visibleSearchFields.contains(field);
if (!visibleSearchFields.contains(field)) {
field.createControls(scrollComposite, filter);
visibleSearchFields.add(field);
} else {
field.addControl(scrollComposite);
}
updateScrollPane();
}
public String getQueryUrl(String repsitoryUrl) {
TracSearch search = new TracSearch();
for (SearchField field : visibleSearchFields) {
search.addFilter(field.getFilter());
}
StringBuilder sb = new StringBuilder();
sb.append(repsitoryUrl);
sb.append(ITracClient.QUERY_URL);
sb.append(search.toUrl());
return sb.toString();
}
private void hideSearchField(SearchField field) {
visibleSearchFields.remove(field);
}
private void updateScrollPane() {
scrollComposite.setSize(scrollComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
scrollComposite.layout();
}
private abstract class SearchField {
protected String fieldName;
private final String displayName;
public SearchField(String fieldName, String displayName) {
this.fieldName = fieldName;
this.displayName = displayName;
}
public abstract void createControls(Composite parent, TracSearchFilter filter);
public abstract void addControl(Composite parent);
public String getFieldName() {
return fieldName;
}
public String getDisplayName() {
return displayName;
}
public abstract TracSearchFilter getFilter();
}
private class TextSearchField extends SearchField {
private final CompareOperator[] compareOperators = { CompareOperator.CONTAINS, CompareOperator.CONTAINS_NOT,
CompareOperator.BEGINS_WITH, CompareOperator.ENDS_WITH, CompareOperator.IS, CompareOperator.IS_NOT, };
private List<TextCriterion> criterions;
public TextSearchField(String fieldName, String displayName) {
super(fieldName, displayName);
}
@Override
public void createControls(Composite parent, TracSearchFilter filter) {
if (filter != null) {
TextCriterion first = addCriterion(parent);
first.setCondition(filter.getOperator());
List<String> values = filter.getValues();
if (!values.isEmpty()) {
first.setSearchText(values.get(0));
for (int i = 1; i < values.size(); i++) {
TextCriterion criterion = addCriterion(parent);
criterion.setSearchText(values.get(1));
}
}
} else {
addCriterion(parent);
}
}
@Override
public void addControl(Composite parent) {
addCriterion(parent);
}
public TextCriterion addCriterion(Composite parent) {
TextCriterion criterion = new TextCriterion();
if (criterions == null) {
criterions = new ArrayList<TextCriterion>();
criterion.createControl(parent);
} else {
criterion.createControl(parent, criterions.get(criterions.size() - 1));
}
criterions.add(criterion);
return criterion;
}
@Override
public TracSearchFilter getFilter() {
TracSearchFilter newFilter = new TracSearchFilter(getFieldName());
newFilter.setOperator(criterions.get(0).getCondition());
for (TextCriterion criterion : criterions) {
newFilter.addValue(criterion.getSearchText());
}
return newFilter;
}
public void removeCriterion(TextCriterion criterion) {
int i = criterions.indexOf(criterion);
if (i == -1) {
throw new RuntimeException();
}
if (i == 0) {
// the first criterion is special since it contains the compare
// operator combo
if (criterions.size() > 1) {
// copy the value from the second criterion to the first
TextCriterion sourceCriterion = criterions.get(1);
criterion.searchText.setText(sourceCriterion.searchText.getText());
removeCriterionByIndex(1);
} else {
// no more criterions, remove all controls
removeCriterionByIndex(0);
hideSearchField(this);
}
} else {
removeCriterionByIndex(i);
}
}
private void removeCriterionByIndex(int i) {
criterions.get(i).remove();
criterions.remove(i);
updateScrollPane();
}
private class TextCriterion {
private Combo conditionCombo;
private Text searchText;
private Label label;
private Button removeButton;
public void createControl(Composite parent) {
label = new Label(parent, SWT.LEFT);
label.setText(getDisplayName() + ": "); //$NON-NLS-1$
conditionCombo = new Combo(parent, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
for (CompareOperator op : compareOperators) {
conditionCombo.add(op.toString());
}
conditionCombo.setText(compareOperators[0].toString());
createSearchTextAndRemoveButton(parent);
}
public void createControl(Composite parent, TextCriterion top) {
label = new Label(parent, SWT.RIGHT);
GridData gd = new GridData();
gd.horizontalAlignment = SWT.END;
gd.horizontalSpan = 2;
label.setLayoutData(gd);
label.setText(Messages.TracFilterQueryPage_or);
createSearchTextAndRemoveButton(parent);
label.moveBelow(top.removeButton);
searchText.moveBelow(label);
removeButton.moveBelow(searchText);
}
private void createSearchTextAndRemoveButton(Composite parent) {
searchText = new Text(parent, SWT.BORDER);
GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL);
searchText.setLayoutData(gd);
removeButton = new Button(parent, SWT.PUSH);
removeButton.setText("-"); //$NON-NLS-1$
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
TextSearchField.this.removeCriterion(TextCriterion.this);
}
});
}
public void remove() {
label.dispose();
if (conditionCombo != null) {
conditionCombo.dispose();
}
searchText.dispose();
removeButton.dispose();
}
public CompareOperator getCondition() {
return (conditionCombo != null) ? compareOperators[conditionCombo.getSelectionIndex()] : null;
}
public String getSearchText() {
return searchText.getText();
}
public boolean setCondition(CompareOperator operator) {
if (conditionCombo != null) {
int i = conditionCombo.indexOf(operator.toString());
if (i != -1) {
conditionCombo.select(i);
return true;
}
}
return false;
}
public void setSearchText(String text) {
searchText.setText(text);
}
}
}
}