/******************************************************************************* * Copyright (c) 2004, 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 * 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); } } } }