001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.actions;
011:
012: import com.ibm.icu.text.Collator;
013:
014: import java.util.ArrayList;
015: import java.util.Collections;
016: import java.util.HashSet;
017: import java.util.Iterator;
018: import java.util.LinkedHashMap;
019: import java.util.List;
020: import java.util.Map;
021:
022: import org.eclipse.core.runtime.Assert;
023:
024: import org.eclipse.swt.SWT;
025: import org.eclipse.swt.custom.BusyIndicator;
026: import org.eclipse.swt.graphics.Image;
027: import org.eclipse.swt.layout.GridData;
028: import org.eclipse.swt.layout.GridLayout;
029: import org.eclipse.swt.widgets.Composite;
030: import org.eclipse.swt.widgets.Control;
031: import org.eclipse.swt.widgets.Shell;
032:
033: import org.eclipse.jface.action.Action;
034: import org.eclipse.jface.action.IContributionItem;
035: import org.eclipse.jface.action.IMenuListener;
036: import org.eclipse.jface.action.IMenuManager;
037: import org.eclipse.jface.action.Separator;
038: import org.eclipse.jface.dialogs.Dialog;
039: import org.eclipse.jface.preference.IPreferenceStore;
040: import org.eclipse.jface.viewers.ILabelProvider;
041: import org.eclipse.jface.viewers.ILabelProviderListener;
042: import org.eclipse.jface.viewers.StructuredViewer;
043: import org.eclipse.jface.viewers.Viewer;
044: import org.eclipse.jface.viewers.ViewerComparator;
045: import org.eclipse.jface.viewers.ViewerFilter;
046: import org.eclipse.jface.window.Window;
047:
048: import org.eclipse.ui.actions.ActionGroup;
049: import org.eclipse.ui.dialogs.SelectionStatusDialog;
050:
051: import org.eclipse.jdt.core.IClassFile;
052: import org.eclipse.jdt.core.ICompilationUnit;
053: import org.eclipse.jdt.core.IJavaElement;
054: import org.eclipse.jdt.core.IJavaModel;
055: import org.eclipse.jdt.core.IJavaProject;
056: import org.eclipse.jdt.core.IMember;
057: import org.eclipse.jdt.core.IPackageFragment;
058: import org.eclipse.jdt.core.IPackageFragmentRoot;
059: import org.eclipse.jdt.core.JavaModelException;
060:
061: import org.eclipse.jdt.internal.ui.JavaPlugin;
062: import org.eclipse.jdt.internal.ui.JavaPluginImages;
063: import org.eclipse.jdt.internal.ui.wizards.dialogfields.CheckedListDialogField;
064: import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
065: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
066: import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
067: import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
068:
069: public class CategoryFilterActionGroup extends ActionGroup {
070:
071: private class CategoryFilter extends ViewerFilter {
072:
073: /**
074: * {@inheritDoc}
075: */
076: public boolean select(Viewer viewer, Object parentElement,
077: Object element) {
078: if (element instanceof IMember) {
079: IMember member = (IMember) element;
080: try {
081: String[] categories = member.getCategories();
082: if (categories.length == 0)
083: return !fFilterUncategorizedMembers;
084:
085: for (int i = 0; i < categories.length; i++) {
086: if (!fFilteredCategories
087: .contains(categories[i]))
088: return true;
089: }
090: return false;
091: } catch (JavaModelException e) {
092: JavaPlugin.log(e);
093: }
094: }
095: return true;
096: }
097:
098: }
099:
100: private class CategoryFilterSelectionDialog extends
101: SelectionStatusDialog implements IListAdapter {
102:
103: private static final int SELECT_ALL = 0;
104: private static final int DESELECT_ALL = 1;
105:
106: private final CheckedListDialogField fCategoryList;
107:
108: public CategoryFilterSelectionDialog(Shell parent,
109: List categories, List selectedCategories) {
110: super (parent);
111:
112: setTitle(ActionMessages.CategoryFilterActionGroup_JavaCategoryFilter_title);
113:
114: String[] buttons = {
115: ActionMessages.CategoryFilterActionGroup_SelectAllCategories,
116: ActionMessages.CategoryFilterActionGroup_DeselectAllCategories };
117:
118: fCategoryList = new CheckedListDialogField(this , buttons,
119: new ILabelProvider() {
120: public Image getImage(Object element) {
121: return null;
122: }
123:
124: public String getText(Object element) {
125: return (String) element;
126: }
127:
128: public void addListener(
129: ILabelProviderListener listener) {
130: }
131:
132: public void dispose() {
133: }
134:
135: public boolean isLabelProperty(Object element,
136: String property) {
137: return false;
138: }
139:
140: public void removeListener(
141: ILabelProviderListener listener) {
142: }
143: });
144: fCategoryList.addElements(categories);
145: fCategoryList.setViewerComparator(new ViewerComparator());
146: fCategoryList
147: .setLabelText(ActionMessages.CategoryFilterActionGroup_SelectCategoriesDescription);
148: fCategoryList.checkAll(true);
149: for (Iterator iter = selectedCategories.iterator(); iter
150: .hasNext();) {
151: String selected = (String) iter.next();
152: fCategoryList.setChecked(selected, false);
153: }
154: if (categories.size() == 0) {
155: fCategoryList.setEnabled(false);
156: }
157: }
158:
159: /**
160: * {@inheritDoc}
161: */
162: protected Control createDialogArea(Composite parent) {
163: Composite composite = new Composite(parent, SWT.NONE);
164: composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
165: true, true));
166: composite.setLayout(new GridLayout(1, true));
167: composite.setFont(parent.getFont());
168:
169: Composite list = new Composite(composite, SWT.NONE);
170: list.setFont(composite.getFont());
171: LayoutUtil.doDefaultLayout(list,
172: new DialogField[] { fCategoryList }, true);
173: LayoutUtil.setHorizontalGrabbing(fCategoryList
174: .getListControl(null));
175: Dialog.applyDialogFont(composite);
176:
177: setHelpAvailable(false);
178:
179: return composite;
180: }
181:
182: /**
183: * {@inheritDoc}
184: */
185: protected void computeResult() {
186: setResult(fCategoryList.getCheckedElements());
187: }
188:
189: /**
190: * {@inheritDoc}
191: */
192: public void customButtonPressed(ListDialogField field, int index) {
193: if (index == SELECT_ALL) {
194: fCategoryList.checkAll(true);
195: fCategoryList.refresh();
196: } else if (index == DESELECT_ALL) {
197: fCategoryList.checkAll(false);
198: fCategoryList.refresh();
199: }
200: }
201:
202: public void doubleClicked(ListDialogField field) {
203: List selectedElements = field.getSelectedElements();
204: if (selectedElements.size() == 1) {
205: Object selected = selectedElements.get(0);
206: fCategoryList.setChecked(selected, !fCategoryList
207: .isChecked(selected));
208: }
209: }
210:
211: public void selectionChanged(ListDialogField field) {
212: }
213: }
214:
215: private class CategoryFilterMenuAction extends Action {
216:
217: public CategoryFilterMenuAction() {
218: setDescription(ActionMessages.CategoryFilterActionGroup_ShowCategoriesActionDescription);
219: setToolTipText(ActionMessages.CategoryFilterActionGroup_ShowCategoriesToolTip);
220: setText(ActionMessages.CategoryFilterActionGroup_ShowCategoriesLabel);
221: JavaPluginImages.setLocalImageDescriptors(this ,
222: "category_menu.gif"); //$NON-NLS-1$
223: }
224:
225: /**
226: * {@inheritDoc}
227: */
228: public void run() {
229: showCategorySelectionDialog(fInputElement);
230: }
231:
232: }
233:
234: private class CategoryFilterAction extends Action {
235:
236: private final String fCategory;
237:
238: public CategoryFilterAction(String category, int count) {
239: fCategory = category;
240: StringBuffer buf = new StringBuffer();
241: buf.append('&').append(count).append(' ').append(fCategory);
242: setText(buf.toString());
243: setChecked(!fFilteredCategories.contains(fCategory));
244: setId(FILTER_CATEGORY_ACTION_ID);
245: }
246:
247: /**
248: * {@inheritDoc}
249: */
250: public void run() {
251: super .run();
252: if (fFilteredCategories.contains(fCategory)) {
253: fFilteredCategories.remove(fCategory);
254: } else {
255: fFilteredCategories.add(fCategory);
256: }
257: fLRUList.put(fCategory, fCategory);
258: storeSettings();
259: fireSelectionChange();
260: }
261:
262: }
263:
264: private class FilterUncategorizedMembersAction extends Action {
265:
266: public FilterUncategorizedMembersAction() {
267: setText(ActionMessages.CategoryFilterActionGroup_ShowUncategorizedMembers);
268: setChecked(!fFilterUncategorizedMembers);
269: setId(FILTER_CATEGORY_ACTION_ID);
270: }
271:
272: /**
273: * {@inheritDoc}
274: */
275: public void run() {
276: fFilterUncategorizedMembers = !fFilterUncategorizedMembers;
277: storeSettings();
278: fireSelectionChange();
279: }
280: }
281:
282: private interface IResultCollector {
283: public boolean accept(String[] category);
284: }
285:
286: private static int COUNTER = 0;//WORKAROUND for Bug 132669 https://bugs.eclipse.org/bugs/show_bug.cgi?id=132669
287:
288: private static final String FILTER_CATEGORY_ACTION_ID = "FilterCategoryActionId"; //$NON-NLS-1$
289: private final String CATEGORY_MENU_GROUP_NAME = "CategoryMenuGroup" + (COUNTER++); //$NON-NLS-1$
290: private static final int MAX_NUMBER_OF_CATEGORIES_IN_MENU = 5;
291:
292: private final StructuredViewer fViewer;
293: private final String fViewerId;
294: private final CategoryFilter fFilter;
295: private final HashSet fFilteredCategories;
296: private IJavaElement[] fInputElement;
297: private final CategoryFilterMenuAction fMenuAction;
298: private IMenuManager fMenuManager;
299: private IMenuListener fMenuListener;
300: private final LinkedHashMap fLRUList;
301: private boolean fFilterUncategorizedMembers;
302:
303: public CategoryFilterActionGroup(final StructuredViewer viewer,
304: final String viewerId, IJavaElement[] input) {
305: Assert.isLegal(viewer != null);
306: Assert.isLegal(viewerId != null);
307: Assert.isLegal(input != null);
308:
309: fLRUList = new LinkedHashMap(
310: MAX_NUMBER_OF_CATEGORIES_IN_MENU * 2, 0.75f, true) {
311: private static final long serialVersionUID = 1L;
312:
313: protected boolean removeEldestEntry(Map.Entry eldest) {
314: return size() > MAX_NUMBER_OF_CATEGORIES_IN_MENU;
315: }
316: };
317: fViewer = viewer;
318: fViewerId = viewerId;
319: fInputElement = input;
320:
321: fFilter = new CategoryFilter();
322:
323: fFilteredCategories = new HashSet();
324: loadSettings();
325:
326: fMenuAction = new CategoryFilterMenuAction();
327:
328: fViewer.addFilter(fFilter);
329: }
330:
331: public void setInput(IJavaElement[] input) {
332: Assert.isLegal(input != null);
333: fInputElement = input;
334: }
335:
336: private void loadSettings() {
337: fFilteredCategories.clear();
338: IPreferenceStore store = JavaPlugin.getDefault()
339: .getPreferenceStore();
340: String string = store.getString(getPreferenceKey());
341: if (string != null && string.length() > 0) {
342: String[] categories = string.split(";"); //$NON-NLS-1$
343: for (int i = 0; i < categories.length; i++) {
344: fFilteredCategories.add(categories[i]);
345: }
346: }
347: string = store.getString(getPreferenceKey() + ".LRU"); //$NON-NLS-1$
348: if (string != null && string.length() > 0) {
349: String[] categories = string.split(";"); //$NON-NLS-1$
350: for (int i = categories.length - 1; i >= 0; i--) {
351: fLRUList.put(categories[i], categories[i]);
352: }
353: }
354: fFilterUncategorizedMembers = store
355: .getBoolean(getPreferenceKey() + ".FilterUncategorized"); //$NON-NLS-1$
356: }
357:
358: private void storeSettings() {
359: IPreferenceStore store = JavaPlugin.getDefault()
360: .getPreferenceStore();
361: if (fFilteredCategories.size() == 0) {
362: store.setValue(getPreferenceKey(), ""); //$NON-NLS-1$
363: } else {
364: StringBuffer buf = new StringBuffer();
365: Iterator iter = fFilteredCategories.iterator();
366: String element = (String) iter.next();
367: buf.append(element);
368: while (iter.hasNext()) {
369: element = (String) iter.next();
370: buf.append(';');
371: buf.append(element);
372: }
373: store.setValue(getPreferenceKey(), buf.toString());
374: buf = new StringBuffer();
375: iter = fLRUList.values().iterator();
376: element = (String) iter.next();
377: buf.append(element);
378: while (iter.hasNext()) {
379: element = (String) iter.next();
380: buf.append(';');
381: buf.append(element);
382: }
383: store.setValue(getPreferenceKey() + ".LRU", buf.toString()); //$NON-NLS-1$
384: store
385: .setValue(
386: getPreferenceKey() + ".FilterUncategorized", fFilterUncategorizedMembers); //$NON-NLS-1$
387: }
388: }
389:
390: public void contributeToViewMenu(IMenuManager menuManager) {
391: menuManager.add(new Separator(CATEGORY_MENU_GROUP_NAME));
392: menuManager
393: .appendToGroup(CATEGORY_MENU_GROUP_NAME, fMenuAction);
394: fMenuListener = new IMenuListener() {
395: public void menuAboutToShow(IMenuManager manager) {
396: if (!manager.isVisible())
397: return;
398: updateMenu(manager);
399: }
400: };
401: menuManager.addMenuListener(fMenuListener);
402: fMenuManager = menuManager;
403: }
404:
405: /**
406: * {@inheritDoc}
407: */
408: public void dispose() {
409: super .dispose();
410: if (fMenuManager != null) {
411: fMenuManager.removeMenuListener(fMenuListener);
412: fMenuManager = null;
413: fMenuListener = null;
414: }
415: }
416:
417: private void updateMenu(IMenuManager manager) {
418: IContributionItem[] items = manager.getItems();
419: if (items != null) {
420: for (int i = 0; i < items.length; i++) {
421: IContributionItem item = items[i];
422: if (item != null
423: && item.getId() != null
424: && item.getId().equals(
425: FILTER_CATEGORY_ACTION_ID)) {
426: IContributionItem removed = manager.remove(item);
427: if (removed != null) {
428: item.dispose();
429: }
430: }
431: }
432: }
433: List menuEntries = new ArrayList();
434: boolean hasUncategorizedMembers = getMenuCategories(menuEntries);
435: Collections.sort(menuEntries, Collator.getInstance());
436:
437: if (menuEntries.size() > 0 && hasUncategorizedMembers)
438: manager.appendToGroup(CATEGORY_MENU_GROUP_NAME,
439: new FilterUncategorizedMembersAction());
440:
441: int count = 0;
442: for (Iterator iter = menuEntries.iterator(); iter.hasNext();) {
443: String category = (String) iter.next();
444: manager.appendToGroup(CATEGORY_MENU_GROUP_NAME,
445: new CategoryFilterAction(category, count + 1));
446: count++;
447: }
448: }
449:
450: private boolean getMenuCategories(List result) {
451: final HashSet/*<String>*/categories = new HashSet();
452: final HashSet/*<String>*/foundLRUCategories = new HashSet();
453: final boolean hasUncategorizedMember[] = new boolean[] { false };
454: for (int i = 0; i < fInputElement.length
455: && !(hasUncategorizedMember[0] && foundLRUCategories
456: .size() >= MAX_NUMBER_OF_CATEGORIES_IN_MENU); i++) {
457: collectCategories(fInputElement[i], new IResultCollector() {
458: public boolean accept(String[] cats) {
459: if (cats.length > 0) {
460: for (int j = 0; j < cats.length; j++) {
461: String category = cats[j];
462: categories.add(category);
463: if (fLRUList.containsKey(category)) {
464: foundLRUCategories.add(category);
465: }
466: }
467: } else {
468: hasUncategorizedMember[0] = true;
469: }
470: return hasUncategorizedMember[0]
471: && foundLRUCategories.size() >= MAX_NUMBER_OF_CATEGORIES_IN_MENU;
472: }
473: });
474: }
475: int count = 0;
476: for (Iterator iter = foundLRUCategories.iterator(); iter
477: .hasNext();) {
478: String element = (String) iter.next();
479: result.add(element);
480: count++;
481: }
482: if (count < MAX_NUMBER_OF_CATEGORIES_IN_MENU) {
483: List sortedCategories = new ArrayList(categories);
484: Collections.sort(sortedCategories, Collator.getInstance());
485: for (Iterator iter = sortedCategories.iterator(); iter
486: .hasNext()
487: && count < MAX_NUMBER_OF_CATEGORIES_IN_MENU;) {
488: String element = (String) iter.next();
489: if (!foundLRUCategories.contains(element)) {
490: result.add(element);
491: count++;
492: }
493: }
494: }
495: return hasUncategorizedMember[0];
496: }
497:
498: private boolean collectCategories(IJavaElement element,
499: IResultCollector collector) {//HashSet result, int max, LinkedHashMap lruList) {
500: try {
501: if (element instanceof IMember) {
502: IMember member = (IMember) element;
503: collector.accept(member.getCategories());
504: return processChildren(member.getChildren(), collector);
505: } else if (element instanceof ICompilationUnit) {
506: return processChildren(((ICompilationUnit) element)
507: .getChildren(), collector);
508: } else if (element instanceof IClassFile) {
509: return processChildren(((IClassFile) element)
510: .getChildren(), collector);
511: } else if (element instanceof IJavaModel) {
512: return processChildren(((IJavaModel) element)
513: .getChildren(), collector);
514: } else if (element instanceof IJavaProject) {
515: return processChildren(((IJavaProject) element)
516: .getChildren(), collector);
517: } else if (element instanceof IPackageFragment) {
518: return processChildren(((IPackageFragment) element)
519: .getChildren(), collector);
520: } else if (element instanceof IPackageFragmentRoot) {
521: return processChildren(((IPackageFragmentRoot) element)
522: .getChildren(), collector);
523: }
524: return false;
525: } catch (JavaModelException e) {
526: JavaPlugin.log(e);
527: return true;
528: }
529: }
530:
531: private boolean processChildren(IJavaElement[] children,
532: IResultCollector collector) {
533: for (int i = 0; i < children.length; i++) {
534: if (collectCategories(children[i], collector))
535: return true;
536: }
537: return false;
538: }
539:
540: private void fireSelectionChange() {
541: fViewer.getControl().setRedraw(false);
542: BusyIndicator.showWhile(fViewer.getControl().getDisplay(),
543: new Runnable() {
544: public void run() {
545: fViewer.refresh();
546: }
547: });
548: fViewer.getControl().setRedraw(true);
549: }
550:
551: private String getPreferenceKey() {
552: return "CategoryFilterActionGroup." + fViewerId; //$NON-NLS-1$
553: }
554:
555: private void showCategorySelectionDialog(IJavaElement[] input) {
556: final HashSet/*<String>*/categories = new HashSet();
557: for (int i = 0; i < input.length; i++) {
558: collectCategories(input[i], new IResultCollector() {
559: public boolean accept(String[] cats) {
560: for (int j = 0; j < cats.length; j++) {
561: categories.add(cats[j]);
562: }
563: return false;
564: }
565: });
566: }
567: CategoryFilterSelectionDialog dialog = new CategoryFilterSelectionDialog(
568: fViewer.getControl().getShell(), new ArrayList(
569: categories), new ArrayList(fFilteredCategories));
570: if (dialog.open() == Window.OK) {
571: Object[] selected = dialog.getResult();
572: for (Iterator iter = categories.iterator(); iter.hasNext();) {
573: String category = (String) iter.next();
574: if (contains(selected, category)) {
575: if (fFilteredCategories.remove(category))
576: fLRUList.put(category, category);
577: } else {
578: if (fFilteredCategories.add(category))
579: fLRUList.put(category, category);
580: }
581: }
582: storeSettings();
583: fireSelectionChange();
584: }
585: }
586:
587: private boolean contains(Object[] selected, String category) {
588: for (int i = 0; i < selected.length; i++) {
589: if (selected[i].equals(category))
590: return true;
591: }
592: return false;
593: }
594:
595: }
|