1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.search;
13 import java.util.HashMap;
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.dnd.DND;
17 import org.eclipse.swt.dnd.Transfer;
18 import org.eclipse.swt.widgets.Composite;
19 import org.eclipse.swt.widgets.Item;
20 import org.eclipse.swt.widgets.Table;
21 import org.eclipse.swt.widgets.Tree;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IAdaptable;
26 import org.eclipse.core.resources.IFile;
27 import org.eclipse.core.resources.IMarker;
28 import org.eclipse.core.resources.IResource;
30 import org.eclipse.jface.action.Action;
31 import org.eclipse.jface.action.IMenuManager;
32 import org.eclipse.jface.action.IToolBarManager;
33 import org.eclipse.jface.action.MenuManager;
34 import org.eclipse.jface.action.Separator;
35 import org.eclipse.jface.viewers.ILabelProvider;
36 import org.eclipse.jface.viewers.IStructuredSelection;
37 import org.eclipse.jface.viewers.ITreeContentProvider;
38 import org.eclipse.jface.viewers.OpenEvent;
39 import org.eclipse.jface.viewers.StructuredViewer;
40 import org.eclipse.jface.viewers.TableViewer;
41 import org.eclipse.jface.viewers.TreeViewer;
42 import org.eclipse.jface.viewers.Viewer;
43 import org.eclipse.jface.viewers.ViewerComparator;
45 import org.eclipse.ui.IActionBars;
46 import org.eclipse.ui.IEditorPart;
47 import org.eclipse.ui.IMemento;
48 import org.eclipse.ui.PartInitException;
49 import org.eclipse.ui.actions.ActionContext;
50 import org.eclipse.ui.dialogs.PreferencesUtil;
51 import org.eclipse.ui.ide.IDE;
52 import org.eclipse.ui.part.IPageSite;
53 import org.eclipse.ui.part.IShowInTargetList;
54 import org.eclipse.ui.part.ResourceTransfer;
55 import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
57 import org.eclipse.ui.texteditor.ITextEditor;
59 import org.eclipse.search.ui.IContextMenuConstants;
60 import org.eclipse.search.ui.ISearchResultViewPart;
61 import org.eclipse.search.ui.NewSearchUI;
62 import org.eclipse.search.ui.text.AbstractTextSearchResult;
63 import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
64 import org.eclipse.search.ui.text.Match;
66 import org.eclipse.jdt.core.IClassFile;
67 import org.eclipse.jdt.core.ICompilationUnit;
68 import org.eclipse.jdt.core.IJavaElement;
69 import org.eclipse.jdt.core.IMember;
71 import org.eclipse.jdt.internal.corext.util.Messages;
73 import org.eclipse.jdt.ui.JavaUI;
74 import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
75 import org.eclipse.jdt.ui.search.IMatchPresentation;
77 import org.eclipse.jdt.internal.ui.JavaPlugin;
78 import org.eclipse.jdt.internal.ui.JavaPluginImages;
79 import org.eclipse.jdt.internal.ui.actions.CopyQualifiedNameAction;
80 import org.eclipse.jdt.internal.ui.dnd.EditorInputTransferDragAdapter;
81 import org.eclipse.jdt.internal.ui.dnd.JdtViewerDragAdapter;
82 import org.eclipse.jdt.internal.ui.dnd.ResourceTransferDragAdapter;
83 import org.eclipse.jdt.internal.ui.packageview.SelectionTransferDragAdapter;
84 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
85 import org.eclipse.jdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
86 import org.eclipse.jdt.internal.ui.viewsupport.ProblemTableViewer;
87 import org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer;
90 public class JavaSearchResultPage extends AbstractTextSearchViewPage implements IAdaptable {
92 public static class DecoratorIgnoringViewerSorter extends ViewerComparator {
94 private final ILabelProvider fLabelProvider;
96 public DecoratorIgnoringViewerSorter(ILabelProvider labelProvider) {
97 fLabelProvider= labelProvider;
101 public int category(Object element) {
102 if (element instanceof IJavaElement || element instanceof IResource)
109 public int compare(Viewer viewer, Object e1, Object e2) {
110 int cat1 = category(e1);
111 int cat2 = category(e2);
116 String name1= fLabelProvider.getText(e1);
117 String name2= fLabelProvider.getText(e2);
119 name1 = "";//$NON-NLS-1$
121 name2 = "";//$NON-NLS-1$
122 return getComparator().compare(name1, name2);
127 private static final int DEFAULT_ELEMENT_LIMIT = 1000;
128 private static final String FALSE = "FALSE"; //$NON-NLS-1$
129 private static final String TRUE = "TRUE"; //$NON-NLS-1$
130 private static final String KEY_GROUPING= "org.eclipse.jdt.search.resultpage.grouping"; //$NON-NLS-1$
131 private static final String KEY_SORTING= "org.eclipse.jdt.search.resultpage.sorting"; //$NON-NLS-1$
132 private static final String KEY_LIMIT_ENABLED= "org.eclipse.jdt.search.resultpage.limit_enabled"; //$NON-NLS-1$
133 private static final String KEY_LIMIT= "org.eclipse.jdt.search.resultpage.limit"; //$NON-NLS-1$
135 private static final String GROUP_GROUPING= "org.eclipse.jdt.search.resultpage.grouping"; //$NON-NLS-1$
136 private static final String GROUP_FILTERING = "org.eclipse.jdt.search.resultpage.filtering"; //$NON-NLS-1$
138 private NewSearchViewActionGroup fActionGroup;
139 private JavaSearchContentProvider fContentProvider;
140 private int fCurrentSortOrder;
141 private SortAction fSortByNameAction;
142 private SortAction fSortByParentName;
143 private SortAction fSortByPathAction;
145 private GroupAction fGroupTypeAction;
146 private GroupAction fGroupFileAction;
147 private GroupAction fGroupPackageAction;
148 private GroupAction fGroupProjectAction;
150 private SelectionDispatchAction fCopyQualifiedNameAction;
152 private SortingLabelProvider fSortingLabelProvider;
154 private int fCurrentGrouping;
156 private static final String[] SHOW_IN_TARGETS= new String[] { JavaUI.ID_PACKAGES , JavaPlugin.ID_RES_NAV };
157 public static final IShowInTargetList SHOW_IN_TARGET_LIST= new IShowInTargetList() {
158 public String[] getShowInTargetIds() {
159 return SHOW_IN_TARGETS;
163 private JavaSearchEditorOpener fEditorOpener= new JavaSearchEditorOpener();
165 public JavaSearchResultPage() {
166 fCopyQualifiedNameAction= null;
169 initGroupingActions();
170 setElementLimit(new Integer(DEFAULT_ELEMENT_LIMIT));
173 private void initSortActions() {
174 fSortByNameAction= new SortAction(SearchMessages.JavaSearchResultPage_sortByName, this, SortingLabelProvider.SHOW_ELEMENT_CONTAINER);
175 fSortByPathAction= new SortAction(SearchMessages.JavaSearchResultPage_sortByPath, this, SortingLabelProvider.SHOW_PATH);
176 fSortByParentName= new SortAction(SearchMessages.JavaSearchResultPage_sortByParentName, this, SortingLabelProvider.SHOW_CONTAINER_ELEMENT);
179 private void initGroupingActions() {
180 fGroupProjectAction= new GroupAction(SearchMessages.JavaSearchResultPage_groupby_project, SearchMessages.JavaSearchResultPage_groupby_project_tooltip, this, LevelTreeContentProvider.LEVEL_PROJECT);
181 JavaPluginImages.setLocalImageDescriptors(fGroupProjectAction, "prj_mode.gif"); //$NON-NLS-1$
182 fGroupPackageAction= new GroupAction(SearchMessages.JavaSearchResultPage_groupby_package, SearchMessages.JavaSearchResultPage_groupby_package_tooltip, this, LevelTreeContentProvider.LEVEL_PACKAGE);
183 JavaPluginImages.setLocalImageDescriptors(fGroupPackageAction, "package_mode.gif"); //$NON-NLS-1$
184 fGroupFileAction= new GroupAction(SearchMessages.JavaSearchResultPage_groupby_file, SearchMessages.JavaSearchResultPage_groupby_file_tooltip, this, LevelTreeContentProvider.LEVEL_FILE);
185 JavaPluginImages.setLocalImageDescriptors(fGroupFileAction, "file_mode.gif"); //$NON-NLS-1$
186 fGroupTypeAction= new GroupAction(SearchMessages.JavaSearchResultPage_groupby_type, SearchMessages.JavaSearchResultPage_groupby_type_tooltip, this, LevelTreeContentProvider.LEVEL_TYPE);
187 JavaPluginImages.setLocalImageDescriptors(fGroupTypeAction, "type_mode.gif"); //$NON-NLS-1$
191 public void setViewPart(ISearchResultViewPart part) {
192 super.setViewPart(part);
193 fActionGroup= new NewSearchViewActionGroup(part);
197 public void showMatch(Match match, int offset, int length, boolean activate) throws PartInitException {
198 IEditorPart editor= fEditorOpener.openMatch(match);
200 if (editor != null && activate)
201 editor.getEditorSite().getPage().activate(editor);
202 Object element= match.getElement();
203 if (editor instanceof ITextEditor) {
204 ITextEditor textEditor= (ITextEditor) editor;
205 textEditor.selectAndReveal(offset, length);
206 } else if (editor != null) {
207 if (element instanceof IFile) {
208 IFile file= (IFile) element;
209 showWithMarker(editor, file, offset, length);
211 } else if (getInput() instanceof JavaSearchResult) {
212 JavaSearchResult result= (JavaSearchResult) getInput();
213 IMatchPresentation participant= result.getSearchParticpant(element);
214 if (participant != null)
215 participant.showMatch(match, offset, length, activate);
219 private void showWithMarker(IEditorPart editor, IFile file, int offset, int length) throws PartInitException {
221 IMarker marker= file.createMarker(NewSearchUI.SEARCH_MARKER);
222 HashMap<String, Integer> attributes= new HashMap<String, Integer>(4);
223 attributes.put(IMarker.CHAR_START, new Integer(offset));
224 attributes.put(IMarker.CHAR_END, new Integer(offset + length));
225 marker.setAttributes(attributes);
226 IDE.gotoMarker(editor, marker);
228 } catch (CoreException e) {
229 throw new PartInitException(SearchMessages.JavaSearchResultPage_error_marker, e);
233 private SelectionDispatchAction getCopyQualifiedNameAction() {
234 if (fCopyQualifiedNameAction == null) {
235 fCopyQualifiedNameAction= new CopyQualifiedNameAction(getSite());
236 fCopyQualifiedNameAction.setActionDefinitionId(CopyQualifiedNameAction.ACTION_DEFINITION_ID);
238 return fCopyQualifiedNameAction;
242 protected void fillContextMenu(IMenuManager mgr) {
243 super.fillContextMenu(mgr);
246 mgr.appendToGroup(IContextMenuConstants.GROUP_EDIT, getCopyQualifiedNameAction());
248 fActionGroup.setContext(new ActionContext(getSite().getSelectionProvider().getSelection()));
249 fActionGroup.fillContextMenu(mgr);
252 private void addSortActions(IMenuManager mgr) {
253 if (getLayout() != FLAG_LAYOUT_FLAT)
255 MenuManager sortMenu= new MenuManager(SearchMessages.JavaSearchResultPage_sortBylabel);
256 sortMenu.add(fSortByNameAction);
257 sortMenu.add(fSortByPathAction);
258 sortMenu.add(fSortByParentName);
260 fSortByNameAction.setChecked(fCurrentSortOrder == fSortByNameAction.getSortOrder());
261 fSortByPathAction.setChecked(fCurrentSortOrder == fSortByPathAction.getSortOrder());
262 fSortByParentName.setChecked(fCurrentSortOrder == fSortByParentName.getSortOrder());
264 mgr.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, sortMenu);
268 protected void fillToolbar(IToolBarManager tbm) {
269 super.fillToolbar(tbm);
271 IActionBars actionBars = getSite().getActionBars();
272 if (actionBars != null) {
273 actionBars.setGlobalActionHandler(CopyQualifiedNameAction.ACTION_HANDLER_ID, getCopyQualifiedNameAction());
276 if (getLayout() != FLAG_LAYOUT_FLAT)
277 addGroupActions(tbm);
280 private void addGroupActions(IToolBarManager mgr) {
281 mgr.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, new Separator(GROUP_GROUPING));
282 mgr.appendToGroup(GROUP_GROUPING, fGroupProjectAction);
283 mgr.appendToGroup(GROUP_GROUPING, fGroupPackageAction);
284 mgr.appendToGroup(GROUP_GROUPING, fGroupFileAction);
285 mgr.appendToGroup(GROUP_GROUPING, fGroupTypeAction);
287 updateGroupingActions();
291 private void updateGroupingActions() {
292 fGroupProjectAction.setChecked(fCurrentGrouping == LevelTreeContentProvider.LEVEL_PROJECT);
293 fGroupPackageAction.setChecked(fCurrentGrouping == LevelTreeContentProvider.LEVEL_PACKAGE);
294 fGroupFileAction.setChecked(fCurrentGrouping == LevelTreeContentProvider.LEVEL_FILE);
295 fGroupTypeAction.setChecked(fCurrentGrouping == LevelTreeContentProvider.LEVEL_TYPE);
300 public void dispose() {
301 fActionGroup.dispose();
306 protected void elementsChanged(Object[] objects) {
307 if (fContentProvider != null)
308 fContentProvider.elementsChanged(objects);
312 protected void clear() {
313 if (fContentProvider != null)
314 fContentProvider.clear();
317 private void addDragAdapters(StructuredViewer viewer) {
318 Transfer[] transfers= new Transfer[] { LocalSelectionTransfer.getInstance(), ResourceTransfer.getInstance() };
319 int ops= DND.DROP_COPY | DND.DROP_LINK;
321 JdtViewerDragAdapter dragAdapter= new JdtViewerDragAdapter(viewer);
322 dragAdapter.addDragSourceListener(new SelectionTransferDragAdapter(viewer));
323 dragAdapter.addDragSourceListener(new EditorInputTransferDragAdapter(viewer));
324 dragAdapter.addDragSourceListener(new ResourceTransferDragAdapter(viewer));
325 viewer.addDragSupport(ops, transfers, dragAdapter);
329 protected void configureTableViewer(TableViewer viewer) {
330 viewer.setUseHashlookup(true);
331 fSortingLabelProvider= new SortingLabelProvider(this);
332 viewer.setLabelProvider(new DecoratingJavaLabelProvider(fSortingLabelProvider, false));
333 fContentProvider=new JavaSearchTableContentProvider(this);
334 viewer.setContentProvider(fContentProvider);
335 viewer.setComparator(new DecoratorIgnoringViewerSorter(fSortingLabelProvider));
336 setSortOrder(fCurrentSortOrder);
337 addDragAdapters(viewer);
341 protected void configureTreeViewer(TreeViewer viewer) {
342 PostfixLabelProvider postfixLabelProvider= new PostfixLabelProvider(this);
343 viewer.setUseHashlookup(true);
344 viewer.setComparator(new DecoratorIgnoringViewerSorter(postfixLabelProvider));
345 viewer.setLabelProvider(new DecoratingJavaLabelProvider(postfixLabelProvider, false));
346 fContentProvider= new LevelTreeContentProvider(this, fCurrentGrouping);
347 viewer.setContentProvider(fContentProvider);
348 addDragAdapters(viewer);
352 protected TreeViewer createTreeViewer(Composite parent) {
353 return new ProblemTreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
357 protected TableViewer createTableViewer(Composite parent) {
358 return new ProblemTableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
361 void setSortOrder(int order) {
362 if (fSortingLabelProvider != null) {
363 fCurrentSortOrder= order;
364 StructuredViewer viewer= getViewer();
365 //viewer.getControl().setRedraw(false);
366 fSortingLabelProvider.setOrder(order);
367 //viewer.getControl().setRedraw(true);
369 getSettings().put(KEY_SORTING, fCurrentSortOrder);
374 public void init(IPageSite site) {
376 IMenuManager menuManager = site.getActionBars().getMenuManager();
377 menuManager.insertBefore(IContextMenuConstants.GROUP_PROPERTIES, new Separator(GROUP_FILTERING));
378 fActionGroup.fillActionBars(site.getActionBars());
379 menuManager.appendToGroup(IContextMenuConstants.GROUP_PROPERTIES, new Action(SearchMessages.JavaSearchResultPage_preferences_label) {
382 String pageId= "org.eclipse.search.preferences.SearchPreferencePage"; //$NON-NLS-1$
383 String[] displayedPages= { pageId,
384 "org.eclipse.ui.editors.preferencePages.Annotations", //$NON-NLS-1$
385 "org.eclipse.ui.preferencePages.ColorsAndFonts" //$NON-NLS-1$
387 PreferencesUtil.createPreferenceDialogOn(JavaPlugin.getActiveWorkbenchShell(), pageId, displayedPages, null).open();
393 * Precondition here: the viewer must be showing a tree with a LevelContentProvider.
395 * @param grouping the grouping which must be one of the <code>LEVEL_*</code> constants from
396 * {@link LevelTreeContentProvider}
398 void setGrouping(int grouping) {
399 fCurrentGrouping= grouping;
400 StructuredViewer viewer= getViewer();
401 LevelTreeContentProvider cp= (LevelTreeContentProvider) viewer.getContentProvider();
402 cp.setLevel(grouping);
403 updateGroupingActions();
404 getSettings().put(KEY_GROUPING, fCurrentGrouping);
405 getViewPart().updateLabel();
409 protected StructuredViewer getViewer() {
410 // override so that it's visible in the package.
411 return super.getViewer();
415 * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#restoreState(org.eclipse.ui.IMemento)
418 public void restoreState(IMemento memento) {
419 super.restoreState(memento);
421 int sortOrder= SortingLabelProvider.SHOW_ELEMENT_CONTAINER;
422 int grouping= LevelTreeContentProvider.LEVEL_PACKAGE;
423 int elementLimit= DEFAULT_ELEMENT_LIMIT;
426 sortOrder= getSettings().getInt(KEY_SORTING);
427 } catch (NumberFormatException e) {
430 grouping= getSettings().getInt(KEY_GROUPING);
431 } catch (NumberFormatException e) {
433 if (FALSE.equals(getSettings().get(KEY_LIMIT_ENABLED))) {
437 elementLimit= getSettings().getInt(KEY_LIMIT);
438 } catch (NumberFormatException e) {
441 if (memento != null) {
442 Integer value= memento.getInteger(KEY_GROUPING);
444 grouping= value.intValue();
445 value= memento.getInteger(KEY_SORTING);
447 sortOrder= value.intValue();
448 boolean limitElements= !FALSE.equals(memento.getString(KEY_LIMIT_ENABLED));
449 value= memento.getInteger(KEY_LIMIT);
451 elementLimit= limitElements ? value.intValue() : -1;
454 fCurrentGrouping= grouping;
455 fCurrentSortOrder= sortOrder;
456 setElementLimit(new Integer(elementLimit));
460 * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#saveState(org.eclipse.ui.IMemento)
463 public void saveState(IMemento memento) {
464 super.saveState(memento);
465 memento.putInteger(KEY_GROUPING, fCurrentGrouping);
466 memento.putInteger(KEY_SORTING, fCurrentSortOrder);
467 int limit= getElementLimit().intValue();
469 memento.putString(KEY_LIMIT_ENABLED, TRUE);
471 memento.putString(KEY_LIMIT_ENABLED, FALSE);
472 memento.putInteger(KEY_LIMIT, limit);
475 private boolean isQueryRunning() {
476 AbstractTextSearchResult result= getInput();
477 if (result != null) {
478 return NewSearchUI.isQueryRunning(result.getQuery());
484 public String getLabel() {
485 String label= super.getLabel();
486 AbstractTextSearchResult input= getInput();
487 if (input != null && input.getActiveMatchFilters() != null && input.getActiveMatchFilters().length > 0) {
488 if (isQueryRunning()) {
489 String message= SearchMessages.JavaSearchResultPage_filtered_message;
490 return Messages.format(message, new Object[] { label });
493 int filteredOut= input.getMatchCount() - getFilteredMatchCount();
494 String message= SearchMessages.JavaSearchResultPage_filteredWithCount_message;
495 return Messages.format(message, new Object[] { label, String.valueOf(filteredOut) });
501 private int getFilteredMatchCount() {
502 StructuredViewer viewer= getViewer();
503 if (viewer instanceof TreeViewer) {
504 ITreeContentProvider tp= (ITreeContentProvider) viewer.getContentProvider();
505 return getMatchCount(tp, getRootElements((TreeViewer) getViewer()));
507 return getMatchCount((TableViewer) viewer);
511 private Object[] getRootElements(TreeViewer viewer) {
512 Tree t= viewer.getTree();
513 Item[] roots= t.getItems();
514 Object[] elements= new Object[roots.length];
515 for (int i = 0; i < elements.length; i++) {
516 elements[i]= roots[i].getData();
521 private Object[] getRootElements(TableViewer viewer) {
522 Table t= viewer.getTable();
523 Item[] roots= t.getItems();
524 Object[] elements= new Object[roots.length];
525 for (int i = 0; i < elements.length; i++) {
526 elements[i]= roots[i].getData();
532 private int getMatchCount(ITreeContentProvider cp, Object[] elements) {
534 for (int j = 0; j < elements.length; j++) {
535 count+= getDisplayedMatchCount(elements[j]);
536 Object[] children = cp.getChildren(elements[j]);
537 count+= getMatchCount(cp, children);
542 private int getMatchCount(TableViewer viewer) {
543 Object[] elements= getRootElements(viewer);
545 for (int i = 0; i < elements.length; i++) {
546 count+= getDisplayedMatchCount(elements[i]);
553 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
555 public Object getAdapter(Class adapter) {
556 if (IShowInTargetList.class.equals(adapter)) {
557 return SHOW_IN_TARGET_LIST;
563 protected void handleOpen(OpenEvent event) {
564 Object firstElement= ((IStructuredSelection)event.getSelection()).getFirstElement();
565 if (firstElement instanceof ICompilationUnit ||
566 firstElement instanceof IClassFile ||
567 firstElement instanceof IMember) {
568 if (getDisplayedMatchCount(firstElement) == 0) {
570 fEditorOpener.openElement(firstElement);
571 } catch (CoreException e) {
572 ExceptionHandler.handle(e, getSite().getShell(), SearchMessages.JavaSearchResultPage_open_editor_error_title, SearchMessages.JavaSearchResultPage_open_editor_error_message);
577 super.handleOpen(event);
581 public void setElementLimit(Integer elementLimit) {
582 super.setElementLimit(elementLimit);
583 int limit= elementLimit.intValue();
584 getSettings().put(KEY_LIMIT, limit);
585 getSettings().put(KEY_LIMIT_ENABLED, limit != -1 ? TRUE : FALSE);