blob: bcbc8c76551844415b943eef4ed37f195535cf0f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2011 Tasktop Technologies and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Frank Becker - improvements
* Perforce - enhancements for bug 319469
*******************************************************************************/
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.IContributionManager;
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.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.commons.ui.CommonImages;
import org.eclipse.mylyn.commons.workbench.DecoratingPatternStyledCellLabelProvider;
import org.eclipse.mylyn.commons.workbench.EnhancedFilteredTree;
import org.eclipse.mylyn.commons.workbench.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 DecoratingPatternStyledCellLabelProvider styledLabelProvider;
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>();
GroupingAction groupByOwnerAction = new GroupingAction(Messages.RepositorySearchResultView_Group_By_Owner,
GroupBy.OWNER);
groupByOwnerAction.setImageDescriptor(CommonImages.PRESENTATION);
// new GroupingAction(Messages.RepositorySearchResultView_Group_By_Complete, GroupBy.COMPLETION);
filterActions = new ArrayList<FilteringAction>();
FilteringAction filterCompleteAction = 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;
}
});
filterCompleteAction.setImageDescriptor(CommonImages.FILTER_COMPLETE);
// 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);
styledLabelProvider = new DecoratingPatternStyledCellLabelProvider(new SearchResultsLabelProvider(
searchResultProvider, viewer), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(),
null);
viewer.setLabelProvider(styledLabelProvider);
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() {
@Override
public void setPattern(String patternString) {
styledLabelProvider.setPattern(patternString);
super.setPattern(patternString);
}
}, 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);
addPresentationActions(menuManager);
}
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();
menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, sortByDialogAction);
addPresentationActions(menuManager);
addPresentationActions(getSite().getActionBars().getToolBarManager());
}
public void addPresentationActions(IContributionManager menuManager) {
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);
}
}
}
}