View | Details | Raw Unified | Return to bug 360894 | Differences between
and this patch

Collapse All | Expand All

(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEPluginImages.java (+7 lines)
Added Link Here
153
	public static final ImageDescriptor DESC_INFO_ST_OBJ = create(PATH_OBJ, "info_st_obj.gif"); //$NON-NLS-1$
153
	public static final ImageDescriptor DESC_INFO_ST_OBJ = create(PATH_OBJ, "info_st_obj.gif"); //$NON-NLS-1$
154
	public static final ImageDescriptor DESC_CATEGORY_OBJ = create(PATH_OBJ, "category_obj.gif"); //$NON-NLS-1$
154
	public static final ImageDescriptor DESC_CATEGORY_OBJ = create(PATH_OBJ, "category_obj.gif"); //$NON-NLS-1$
155
	public static final ImageDescriptor DESC_PSEARCH_OBJ = create(PATH_OBJ, "psearch_obj.gif"); //$NON-NLS-1$
155
	public static final ImageDescriptor DESC_PSEARCH_OBJ = create(PATH_OBJ, "psearch_obj.gif"); //$NON-NLS-1$
156
	public static final ImageDescriptor DESC_ESEARCH_OBJ = create(PATH_OBJ, "esearch_obj.gif"); //$NON-NLS-1$
156
	public static final ImageDescriptor DESC_SITE_OBJ = create(PATH_OBJ, "site_obj.gif"); //$NON-NLS-1$
157
	public static final ImageDescriptor DESC_SITE_OBJ = create(PATH_OBJ, "site_obj.gif"); //$NON-NLS-1$
157
	public static final ImageDescriptor DESC_JUNIT_MAIN_TAB = create(PATH_OBJ, "test.gif"); //$NON-NLS-1$
158
	public static final ImageDescriptor DESC_JUNIT_MAIN_TAB = create(PATH_OBJ, "test.gif"); //$NON-NLS-1$
158
	public static final ImageDescriptor DESC_OUTPUT_FOLDER_OBJ = create(PATH_OBJ, "output_folder_attrib.gif"); //$NON-NLS-1$
159
	public static final ImageDescriptor DESC_OUTPUT_FOLDER_OBJ = create(PATH_OBJ, "output_folder_attrib.gif"); //$NON-NLS-1$
Added Link Here
232
	public static final ImageDescriptor DESC_VERTICAL = create(PATH_LCL, "th_vertical.gif"); //$NON-NLS-1$
233
	public static final ImageDescriptor DESC_VERTICAL = create(PATH_LCL, "th_vertical.gif"); //$NON-NLS-1$
233
	public static final ImageDescriptor DESC_COLLAPSE_ALL = create(PATH_LCL, "collapseall.gif"); //$NON-NLS-1$
234
	public static final ImageDescriptor DESC_COLLAPSE_ALL = create(PATH_LCL, "collapseall.gif"); //$NON-NLS-1$
234
	public static final ImageDescriptor DESC_COLLAPSE_ALL_MINI = create(PATH_LCL, "collapse_all_mini.gif"); //$NON-NLS-1$
235
	public static final ImageDescriptor DESC_COLLAPSE_ALL_MINI = create(PATH_LCL, "collapse_all_mini.gif"); //$NON-NLS-1$
236
	public static final ImageDescriptor DESC_TOGGLE_EXPAND_STATE = create(PATH_LCL, "toggle_expand_state.gif"); //$NON-NLS-1$
235
	public static final ImageDescriptor DESC_HELP = create(PATH_LCL, "help.gif"); //$NON-NLS-1$
237
	public static final ImageDescriptor DESC_HELP = create(PATH_LCL, "help.gif"); //$NON-NLS-1$
236
	public static final ImageDescriptor DESC_LINK_WITH_EDITOR = create(PATH_LCL, "synced.gif"); //$NON-NLS-1$
238
	public static final ImageDescriptor DESC_LINK_WITH_EDITOR = create(PATH_LCL, "synced.gif"); //$NON-NLS-1$
237
	public static final ImageDescriptor DESC_CALLEES = create(PATH_LCL, "ch_callees.gif"); //$NON-NLS-1$
239
	public static final ImageDescriptor DESC_CALLEES = create(PATH_LCL, "ch_callees.gif"); //$NON-NLS-1$
Added Link Here
242
	public static final ImageDescriptor DESC_HISTORY_LIST = create(PATH_LCL, "history_list.gif"); //$NON-NLS-1$
244
	public static final ImageDescriptor DESC_HISTORY_LIST = create(PATH_LCL, "history_list.gif"); //$NON-NLS-1$
243
	public static final ImageDescriptor DESC_CLEAR = create(PATH_LCL, "clear.gif"); //$NON-NLS-1$
245
	public static final ImageDescriptor DESC_CLEAR = create(PATH_LCL, "clear.gif"); //$NON-NLS-1$
244
	public static final ImageDescriptor DESC_FILTER = create(PATH_LCL, "filter_ps.gif"); //$NON-NLS-1$
246
	public static final ImageDescriptor DESC_FILTER = create(PATH_LCL, "filter_ps.gif"); //$NON-NLS-1$
247
	public static final ImageDescriptor DESC_FILTER_RELATED = create(PATH_LCL, "filter_related.gif"); //$NON-NLS-1$
248
	public static final ImageDescriptor DESC_SEARCH_EXTENSIONS = create(PATH_LCL, "search_extensions.gif"); //$NON-NLS-1$
245
249
246
	public static final ImageDescriptor DESC_ADD_ATT_DISABLED = create(PATH_LCL_DISABLED, "add_att.gif"); //$NON-NLS-1$
250
	public static final ImageDescriptor DESC_ADD_ATT_DISABLED = create(PATH_LCL_DISABLED, "add_att.gif"); //$NON-NLS-1$
247
	public static final ImageDescriptor DESC_ALPHAB_SORT_CO_DISABLED = create(PATH_LCL_DISABLED, "alphab_sort_co.gif"); //$NON-NLS-1$
251
	public static final ImageDescriptor DESC_ALPHAB_SORT_CO_DISABLED = create(PATH_LCL_DISABLED, "alphab_sort_co.gif"); //$NON-NLS-1$
Added Link Here
255
	public static final ImageDescriptor DESC_HORIZONTAL_DISABLED = create(PATH_LCL_DISABLED, "th_horizontal.gif"); //$NON-NLS-1$
259
	public static final ImageDescriptor DESC_HORIZONTAL_DISABLED = create(PATH_LCL_DISABLED, "th_horizontal.gif"); //$NON-NLS-1$
256
	public static final ImageDescriptor DESC_VERTICAL_DISABLED = create(PATH_LCL_DISABLED, "th_vertical.gif"); //$NON-NLS-1$
260
	public static final ImageDescriptor DESC_VERTICAL_DISABLED = create(PATH_LCL_DISABLED, "th_vertical.gif"); //$NON-NLS-1$
257
	public static final ImageDescriptor DESC_COLLAPSE_ALL_DISABLED = create(PATH_LCL_DISABLED, "collapseall.gif"); //$NON-NLS-1$
261
	public static final ImageDescriptor DESC_COLLAPSE_ALL_DISABLED = create(PATH_LCL_DISABLED, "collapseall.gif"); //$NON-NLS-1$
262
	public static final ImageDescriptor DESC_TOGGLE_EXPAND_STATE_DISABLED = create(PATH_LCL_DISABLED, "toggle_expand_state.gif"); //$NON-NLS-1$	
258
	public static final ImageDescriptor DESC_LINK_WITH_EDITOR_DISABLED = create(PATH_LCL_DISABLED, "synced.gif"); //$NON-NLS-1$
263
	public static final ImageDescriptor DESC_LINK_WITH_EDITOR_DISABLED = create(PATH_LCL_DISABLED, "synced.gif"); //$NON-NLS-1$
259
	public static final ImageDescriptor DESC_CALLEES_DISABLED = create(PATH_LCL_DISABLED, "ch_callees.gif"); //$NON-NLS-1$
264
	public static final ImageDescriptor DESC_CALLEES_DISABLED = create(PATH_LCL_DISABLED, "ch_callees.gif"); //$NON-NLS-1$
260
	public static final ImageDescriptor DESC_CALLERS_DISABLED = create(PATH_LCL_DISABLED, "ch_callers.gif"); //$NON-NLS-1$
265
	public static final ImageDescriptor DESC_CALLERS_DISABLED = create(PATH_LCL_DISABLED, "ch_callers.gif"); //$NON-NLS-1$
Added Link Here
264
	public static final ImageDescriptor DESC_HISTORY_LIST_DISABLED = create(PATH_LCL_DISABLED, "history_list.gif"); //$NON-NLS-1$
269
	public static final ImageDescriptor DESC_HISTORY_LIST_DISABLED = create(PATH_LCL_DISABLED, "history_list.gif"); //$NON-NLS-1$
265
	public static final ImageDescriptor DESC_DCLEAR = create(PATH_LCL_DISABLED, "clear.gif"); //$NON-NLS-1$
270
	public static final ImageDescriptor DESC_DCLEAR = create(PATH_LCL_DISABLED, "clear.gif"); //$NON-NLS-1$
266
	public static final ImageDescriptor DESC_FILTER_DISABLED = create(PATH_LCL_DISABLED, "filter_ps.gif"); //$NON-NLS-1$
271
	public static final ImageDescriptor DESC_FILTER_DISABLED = create(PATH_LCL_DISABLED, "filter_ps.gif"); //$NON-NLS-1$
272
	public static final ImageDescriptor DESC_FILTER_RELATED_DISABLED = create(PATH_LCL_DISABLED, "filter_related.gif"); //$NON-NLS-1$
273
	public static final ImageDescriptor DESC_SEARCH_EXTENSIONS_DISABLED = create(PATH_LCL_DISABLED, "search_extensions.gif"); //$NON-NLS-1$
267
274
268
	public static final ImageDescriptor DESC_RUN_EXC = create(PATH_OBJ, "run_exc.gif"); //$NON-NLS-1$
275
	public static final ImageDescriptor DESC_RUN_EXC = create(PATH_OBJ, "run_exc.gif"); //$NON-NLS-1$
269
	public static final ImageDescriptor DESC_DEBUG_EXC = create(PATH_OBJ, "debug_exc.gif"); //$NON-NLS-1$
276
	public static final ImageDescriptor DESC_DEBUG_EXC = create(PATH_OBJ, "debug_exc.gif"); //$NON-NLS-1$
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java (+6 lines)
Lines 54-59 Link Here
54
54
55
	public static String DependencyPropertiesDialog_exportGroupText;
55
	public static String DependencyPropertiesDialog_exportGroupText;
56
56
57
	public static String ExtensionsPage_toggleExpandState;
58
	public static String ExtensionsPage_searchWithExtensionsFilter;
57
	public static String ExternalizeStringsOperation_editNames_addComment;
59
	public static String ExternalizeStringsOperation_editNames_addComment;
58
60
59
	public static String ExternalizeStringsOperation_editNames_insertProperty;
61
	public static String ExternalizeStringsOperation_editNames_insertProperty;
Lines 1425-1430 Link Here
1425
	public static String EditorActions_revert;
1427
	public static String EditorActions_revert;
1426
	public static String Actions_open_label;
1428
	public static String Actions_open_label;
1427
	public static String Actions_delete_label;
1429
	public static String Actions_delete_label;
1430
	public static String Actions_filter_relatedPluginElements;
1431
	public static String Actions_search_relatedPluginElements;
1428
	public static String Actions_synchronizeVersions_label;
1432
	public static String Actions_synchronizeVersions_label;
1429
1433
1430
	public static String Menus_new_label;
1434
	public static String Menus_new_label;
Lines 1501-1506 Link Here
1501
	public static String SearchAction_Declaration;
1505
	public static String SearchAction_Declaration;
1502
	public static String ShowDescriptionAction_label;
1506
	public static String ShowDescriptionAction_label;
1503
	public static String ShowDescriptionAction_title;
1507
	public static String ShowDescriptionAction_title;
1508
	public static String ShowAllExtensionsAction_label;
1509
	public static String HideUnfilteredExtensionsAction_label;
1504
	public static String ShowSampleAction_installing;
1510
	public static String ShowSampleAction_installing;
1505
	public static String ShowSampleAction_title;
1511
	public static String ShowSampleAction_title;
1506
	public static String ShowSampleAction_msgDesc;
1512
	public static String ShowSampleAction_msgDesc;
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/actions/FilterRelatedExtensionsAction.java (+61 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.editor.actions;
12
13
import org.eclipse.jface.action.Action;
14
import org.eclipse.jface.viewers.IStructuredSelection;
15
import org.eclipse.jface.viewers.TreeViewer;
16
import org.eclipse.pde.internal.ui.PDEPluginImages;
17
import org.eclipse.pde.internal.ui.PDEUIMessages;
18
import org.eclipse.pde.internal.ui.editor.plugin.ExtensionsSection;
19
import org.eclipse.pde.internal.ui.editor.plugin.FormFilteredTree;
20
import org.eclipse.pde.internal.ui.util.ExtensionsFilterUtil;
21
import org.eclipse.swt.widgets.Text;
22
import org.eclipse.ui.PlatformUI;
23
import org.eclipse.ui.actions.ActionFactory;
24
import org.eclipse.ui.keys.IBindingService;
25
26
/**
27
 * Set the search pattern text to all values found by attribute list {@link ExtensionsFilterUtil#RELATED_ATTRIBUTES}  
28
 * 
29
 * @author Sascha Becher
30
 */
31
public class FilterRelatedExtensionsAction extends Action {
32
33
	protected ExtensionsSection fSection;
34
	protected TreeViewer fExtensionTree;
35
	protected FormFilteredTree fFilteredTree;
36
37
	public FilterRelatedExtensionsAction(TreeViewer treeViewer, FormFilteredTree filteredTree, ExtensionsSection section, boolean inContextMenu) {
38
		setImageDescriptor(PDEPluginImages.DESC_FILTER_RELATED);
39
		setDisabledImageDescriptor(PDEPluginImages.DESC_FILTER_RELATED_DISABLED);
40
		String filterBinding = ((IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class)).getBestActiveBindingFormattedFor(ActionFactory.FIND.getCommandId());
41
		String title = PDEUIMessages.Actions_filter_relatedPluginElements + ((filterBinding != null) ? "\t" + filterBinding : ""); //$NON-NLS-1$ //$NON-NLS-2$
42
		String toolTip = PDEUIMessages.Actions_filter_relatedPluginElements + ((filterBinding != null) ? " (" + filterBinding + ")" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
43
		if (inContextMenu) {
44
			setText(title);
45
		}
46
		setToolTipText(toolTip);
47
		fSection = section;
48
		fExtensionTree = treeViewer;
49
		fFilteredTree = filteredTree;
50
	}
51
52
	public void run() {
53
		String filterPattern = ExtensionsFilterUtil.getFilterRelatedPattern((IStructuredSelection) fExtensionTree.getSelection());
54
		Text filterControl = fFilteredTree.getFilterControl();
55
		if (filterControl != null && filterPattern.length() > 0) {
56
			fSection.setBypassFilterDelay(true); // force immediate job run
57
			filterControl.setText(filterPattern);
58
		}
59
	}
60
61
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/actions/SearchExtensionsAction.java (+80 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.editor.actions;
12
13
import org.eclipse.jface.action.Action;
14
import org.eclipse.jface.viewers.ISelection;
15
import org.eclipse.jface.viewers.IStructuredSelection;
16
import org.eclipse.pde.internal.core.search.PluginSearchInput;
17
import org.eclipse.pde.internal.core.search.PluginSearchScope;
18
import org.eclipse.pde.internal.ui.PDEPluginImages;
19
import org.eclipse.pde.internal.ui.editor.plugin.FormFilteredTree;
20
import org.eclipse.pde.internal.ui.search.FindExtensionsByAttributeQuery;
21
import org.eclipse.pde.internal.ui.util.ExtensionsFilterUtil;
22
import org.eclipse.search.ui.ISearchQuery;
23
import org.eclipse.search.ui.NewSearchUI;
24
25
/**
26
 * Search in workspace plugins for occurences of either the current filter text or filter related attributes
27
 * using the ExtensionsPatternFilter search behaviour.
28
 * 
29
 * @author Sascha Becher
30
 */
31
public class SearchExtensionsAction extends Action {
32
33
	protected FormFilteredTree fFilteredTree;
34
35
	private IStructuredSelection fSelection;
36
	private String fFilterRelatedText;
37
38
	public SearchExtensionsAction(FormFilteredTree filteredTree, String actionText) {
39
		this(filteredTree.getViewer().getSelection(), actionText);
40
		fFilteredTree = filteredTree;
41
	}
42
43
	public SearchExtensionsAction(ISelection selection, String actionText) {
44
		setImageDescriptor(PDEPluginImages.DESC_SEARCH_EXTENSIONS);
45
		setDisabledImageDescriptor(PDEPluginImages.DESC_SEARCH_EXTENSIONS_DISABLED);
46
		setText(actionText);
47
		if (selection != null && selection instanceof IStructuredSelection) {
48
			fSelection = (IStructuredSelection) selection;
49
		}
50
	}
51
52
	public void run() {
53
		if (fSelection != null) {
54
			this.fFilterRelatedText = ExtensionsFilterUtil.getFilterRelatedPattern(fSelection);
55
			NewSearchUI.activateSearchResultView();
56
			NewSearchUI.runQueryInBackground(createSearchQuery());
57
		}
58
	}
59
60
	protected ISearchQuery createSearchQuery() {
61
		PluginSearchInput input = new PluginSearchInput();
62
		input.setSearchElement(PluginSearchInput.ELEMENT_PLUGIN);
63
		input.setSearchLimit(PluginSearchInput.LIMIT_ALL);
64
		input.setSearchString(getFilterText());
65
		input.setSearchScope(new PluginSearchScope(PluginSearchScope.SCOPE_WORKSPACE, PluginSearchScope.EXTERNAL_SCOPE_ALL, null));
66
		input.setCaseSensitive(false);
67
		return new FindExtensionsByAttributeQuery(input);
68
	}
69
70
	private String getFilterText() {
71
		if (fFilterRelatedText != null && fFilterRelatedText.length() > 0) {
72
			return fFilterRelatedText;
73
		}
74
		if (fFilteredTree != null) {
75
			return fFilteredTree.getFilterControl().getText();
76
		}
77
		return new String();
78
	}
79
80
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/actions/ShowAllExtensionsAction.java (+130 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.editor.actions;
12
13
import java.util.*;
14
import org.eclipse.jface.action.Action;
15
import org.eclipse.jface.viewers.ISelection;
16
import org.eclipse.pde.core.IBaseModel;
17
import org.eclipse.pde.core.plugin.*;
18
import org.eclipse.pde.internal.core.text.plugin.PluginNode;
19
import org.eclipse.pde.internal.ui.PDEUIMessages;
20
import org.eclipse.pde.internal.ui.editor.plugin.FormFilteredTree;
21
import org.eclipse.pde.internal.ui.search.ExtensionsPatternFilter;
22
import org.eclipse.swt.widgets.TreeItem;
23
24
/**
25
 * Reveals all extensions when the tree is in filter mode.
26
 * The purpose is convenience. When the Filter Related action shows that 
27
 * a certain item that should have been found with the search is missing,
28
 * it is convenient to bring up the required extension to add the
29
 * missing element without loosing the focus on the search result.
30
 * Once all extensions are revealed this action hides them again except
31
 * for those extensions that received new elements. 
32
 * 
33
 * @author Sascha Becher
34
 */
35
public class ShowAllExtensionsAction extends Action {
36
37
	private static int SHOW_ALL = 0;
38
	private static int HIDE_UNFILTERED = 1;
39
40
	private int mode;
41
	private FormFilteredTree fFilteredTree;
42
	private IPluginModelBase fModel;
43
	private ExtensionsPatternFilter fPatternFilter;
44
45
	public ShowAllExtensionsAction(IBaseModel model, FormFilteredTree filteredTree, ExtensionsPatternFilter patternFilter) {
46
		fModel = (IPluginModelBase) model;
47
		fFilteredTree = filteredTree;
48
		fPatternFilter = patternFilter;
49
		mode = getRequiredChange();
50
		setText(mode == SHOW_ALL ? PDEUIMessages.ShowAllExtensionsAction_label : PDEUIMessages.HideUnfilteredExtensionsAction_label);
51
	}
52
53
	public void run() {
54
		if (mode == SHOW_ALL) {
55
			IPluginExtension[] extensions = fModel.getExtensions().getExtensions();
56
			try {
57
				ISelection selection = fFilteredTree.getViewer().getSelection();
58
				Object[] expanded = fFilteredTree.getViewer().getVisibleExpandedElements();
59
				fFilteredTree.setRedraw(false);
60
				for (int i = 0; i < extensions.length; i++) {
61
					fPatternFilter.addElement(extensions[i]);
62
				}
63
				fFilteredTree.update();
64
				fFilteredTree.redraw();
65
				fFilteredTree.getViewer().refresh();
66
67
				TreeItem[] treeItems = fFilteredTree.getViewer().getTree().getItems();
68
				for (int i = 0; i < treeItems.length; i++) {
69
					TreeItem treeItem = treeItems[i];
70
					if (treeItem != null && !treeItem.getExpanded()) {
71
						treeItem.setExpanded(true);
72
					}
73
				}
74
				fFilteredTree.getViewer().refresh();
75
				fFilteredTree.getViewer().setExpandedElements(expanded);
76
				fFilteredTree.getViewer().setSelection(selection);
77
			} finally {
78
				fFilteredTree.setRedraw(true);
79
			}
80
		} else if (mode == HIDE_UNFILTERED) {
81
			List unfiltered = getUnfilteredExtensions(fPatternFilter.getMatchingLeafs());
82
			for (Iterator iterator = unfiltered.iterator(); iterator.hasNext();) {
83
				fPatternFilter.removeElement(iterator.next());
84
			}
85
		}
86
		fFilteredTree.getViewer().refresh();
87
	}
88
89
	public int getRequiredChange() {
90
		boolean visible = true;
91
		IPluginExtension[] extensions = fModel.getExtensions().getExtensions();
92
		for (int i = 0; i < extensions.length; i++) {
93
			IPluginExtension iPluginExtension = extensions[i];
94
			visible &= fPatternFilter.containsElement(iPluginExtension);
95
		}
96
		if (visible) {
97
			return HIDE_UNFILTERED;
98
		}
99
		return SHOW_ALL;
100
	}
101
102
	private List getUnfilteredExtensions(Collection matchingLeafs) {
103
		List unfilteredExtensions = new ArrayList();
104
		try {
105
			fFilteredTree.getViewer().setExpandPreCheckFilters(true);
106
			IPluginExtension[] extensions = fModel.getPluginBase().getExtensions();
107
			for (int i = 0; i < extensions.length; i++) {
108
				IPluginExtension iPluginExtension = extensions[i];
109
				boolean found = false;
110
				for (Iterator it = matchingLeafs.iterator(); it.hasNext();) {
111
					IPluginObject element = ((IPluginObject) it.next());
112
					while (element.getParent() != null && !(element.getParent() instanceof PluginNode)) {
113
						element = element.getParent();
114
					}
115
					if (element.equals(iPluginExtension) || fFilteredTree.getViewer().isExpandable(iPluginExtension)) {
116
						found = true;
117
						break;
118
					}
119
				}
120
				if (!found) {
121
					unfilteredExtensions.add(iPluginExtension);
122
				}
123
			}
124
		} finally {
125
			fFilteredTree.getViewer().setExpandPreCheckFilters(false);
126
		}
127
		return unfilteredExtensions;
128
	}
129
130
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/actions/ToggleExpandStateAction.java (+181 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.editor.actions;
12
13
import java.util.Iterator;
14
import org.eclipse.jface.action.Action;
15
import org.eclipse.jface.viewers.*;
16
import org.eclipse.pde.core.plugin.IPluginParent;
17
import org.eclipse.pde.internal.core.text.plugin.PluginExtensionNode;
18
import org.eclipse.pde.internal.core.text.plugin.PluginParentNode;
19
import org.eclipse.pde.internal.ui.PDEPluginImages;
20
import org.eclipse.pde.internal.ui.PDEUIMessages;
21
import org.eclipse.pde.internal.ui.editor.plugin.FormFilteredTree;
22
import org.eclipse.pde.internal.ui.search.ExtensionsPatternFilter;
23
import org.eclipse.swt.widgets.TreeItem;
24
25
/**
26
 * Expands and collapses selected tree nodes in the extension elements tree viewer upon their expand state.
27
 *  
28
 * @author Sascha Becher
29
 */
30
public class ToggleExpandStateAction extends Action {
31
32
	public static int NEEDS_EXPAND = 1;
33
	public static int NEEDS_COLLAPSE = 2;
34
35
	protected TreeViewer fExtensionTree;
36
	protected FormFilteredTree fFilteredTree;
37
38
	public ToggleExpandStateAction(FormFilteredTree filteredTree, TreeViewer treeViewer) {
39
		setImageDescriptor(PDEPluginImages.DESC_TOGGLE_EXPAND_STATE);
40
		setDisabledImageDescriptor(PDEPluginImages.DESC_TOGGLE_EXPAND_STATE_DISABLED);
41
		setText(PDEUIMessages.ExtensionsPage_toggleExpandState);
42
		fExtensionTree = treeViewer;
43
		fFilteredTree = filteredTree;
44
	}
45
46
	public void run() {
47
		StructuredSelection selection = (StructuredSelection) fExtensionTree.getSelection();
48
		if (fExtensionTree.getTree().getSelectionCount() > 0) {
49
			TreeItem[] items = fExtensionTree.getTree().getSelection();
50
			try {
51
				fFilteredTree.setRedraw(false);
52
				int state = getStateChangeRequired(items);
53
				toggleExpandState(state, selection);
54
			} finally {
55
				fFilteredTree.setRedraw(true);
56
				fExtensionTree.refresh();
57
			}
58
		}
59
	}
60
61
	public void toggleExpandState(int state, StructuredSelection selection) {
62
		TreeItem[] items = fExtensionTree.getTree().getSelection();
63
		if (state == NEEDS_EXPAND) { // expand sub tree
64
			traverseChildrenAndSetExpanded(items); // load non-expanded children
65
			fExtensionTree.refresh();
66
			expandChildrenElements(selection.toArray(), true);
67
			fExtensionTree.setSelection(selection, false);
68
		} else { // collapse sub tree
69
			for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
70
				fExtensionTree.setExpandedState(iterator.next(), false);
71
			}
72
		}
73
	}
74
75
	public int getStateChangeRequired(TreeItem[] selection) {
76
		return (traverseStateChangeRequired(selection)) ? NEEDS_EXPAND : NEEDS_COLLAPSE;
77
	}
78
79
	/**
80
	 * @param items items to be traversed
81
	 * @return <code>true</code> if at least one of the tree items could be expanded but is not. Otherwise <code>false</code> is returned.
82
	 */
83
	protected boolean traverseStateChangeRequired(TreeItem[] items) {
84
		if (items != null) {
85
			for (int i = 0; i < items.length; i++) {
86
				TreeItem treeItem = items[i];
87
				TreeItem[] children = treeItem.getItems();
88
				if (children.length > 0) {
89
					if (treeItem.getExpanded()) {
90
						if (traverseStateChangeRequired(children)) {
91
							return true;
92
						}
93
					} else {
94
						return true;
95
					}
96
				}
97
			}
98
		}
99
		return false;
100
	}
101
102
	/**
103
	 * Expands subtrees of given items. Items of type <code>PluginExtensionNode</code> that have multiple children to expand
104
	 * will only be expanded to the that level. Further expanding is required to reveal the whole subtree. This is for reasons of
105
	 * convenience.
106
	 * 
107
	 * @param items tree items to be expand with their children
108
	 */
109
	private void traverseChildrenAndSetExpanded(TreeItem[] items) {
110
		for (int i = 0; i < items.length; i++) {
111
			TreeItem treeItem = items[i];
112
			TreeItem[] children = treeItem.getItems();
113
			int extensionsChildCount = getExtensionsChildCount((IPluginParent) treeItem.getData());
114
			boolean furtherExpanding = !(extensionsChildCount > 1 && (!treeItem.getExpanded()));
115
			treeItem.setExpanded(furtherExpanding);
116
			if (furtherExpanding) {
117
				traverseChildrenAndSetExpanded(children);
118
			}
119
		}
120
	}
121
122
	private int getExtensionsChildCount(IPluginParent leafData) {
123
		int extensionsChildCount = 0;
124
		if (leafData != null && leafData instanceof PluginExtensionNode) {
125
			if (!fFilteredTree.isFiltered()) {
126
				return leafData.getChildCount();
127
			}
128
			ExtensionsPatternFilter filter = (ExtensionsPatternFilter) fFilteredTree.getPatternFilter();
129
			for (int j = 0; j < leafData.getChildCount(); j++) {
130
				if (filter.containsElement(leafData.getChildren()[j])) {
131
					extensionsChildCount++;
132
				}
133
			}
134
		}
135
		return extensionsChildCount;
136
	}
137
138
	/**
139
	 * @param children list of elements to be expand with their children
140
	 */
141
	private void expandChildrenElements(Object[] children, boolean fullExpand) {
142
		for (int i = 0; i < children.length; i++) {
143
			Object child = children[i];
144
			if (child instanceof PluginParentNode) {
145
				PluginParentNode node = (PluginParentNode) child;
146
				if (node.getChildCount() > 0 && fullExpand) {
147
					boolean furtherExpanding = !(node instanceof PluginExtensionNode && !fExtensionTree.getExpandedState(node));
148
					expandChildrenElements(node.getChildren(), furtherExpanding);
149
				} else {
150
					fExtensionTree.expandToLevel(node, 0);
151
				}
152
			}
153
		}
154
	}
155
156
	/**
157
	 * Determines whether the selected leafs are expandable
158
	 * 
159
	 * @param selection selection to test each item with
160
	 * @return whether the selection can be expanded
161
	 */
162
	public static boolean isExpandable(IStructuredSelection selection) {
163
		boolean isExpandable = false;
164
		if (selection != null) {
165
			if (!selection.isEmpty()) {
166
				for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
167
					Object element = iterator.next();
168
					if (element instanceof PluginParentNode) {
169
						PluginParentNode node = (PluginParentNode) element;
170
						if (node.getChildCount() > 0) {
171
							isExpandable = true;
172
							break;
173
						}
174
					}
175
				}
176
			}
177
		}
178
		return isExpandable;
179
	}
180
181
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/AbstractPluginElementDetails.java (-1 / +25 lines)
Lines 13-18 Link Here
13
13
14
import org.eclipse.pde.internal.ui.editor.PDEDetails;
14
import org.eclipse.pde.internal.ui.editor.PDEDetails;
15
import org.eclipse.pde.internal.ui.editor.PDESection;
15
import org.eclipse.pde.internal.ui.editor.PDESection;
16
import org.eclipse.swt.custom.CCombo;
17
import org.eclipse.swt.widgets.*;
18
import org.eclipse.ui.actions.ActionFactory;
16
19
17
public abstract class AbstractPluginElementDetails extends PDEDetails {
20
public abstract class AbstractPluginElementDetails extends PDEDetails {
18
21
Lines 26-29 Link Here
26
		return fMasterSection;
29
		return fMasterSection;
27
	}
30
	}
28
31
29
}
32
	public boolean doGlobalAction(String actionId) {
33
		// TODO reveal the keybinding Ctrl+F to the user, ideally by showing the action in the context menu
34
		if (actionId.equals(ActionFactory.FIND.getId())) {
35
			if (fMasterSection != null && fMasterSection instanceof ExtensionsSection) {
36
				final Control focusControl = Display.getCurrent().getFocusControl(); // getPage().getLastFocusControl();
37
				String filterText = (focusControl instanceof Text) ? ((Text) focusControl).getText() : (focusControl instanceof CCombo) ? ((CCombo) focusControl).getText() : null;
38
				if (filterText != null) {
39
					// add value of the currently focused attribute text to the filter
40
					((ExtensionsSection) fMasterSection).addAttributeToFilter(filterText, true);
41
					Display.getCurrent().asyncExec(new Runnable() {
42
						public void run() {
43
							// bugfix: after tree refresh bring focus back to the element details form
44
							getPage().updateFormSelection();
45
						}
46
					});
47
				}
48
			}
49
		}
50
		return super.doGlobalAction(actionId);
51
	}
52
53
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ExtensionsSection.java (-64 / +371 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 8-21 Link Here
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Peter Friese <peter.friese@gentleware.com> - bug 194529, bug 196867
10
 *     Peter Friese <peter.friese@gentleware.com> - bug 194529, bug 196867
11
 *     Sascha Becher <s.becher@qualitype.com> - bug 360894
11
 *******************************************************************************/
12
 *******************************************************************************/
12
package org.eclipse.pde.internal.ui.editor.plugin;
13
package org.eclipse.pde.internal.ui.editor.plugin;
13
14
14
import java.util.*;
15
import java.util.*;
15
import org.eclipse.core.resources.IProject;
16
import org.eclipse.core.resources.IProject;
16
import org.eclipse.core.runtime.*;
17
import org.eclipse.core.runtime.*;
18
import org.eclipse.core.runtime.Path;
19
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
20
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
17
import org.eclipse.jface.action.*;
21
import org.eclipse.jface.action.*;
18
import org.eclipse.jface.dialogs.IMessageProvider;
22
import org.eclipse.jface.dialogs.IMessageProvider;
23
import org.eclipse.jface.resource.JFaceResources;
19
import org.eclipse.jface.util.IPropertyChangeListener;
24
import org.eclipse.jface.util.IPropertyChangeListener;
20
import org.eclipse.jface.util.PropertyChangeEvent;
25
import org.eclipse.jface.util.PropertyChangeEvent;
21
import org.eclipse.jface.viewers.*;
26
import org.eclipse.jface.viewers.*;
Lines 30-83 Link Here
30
import org.eclipse.pde.internal.core.schema.SchemaRegistry;
35
import org.eclipse.pde.internal.core.schema.SchemaRegistry;
31
import org.eclipse.pde.internal.core.text.IDocumentElementNode;
36
import org.eclipse.pde.internal.core.text.IDocumentElementNode;
32
import org.eclipse.pde.internal.core.text.plugin.PluginBaseNode;
37
import org.eclipse.pde.internal.core.text.plugin.PluginBaseNode;
38
import org.eclipse.pde.internal.core.text.plugin.PluginExtensionNode;
33
import org.eclipse.pde.internal.ui.*;
39
import org.eclipse.pde.internal.ui.*;
34
import org.eclipse.pde.internal.ui.editor.*;
40
import org.eclipse.pde.internal.ui.editor.*;
35
import org.eclipse.pde.internal.ui.editor.actions.CollapseAction;
41
import org.eclipse.pde.internal.ui.editor.actions.*;
36
import org.eclipse.pde.internal.ui.editor.actions.SortAction;
37
import org.eclipse.pde.internal.ui.editor.contentassist.XMLElementProposalComputer;
42
import org.eclipse.pde.internal.ui.editor.contentassist.XMLElementProposalComputer;
38
import org.eclipse.pde.internal.ui.elements.DefaultContentProvider;
43
import org.eclipse.pde.internal.ui.elements.DefaultContentProvider;
39
import org.eclipse.pde.internal.ui.parts.TreePart;
44
import org.eclipse.pde.internal.ui.parts.TreePart;
45
import org.eclipse.pde.internal.ui.search.ExtensionsPatternFilter;
40
import org.eclipse.pde.internal.ui.search.PluginSearchActionGroup;
46
import org.eclipse.pde.internal.ui.search.PluginSearchActionGroup;
41
import org.eclipse.pde.internal.ui.util.SWTUtil;
47
import org.eclipse.pde.internal.ui.util.*;
42
import org.eclipse.pde.internal.ui.wizards.extension.ExtensionEditorWizard;
48
import org.eclipse.pde.internal.ui.wizards.extension.ExtensionEditorWizard;
43
import org.eclipse.pde.internal.ui.wizards.extension.NewExtensionWizard;
49
import org.eclipse.pde.internal.ui.wizards.extension.NewExtensionWizard;
44
import org.eclipse.pde.ui.IExtensionEditorWizard;
50
import org.eclipse.pde.ui.IExtensionEditorWizard;
45
import org.eclipse.swt.SWT;
51
import org.eclipse.swt.SWT;
46
import org.eclipse.swt.custom.BusyIndicator;
52
import org.eclipse.swt.custom.BusyIndicator;
53
import org.eclipse.swt.dnd.Clipboard;
47
import org.eclipse.swt.events.*;
54
import org.eclipse.swt.events.*;
48
import org.eclipse.swt.graphics.Cursor;
55
import org.eclipse.swt.graphics.*;
49
import org.eclipse.swt.graphics.Image;
50
import org.eclipse.swt.internal.BidiUtil;
56
import org.eclipse.swt.internal.BidiUtil;
51
import org.eclipse.swt.widgets.*;
57
import org.eclipse.swt.widgets.*;
52
import org.eclipse.ui.actions.ActionContext;
58
import org.eclipse.ui.actions.ActionContext;
53
import org.eclipse.ui.actions.ActionFactory;
59
import org.eclipse.ui.actions.ActionFactory;
54
import org.eclipse.ui.dialogs.PatternFilter;
55
import org.eclipse.ui.forms.widgets.FormToolkit;
60
import org.eclipse.ui.forms.widgets.FormToolkit;
56
import org.eclipse.ui.forms.widgets.Section;
61
import org.eclipse.ui.forms.widgets.Section;
62
import org.eclipse.ui.progress.WorkbenchJob;
57
63
58
public class ExtensionsSection extends TreeSection implements IModelChangedListener, IPropertyChangeListener {
64
public class ExtensionsSection extends TreeSection implements IModelChangedListener, IPropertyChangeListener {
65
	private static final int REFRESHJOB_DELAY_TIME = 1200; // milliseconds to wait
66
	private static final int ACCELERATED_SCROLLING = 15; // lines to skip
59
	private static final int BUTTON_MOVE_DOWN = 4;
67
	private static final int BUTTON_MOVE_DOWN = 4;
60
	private static final int BUTTON_MOVE_UP = 3;
68
	private static final int BUTTON_MOVE_UP = 3;
61
	private static final int BUTTON_EDIT = 2;
69
	private static final int BUTTON_EDIT = 2;
62
	private static final int BUTTON_REMOVE = 1;
70
	private static final int BUTTON_REMOVE = 1;
71
	private static final int BUTTON_ADD = 0;
63
	private TreeViewer fExtensionTree;
72
	private TreeViewer fExtensionTree;
64
	private Image fExtensionImage;
73
	private Image fExtensionImage;
65
	private Image fGenericElementImage;
74
	private Image fGenericElementImage;
66
	private FormFilteredTree fFilteredTree;
75
	private FormFilteredTree fFilteredTree;
76
	private ExtensionsPatternFilter fPatternFilter;
67
	private SchemaRegistry fSchemaRegistry;
77
	private SchemaRegistry fSchemaRegistry;
68
	private Hashtable fEditorWizards;
78
	private Hashtable fEditorWizards;
69
	private SortAction fSortAction;
79
	private SortAction fSortAction;
70
	private CollapseAction fCollapseAction;
80
	private CollapseAction fCollapseAction;
81
	private ToggleExpandStateAction fExpandAction;
82
	private FilterRelatedExtensionsAction fFilterRelatedAction;
83
	private SearchExtensionsAction fSearchAction;
84
	private boolean fBypassFilterDelay = false;
71
85
72
	private static final int BUTTON_ADD = 0;
86
	/**
73
87
	 * <code>label, name, class, id, commandId, property, activityId, attribute, value</code>
74
	private static final String[] COMMON_LABEL_PROPERTIES = {"label", //$NON-NLS-1$
88
	 * <br>
75
			"name", //$NON-NLS-1$
89
	 * While adding elements to the array at the end is possible without concern, changing 
76
			"id", //$NON-NLS-1$
90
	 * previous elements requires to refactor occurences with indexed access to the array.
77
			"commandId", //$NON-NLS-1$
91
	 */
78
			"activityId"}; //$NON-NLS-1$ 
92
	// TODO common label properties might be configured through preferences
93
	public static final String[] COMMON_LABEL_ATTRIBUTES = {"label", //$NON-NLS-1$
94
			"name", "locationURI", "class", "id", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
95
			"commandId", "property", "activityId", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
96
			"attribute", "value"}; //$NON-NLS-1$ //$NON-NLS-2$
79
97
80
	private static final String[] VALID_IMAGE_TYPES = {"png", "bmp", "ico", "gif", "jpg", "tiff"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
98
	private static final String[] VALID_IMAGE_TYPES = {"png", "bmp", "ico", "gif", "jpg", "tiff"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
99
	private static final String MENU_NEW_ID = "NewMenu"; //$NON-NLS-1$
81
100
82
	class ExtensionContentProvider extends DefaultContentProvider implements ITreeContentProvider {
101
	class ExtensionContentProvider extends DefaultContentProvider implements ITreeContentProvider {
83
		public Object[] getChildren(Object parent) {
102
		public Object[] getChildren(Object parent) {
Lines 112-124 Link Here
112
		}
131
		}
113
	}
132
	}
114
133
115
	class ExtensionLabelProvider extends LabelProvider {
134
	class ExtensionLabelProvider extends LabelProvider implements IFontProvider {
116
		public String getText(Object obj) {
135
		public String getText(Object obj) {
117
			return resolveObjectName(obj);
136
			return resolveObjectName(obj);
118
		}
137
		}
119
138
120
		public Image getImage(Object obj) {
139
		public Image getImage(Object obj) {
121
			return resolveObjectImage(obj);
140
			return resolveObjectImage(obj);
141
		}
142
143
		public Font getFont(Object element) {
144
			if (fFilteredTree.isFiltered() && fPatternFilter.getMatchingLeafs().contains(element)) {
145
				return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT);
146
			}
147
			return null;
122
		}
148
		}
123
	}
149
	}
124
150
Lines 221-229 Link Here
221
		section.setText(PDEUIMessages.ManifestEditor_DetailExtension_title);
247
		section.setText(PDEUIMessages.ManifestEditor_DetailExtension_title);
222
		initialize((IPluginModelBase) getPage().getModel());
248
		initialize((IPluginModelBase) getPage().getModel());
223
		createSectionToolbar(section, toolkit);
249
		createSectionToolbar(section, toolkit);
250
		// accelerated tree scrolling enabled
251
		fFilteredTree.addMouseWheelListener(new AcceleratedTreeScrolling(fExtensionTree.getTree(), ACCELERATED_SCROLLING));
224
		// Create the adapted listener for the filter entry field
252
		// Create the adapted listener for the filter entry field
225
		fFilteredTree.createUIListenerEntryFilter(this);
253
		fFilteredTree.createUIListenerEntryFilter(this);
226
		Text filterText = fFilteredTree.getFilterControl();
254
		final Text filterText = fFilteredTree.getFilterControl();
227
		if (filterText != null) {
255
		if (filterText != null) {
228
			filterText.addModifyListener(new ModifyListener() {
256
			filterText.addModifyListener(new ModifyListener() {
229
				public void modifyText(ModifyEvent e) {
257
				public void modifyText(ModifyEvent e) {
Lines 252-260 Link Here
252
				}
280
				}
253
			}
281
			}
254
		});
282
		});
283
		// Add action to filter tree with some of the selection's attributes
284
		fFilterRelatedAction = new FilterRelatedExtensionsAction(fExtensionTree, fFilteredTree, this, false);
285
		toolBarManager.add(fFilterRelatedAction);
286
		// Add action to search all workspace plugins with current filtering applied to the tree viewer
287
		fSearchAction = new SearchExtensionsAction(fFilteredTree, PDEUIMessages.ExtensionsPage_searchWithExtensionsFilter);
288
		toolBarManager.add(fSearchAction);
289
		// Add separator
290
		Separator separator = new Separator();
291
		toolBarManager.add(separator);
255
		// Add sort action to the tool bar
292
		// Add sort action to the tool bar
256
		fSortAction = new SortAction(fExtensionTree, PDEUIMessages.ExtensionsPage_sortAlpha, null, null, this);
293
		fSortAction = new SortAction(fExtensionTree, PDEUIMessages.ExtensionsPage_sortAlpha, null, null, this) {
294
			public void run() {
295
				Object[] expanded = fFilteredTree.getViewer().getVisibleExpandedElements();
296
				try {
297
					fFilteredTree.setRedraw(false);
298
					super.run();
299
					// bugfix: retain tree expand state after sort action
300
					fFilteredTree.getViewer().setExpandedElements(expanded);
301
				} finally {
302
					fFilteredTree.setRedraw(true);
303
				}
304
			}
305
		};
257
		toolBarManager.add(fSortAction);
306
		toolBarManager.add(fSortAction);
307
		// Add expand selected leafs action to the toolbar
308
		fExpandAction = new ToggleExpandStateAction(fFilteredTree, fExtensionTree);
309
		toolBarManager.add(fExpandAction);
258
		// Add collapse action to the tool bar
310
		// Add collapse action to the tool bar
259
		fCollapseAction = new CollapseAction(fExtensionTree, PDEUIMessages.ExtensionsPage_collapseAll);
311
		fCollapseAction = new CollapseAction(fExtensionTree, PDEUIMessages.ExtensionsPage_collapseAll);
260
		toolBarManager.add(fCollapseAction);
312
		toolBarManager.add(fCollapseAction);
Lines 309-319 Link Here
309
	 * @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String)
361
	 * @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String)
310
	 */
362
	 */
311
	public boolean doGlobalAction(String actionId) {
363
	public boolean doGlobalAction(String actionId) {
312
364
		if (actionId.equals(ActionFactory.FIND.getId()) && fFilterRelatedAction != null) {
365
			fFilterRelatedAction.run();
366
			return true;
367
		}
313
		if (!isEditable()) {
368
		if (!isEditable()) {
314
			return false;
369
			return false;
315
		}
370
		}
316
317
		if (actionId.equals(ActionFactory.DELETE.getId())) {
371
		if (actionId.equals(ActionFactory.DELETE.getId())) {
318
			handleDelete();
372
			handleDelete();
319
			return true;
373
			return true;
Lines 348-360 Link Here
348
402
349
	protected void fillContextMenu(IMenuManager manager) {
403
	protected void fillContextMenu(IMenuManager manager) {
350
		ISelection selection = fExtensionTree.getSelection();
404
		ISelection selection = fExtensionTree.getSelection();
351
		IStructuredSelection ssel = (IStructuredSelection) selection;
405
		final IStructuredSelection ssel = (IStructuredSelection) selection;
352
		if (ssel.size() == 1) {
406
		if (ssel.size() == 1) {
353
			Object object = ssel.getFirstElement();
407
			Object object = ssel.getFirstElement();
354
			if (object instanceof IPluginParent) {
408
			if (object instanceof IPluginParent) {
355
				IPluginParent parent = (IPluginParent) object;
409
				IPluginParent parent = (IPluginParent) object;
356
				if (parent.getModel().getUnderlyingResource() != null) {
410
				if (parent.getModel().getUnderlyingResource() != null) {
357
					fillContextMenu(getPage(), parent, manager);
411
					boolean removeEnabled = !fFilteredTree.isFiltered() || isRemoveEnabled(ssel);
412
					fillContextMenu(getPage(), parent, manager, false, removeEnabled);
358
					manager.add(new Separator());
413
					manager.add(new Separator());
359
				}
414
				}
360
			}
415
			}
Lines 366-371 Link Here
366
				manager.add(new Separator());
421
				manager.add(new Separator());
367
			}
422
			}
368
		} else if (ssel.size() > 1) {
423
		} else if (ssel.size() > 1) {
424
			boolean removeEnabled = !fFilteredTree.isFiltered() || isRemoveEnabled(ssel);
369
			// multiple
425
			// multiple
370
			Action delAction = new Action() {
426
			Action delAction = new Action() {
371
				public void run() {
427
				public void run() {
Lines 375-388 Link Here
375
			delAction.setText(PDEUIMessages.Actions_delete_label);
431
			delAction.setText(PDEUIMessages.Actions_delete_label);
376
			manager.add(delAction);
432
			manager.add(delAction);
377
			manager.add(new Separator());
433
			manager.add(new Separator());
378
			delAction.setEnabled(isEditable());
434
			delAction.setEnabled(isEditable() && removeEnabled);
435
		}
436
		if (ssel.size() > 0) {
437
			if (ExtensionsFilterUtil.isFilterRelatedEnabled(ssel)) {
438
				FilterRelatedExtensionsAction filterRelatedAction = new FilterRelatedExtensionsAction(fExtensionTree, fFilteredTree, this, true);
439
				manager.add(filterRelatedAction);
440
				SearchExtensionsAction searchRelatedAction = new SearchExtensionsAction(ssel, PDEUIMessages.Actions_search_relatedPluginElements);
441
				manager.add(searchRelatedAction);
442
				manager.add(new Separator());
443
			}
379
		}
444
		}
380
		manager.add(new Separator());
445
		manager.add(new Separator());
446
447
		if (fFilteredTree.isFiltered()) {
448
			// Add action to reveal all extensions when the tree is in filter mode
449
			ShowAllExtensionsAction fShowAllAction = new ShowAllExtensionsAction(getPage().getModel(), fFilteredTree, fPatternFilter);
450
			if (manager.find(MENU_NEW_ID) != null) {
451
				manager.insertAfter(MENU_NEW_ID, fShowAllAction);
452
			} else {
453
				manager.add(fShowAllAction);
454
				manager.add(new Separator());
455
			}
456
		}
381
		if (ssel.size() < 2) { // only cut things when the selection is one
457
		if (ssel.size() < 2) { // only cut things when the selection is one
382
			getPage().getPDEEditor().getContributor().addClipboardActions(manager);
458
			getPage().getPDEEditor().getContributor().addClipboardActions(manager);
383
		}
459
		}
384
		getPage().getPDEEditor().getContributor().contextMenuAboutToShow(manager, false);
460
		getPage().getPDEEditor().getContributor().contextMenuAboutToShow(manager, false);
385
461
		this.fFilteredTree.update();
386
	}
462
	}
387
463
388
	static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager) {
464
	static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager) {
Lines 394-400 Link Here
394
	}
470
	}
395
471
396
	static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager, boolean addSiblingItems, boolean fullMenu) {
472
	static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager, boolean addSiblingItems, boolean fullMenu) {
397
		MenuManager menu = new MenuManager(PDEUIMessages.Menus_new_label);
473
		MenuManager menu = new MenuManager(PDEUIMessages.Menus_new_label, MENU_NEW_ID);
398
		IPluginExtension extension = getExtension(parent);
474
		IPluginExtension extension = getExtension(parent);
399
		ISchema schema = getSchema(extension);
475
		ISchema schema = getSchema(extension);
400
		if (schema == null) {
476
		if (schema == null) {
Lines 493-498 Link Here
493
		}
569
		}
494
	}
570
	}
495
571
572
	public FormFilteredTree getFormFilteredTree() {
573
		return fFilteredTree;
574
	}
575
576
	/**
577
	 * Adds another value to filter text and a preceding separator character if necessary.
578
	 * Empty values as well as <code>true</code> and <code>false</code> are omitted.
579
	 * 
580
	 * @param attributeValue Value to be trimmed and added to the filter text
581
	 * @param clearFilterText When <code>true</code> the filter text is replaced with the attribute value, appended otherwise.
582
	 */
583
	public void addAttributeToFilter(String attributeValue, boolean clearFilterText) {
584
		Text filterControl = fFilteredTree.getFilterControl();
585
		if (filterControl != null && attributeValue != null) {
586
			String trimmedValue = attributeValue.trim();
587
			if (trimmedValue.length() > 0 && ExtensionsFilterUtil.isNotBoolean(trimmedValue)) {
588
				if (trimmedValue.startsWith("%")) {//$NON-NLS-1$
589
					IPluginModelBase model = getPluginModelBase();
590
					trimmedValue = ((model != null) ? model.getResourceString(trimmedValue) : trimmedValue).replaceAll("\"", ""); //$NON-NLS-1$ //$NON-NLS-2$
591
				}
592
				String filterPattern;
593
				if (clearFilterText) {
594
					filterPattern = trimmedValue;
595
				} else {
596
					filterPattern = filterControl.getText();
597
					if (filterPattern.length() > 0 && !filterPattern.endsWith("/")) { //$NON-NLS-1$
598
						filterPattern += "/"; //$NON-NLS-1$
599
					}
600
					filterPattern += trimmedValue;
601
				}
602
				if (filterPattern.indexOf('/') != -1) { // quote when
603
					filterPattern = "\"" + filterPattern + "\""; //$NON-NLS-1$ //$NON-NLS-2$
604
				}
605
				setBypassFilterDelay(true); // force immediate job run
606
				filterControl.setText(filterPattern);
607
			}
608
		}
609
	}
610
496
	private void handleNew() {
611
	private void handleNew() {
497
		final IProject project = getPage().getPDEEditor().getCommonProject();
612
		final IProject project = getPage().getPDEEditor().getCommonProject();
498
		BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() {
613
		BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() {
Lines 555-560 Link Here
555
670
556
	private void handleSelectAll() {
671
	private void handleSelectAll() {
557
		fExtensionTree.getTree().selectAll();
672
		fExtensionTree.getTree().selectAll();
673
		updateButtons(fFilteredTree.getViewer().getSelection());
558
	}
674
	}
559
675
560
	private ArrayList getEditorWizards(IStructuredSelection selection) {
676
	private ArrayList getEditorWizards(IStructuredSelection selection) {
Lines 643-655 Link Here
643
		// The model changed but the editor is still open, we should try to retain expansion, selection will be retained on its own
759
		// The model changed but the editor is still open, we should try to retain expansion, selection will be retained on its own
644
		Object[] expanded = fExtensionTree.getExpandedElements();
760
		Object[] expanded = fExtensionTree.getExpandedElements();
645
		IPluginModelBase model = (IPluginModelBase) getPage().getModel();
761
		IPluginModelBase model = (IPluginModelBase) getPage().getModel();
646
		fExtensionTree.getControl().setRedraw(false);
762
		int[] indexPath = getTreeIndexPath(fExtensionTree.getTree());
647
		fExtensionTree.setInput(model.getPluginBase());
763
		try {
648
		fExtensionTree.setExpandedElements(expanded);
764
			fExtensionTree.getControl().setRedraw(false);
649
		fExtensionTree.getControl().setRedraw(true);
765
			fExtensionTree.setInput(model.getPluginBase());
650
		reportMissingExtensionPointSchemas(model.getPluginBase());
766
			fExtensionTree.setExpandedElements(expanded);
651
		getManagedForm().fireSelectionChanged(ExtensionsSection.this, fExtensionTree.getSelection());
767
652
		super.refresh();
768
			reportMissingExtensionPointSchemas(model.getPluginBase());
769
			getManagedForm().fireSelectionChanged(ExtensionsSection.this, fExtensionTree.getSelection());
770
			super.refresh();
771
772
			if (indexPath != null) {
773
				// fix for Bug 371066
774
				revealTopItem(fExtensionTree.getTree(), indexPath);
775
			}
776
		} finally {
777
			fExtensionTree.getControl().setRedraw(true);
778
		}
779
	}
780
781
	private static int[] getTreeIndexPath(Tree tree) {
782
		int[] indexPath = null;
783
		if (tree != null) {
784
			TreeItem item = tree.getTopItem();
785
			int count = 1;
786
			while (item != null && (item = item.getParentItem()) != null) {
787
				count++;
788
			}
789
			indexPath = new int[count];
790
			int index = 0;
791
			item = tree.getTopItem();
792
			while (item != null && index < count) {
793
				TreeItem parent = item.getParentItem();
794
				if (parent != null) {
795
					indexPath[index++] = parent.indexOf(item);
796
				} else {
797
					indexPath[index++] = tree.indexOf(item);
798
				}
799
				item = parent;
800
			}
801
		}
802
		return indexPath;
803
	}
804
805
	private static void revealTopItem(Tree tree, int[] indexPath) {
806
		TreeItem itemFound = null;
807
		for (int i = indexPath.length - 1; i >= 0; i--) {
808
			int index = indexPath[i];
809
			if (itemFound != null) {
810
				itemFound = (itemFound.getItemCount() > index) ? itemFound.getItem(indexPath[i]) : null;
811
			} else if (i == indexPath.length - 1) {
812
				itemFound = (tree.getItemCount() > index) ? tree.getItem(indexPath[i]) : null;
813
			}
814
		}
815
		if (itemFound != null) {
816
			tree.setTopItem(itemFound);
817
		}
653
	}
818
	}
654
819
655
	public void modelChanged(IModelChangedEvent event) {
820
	public void modelChanged(IModelChangedEvent event) {
Lines 669-674 Link Here
669
			IPluginObject pobj = (IPluginObject) changeObject;
834
			IPluginObject pobj = (IPluginObject) changeObject;
670
			IPluginObject parent = changeObject instanceof IPluginExtension ? ((IPluginModelBase) getPage().getModel()).getPluginBase() : pobj.getParent();
835
			IPluginObject parent = changeObject instanceof IPluginExtension ? ((IPluginModelBase) getPage().getModel()).getPluginBase() : pobj.getParent();
671
			if (event.getChangeType() == IModelChangedEvent.INSERT) {
836
			if (event.getChangeType() == IModelChangedEvent.INSERT) {
837
				// enables adding extensions while tree is filtered
838
				if (fFilteredTree.isFiltered()) {
839
					Object[] inserted = event.getChangedObjects();
840
					for (int i = 0; i < inserted.length; i++) {
841
						fPatternFilter.addElement(inserted[i]);
842
					}
843
					if (inserted.length == 1) {
844
						fFilteredTree.getViewer().setSelection(new StructuredSelection(inserted[0]));
845
					}
846
				}
847
848
				//
672
				fExtensionTree.refresh(parent);
849
				fExtensionTree.refresh(parent);
673
				if (changeObject instanceof IPluginExtension) {
850
				if (changeObject instanceof IPluginExtension) {
674
					IPluginExtension ext = (IPluginExtension) changeObject;
851
					IPluginExtension ext = (IPluginExtension) changeObject;
Lines 809-817 Link Here
809
			if (labelAtt == null) {
986
			if (labelAtt == null) {
810
				// try some hard-coded attributes that
987
				// try some hard-coded attributes that
811
				// are used frequently
988
				// are used frequently
812
				for (int i = 0; i < COMMON_LABEL_PROPERTIES.length; i++) {
989
				for (int i = 0; i < COMMON_LABEL_ATTRIBUTES.length; i++) {
813
					labelAtt = element.getAttribute(COMMON_LABEL_PROPERTIES[i]);
990
					labelAtt = element.getAttribute(COMMON_LABEL_ATTRIBUTES[i]);
814
					if (labelAtt != null)
991
					if (labelAtt != null && labelAtt.getValue().length() > 0)
815
						break;
992
						break;
816
				}
993
				}
817
				if (labelAtt == null) {
994
				if (labelAtt == null) {
Lines 821-829 Link Here
821
						labelAtt = element.getAttributes()[0];
998
						labelAtt = element.getAttributes()[0];
822
				}
999
				}
823
			}
1000
			}
824
			if (labelAtt != null && labelAtt.getValue() != null)
1001
			if (labelAtt != null && labelAtt.getValue() != null) {
825
				fullName = stripShortcuts(labelAtt.getValue());
1002
				fullName = stripShortcuts(labelAtt.getValue());
1003
				if (labelAtt.getName().equals(COMMON_LABEL_ATTRIBUTES[3])) { // remove package from handler class 
1004
					fullName = fullName.substring(fullName.lastIndexOf('.') + 1, fullName.length());
1005
				}
1006
			}
826
			fullName = element.getResourceString(fullName);
1007
			fullName = element.getResourceString(fullName);
1008
827
			if (fullNames)
1009
			if (fullNames)
828
				return fullName != null ? fullName : baseName;
1010
				return fullName != null ? fullName : baseName;
829
			if (fullName == null)
1011
			if (fullName == null)
Lines 836-847 Link Here
836
				return fullName + " \u200f(\u200e" + baseName + ")"; //$NON-NLS-1$ //$NON-NLS-2$
1018
				return fullName + " \u200f(\u200e" + baseName + ")"; //$NON-NLS-1$ //$NON-NLS-2$
837
			return fullName + " (" + baseName + ')'; //$NON-NLS-1$
1019
			return fullName + " (" + baseName + ')'; //$NON-NLS-1$
838
		}
1020
		}
839
		return obj.toString();
1021
		if (obj != null) {
1022
			return obj.toString();
1023
		}
1024
		return new String();
840
	}
1025
	}
841
1026
842
	public void setFocus() {
1027
	public void setFocus() {
843
		if (fExtensionTree != null)
1028
		if (fExtensionTree != null)
844
			fExtensionTree.getTree().setFocus();
1029
			fExtensionTree.getTree().setFocus();
1030
	}
1031
1032
	/**
1033
	 * Temporarily bypasses default {@link FormFilteredTree#getRefreshJobDelay()} for several actions to immediatly start tree 
1034
	 * filtering. Only the next job to call <code>getRefreshJobDelay()</code> will be affected and reset this value.
1035
	 * 
1036
	 * @param bypassFilterDelay <code>true</code> bypasses the refresh job delay by overriding it with <code>0</code> 
1037
	 */
1038
	public void setBypassFilterDelay(boolean bypassFilterDelay) {
1039
		fBypassFilterDelay = bypassFilterDelay;
845
	}
1040
	}
846
1041
847
	public static String stripShortcuts(String input) {
1042
	public static String stripShortcuts(String input) {
Lines 855-860 Link Here
855
			output.append(c);
1050
			output.append(c);
856
		}
1051
		}
857
		return output.toString();
1052
		return output.toString();
1053
	}
1054
1055
	public boolean canCopy(ISelection selection) {
1056
		// Partial fix for Bug 360079, enables Ctrl+C in filter text if plugin model is editable
1057
		if (fFilteredTree.getFilterControl().isFocusControl() && !selection.isEmpty()) {
1058
			return true;
1059
		}
1060
		// TODO enable copy also when plugin model is not editable
1061
		return super.canCopy(selection);
1062
	}
1063
1064
	public boolean canPaste(Clipboard clipboard) {
1065
		// Partial fix for Bug 360079, enables Ctrl+V in filter text if plugin model is editable
1066
		if (fFilteredTree.getFilterControl().isFocusControl()) {
1067
			return true;
1068
		}
1069
		// TODO enable paste also when plugin model is not editable
1070
		return super.canPaste(clipboard);
858
	}
1071
	}
859
1072
860
	/* (non-Javadoc)
1073
	/* (non-Javadoc)
Lines 1081-1086 Link Here
1081
	}
1294
	}
1082
1295
1083
	private void updateButtons(Object item) {
1296
	private void updateButtons(Object item) {
1297
		if (fExpandAction != null) {
1298
			fExpandAction.setEnabled(ToggleExpandStateAction.isExpandable((IStructuredSelection) fExtensionTree.getSelection()));
1299
		}
1300
		if (fFilterRelatedAction != null) {
1301
			fFilterRelatedAction.setEnabled(ExtensionsFilterUtil.isFilterRelatedEnabled((IStructuredSelection) fExtensionTree.getSelection()));
1302
		}
1303
		if (fSearchAction != null) {
1304
			Text filterControl = fFilteredTree.getFilterControl();
1305
			boolean searchEnabled = filterControl != null && filterControl.getText().length() > 0;
1306
			fSearchAction.setEnabled(searchEnabled);
1307
		}
1308
1084
		if (getPage().getModel().isEditable() == false)
1309
		if (getPage().getModel().isEditable() == false)
1085
			return;
1310
			return;
1086
		boolean sorted = fSortAction != null && fSortAction.isChecked();
1311
		boolean sorted = fSortAction != null && fSortAction.isChecked();
Lines 1089-1132 Link Here
1089
			getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, false);
1314
			getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, false);
1090
			return;
1315
			return;
1091
		}
1316
		}
1317
		IStructuredSelection selection = (item instanceof IStructuredSelection) ? (IStructuredSelection) item : null;
1092
1318
1093
		boolean filtered = fFilteredTree.isFiltered();
1319
		boolean filtered = fFilteredTree.isFiltered();
1094
		boolean addEnabled = true;
1320
		boolean addEnabled = true;
1095
		boolean removeEnabled = false;
1321
		boolean removeEnabled = true;
1096
		boolean upEnabled = false;
1322
		boolean upEnabled = false;
1097
		boolean downEnabled = false;
1323
		boolean downEnabled = false;
1098
1324
1099
		if (item != null) {
1100
			removeEnabled = true;
1101
		}
1102
		if (filtered) {
1325
		if (filtered) {
1103
			// Fix for bug 194529 and bug 194828
1326
			// Fix for bug 194529 and bug 194828
1104
			addEnabled = false;
1327
			// Update: adding during filtering enabled by additional filter capability
1328
			addEnabled = true;
1105
			upEnabled = false;
1329
			upEnabled = false;
1106
			downEnabled = false;
1330
			downEnabled = false;
1331
			removeEnabled = isRemoveEnabled(selection);
1107
		} else {
1332
		} else {
1108
			if (item instanceof IStructuredSelection) {
1333
			if (selection != null && selection.size() == 1) {
1109
				if (((IStructuredSelection) item).size() == 1) {
1334
				Object selected = selection.getFirstElement();
1110
					Object selected = ((IStructuredSelection) item).getFirstElement();
1335
				if (selected instanceof IPluginElement) {
1111
					if (selected instanceof IPluginElement) {
1336
					IPluginElement element = (IPluginElement) selected;
1112
						IPluginElement element = (IPluginElement) selected;
1337
					IPluginParent parent = (IPluginParent) element.getParent();
1113
						IPluginParent parent = (IPluginParent) element.getParent();
1338
					// check up
1114
						// check up
1339
					int index = parent.getIndexOf(element);
1115
						int index = parent.getIndexOf(element);
1340
					if (index > 0)
1116
						if (index > 0)
1341
						upEnabled = true;
1117
							upEnabled = true;
1342
					if (index < parent.getChildCount() - 1)
1118
						if (index < parent.getChildCount() - 1)
1343
						downEnabled = true;
1119
							downEnabled = true;
1344
				} else if (selected instanceof IPluginExtension) {
1120
					} else if (selected instanceof IPluginExtension) {
1345
					IPluginExtension extension = (IPluginExtension) selected;
1121
						IPluginExtension extension = (IPluginExtension) selected;
1346
					IExtensions extensions = (IExtensions) extension.getParent();
1122
						IExtensions extensions = (IExtensions) extension.getParent();
1347
					int index = extensions.getIndexOf(extension);
1123
						int index = extensions.getIndexOf(extension);
1348
					int size = extensions.getExtensions().length;
1124
						int size = extensions.getExtensions().length;
1349
					if (index > 0)
1125
						if (index > 0)
1350
						upEnabled = true;
1126
							upEnabled = true;
1351
					if (index < size - 1)
1127
						if (index < size - 1)
1352
						downEnabled = true;
1128
							downEnabled = true;
1129
					}
1130
				}
1353
				}
1131
			}
1354
			}
1132
		}
1355
		}
Lines 1136-1146 Link Here
1136
		getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, downEnabled);
1359
		getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, downEnabled);
1137
	}
1360
	}
1138
1361
1362
	/**
1363
	 * Since filtering potentially hides children of extensions, removing them when they still have children is intransparent.
1364
	 * Needs to be called only when the tree is filtered.
1365
	 *  
1366
	 * @param selection selection to be tested
1367
	 * @return whether removing the selected elements is enabled
1368
	 */
1369
	boolean isRemoveEnabled(IStructuredSelection selection) {
1370
		if (selection != null) {
1371
			for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
1372
				Object element = iterator.next();
1373
				if (element instanceof PluginExtensionNode) {
1374
					return ((PluginExtensionNode) element).getChildCount() == 0;
1375
				}
1376
			}
1377
		}
1378
		return true;
1379
	}
1380
1139
	/* (non-Javadoc)
1381
	/* (non-Javadoc)
1140
	 * @see org.eclipse.pde.internal.ui.editor.TreeSection#createTreeViewer(org.eclipse.swt.widgets.Composite, int)
1382
	 * @see org.eclipse.pde.internal.ui.editor.TreeSection#createTreeViewer(org.eclipse.swt.widgets.Composite, int)
1141
	 */
1383
	 */
1142
	protected TreeViewer createTreeViewer(Composite parent, int style) {
1384
	protected TreeViewer createTreeViewer(Composite parent, int style) {
1143
		fFilteredTree = new FormFilteredTree(parent, style, new PatternFilter());
1385
		fPatternFilter = new ExtensionsPatternFilter();
1386
		fFilteredTree = new FormFilteredTree(parent, style, fPatternFilter) {
1387
			protected WorkbenchJob doCreateRefreshJob() {
1388
				final WorkbenchJob job = super.doCreateRefreshJob();
1389
				job.addJobChangeListener(new JobChangeAdapter() {
1390
					private ISelection selection;
1391
					private boolean aboutToRunPassed = false;
1392
1393
					public void scheduled(IJobChangeEvent event) {
1394
						((ExtensionsPatternFilter) fFilteredTree.getPatternFilter()).clearMatchingLeafs();
1395
						selection = fExtensionTree.getSelection();
1396
					}
1397
1398
					public void aboutToRun(IJobChangeEvent event) {
1399
						aboutToRunPassed = true;
1400
					}
1401
1402
					/* 
1403
					 * Restores selection after tree refresh and expands tree up to matching leafs only
1404
					 */
1405
					public void done(IJobChangeEvent event) {
1406
						if (aboutToRunPassed) { // restoring is only required if the job actually ran
1407
							try {
1408
								fFilteredTree.setRedraw(false);
1409
								ExtensionsPatternFilter extensionsPatternFilter = ((ExtensionsPatternFilter) fFilteredTree.getPatternFilter());
1410
								fExtensionTree.collapseAll();
1411
								Object[] leafs = extensionsPatternFilter.getMatchingLeafsAsArray();
1412
								for (int i = 0; i < leafs.length; i++) {
1413
									fExtensionTree.expandToLevel(leafs[i], 0);
1414
								}
1415
								if (selection != null && !(selection.isEmpty())) {
1416
									fExtensionTree.setSelection(selection, true);
1417
								}
1418
							} finally {
1419
								fFilteredTree.setRedraw(true);
1420
							}
1421
						}
1422
					}
1423
				});
1424
				return job;
1425
			}
1426
1427
			protected long getRefreshJobDelay() {
1428
				// Prolonged job delay time is required because of the attribute search being more costly in nature.
1429
				// This can block input to the filter text severly. Thus it shouldn't happen when typing slowly.
1430
				// The delay of 1500ms is bypassed by some actions that use the filter text to initiate searches or clear the text.
1431
				long delay = (fBypassFilterDelay) ? 0 : REFRESHJOB_DELAY_TIME;
1432
				setBypassFilterDelay(false); // reset afterwards
1433
				return delay;
1434
			}
1435
1436
			protected void clearText() {
1437
				// bugfix: additional notification with textChanged() would cause a needless 2nd refresh job run
1438
				// which in turn would have a longer delay time than the 1st run.
1439
				setFilterText(""); //$NON-NLS-1$
1440
			}
1441
1442
			protected void textChanged() {
1443
				String filterText = getFilterString();
1444
				if (filterText != null && filterText.length() == 0) {
1445
					// clearing the filter text doesn't require a refresh job delay
1446
					setBypassFilterDelay(true);
1447
				}
1448
				super.textChanged();
1449
			}
1450
		};
1144
		parent.setData("filtered", Boolean.TRUE); //$NON-NLS-1$
1451
		parent.setData("filtered", Boolean.TRUE); //$NON-NLS-1$
1145
		return fFilteredTree.getViewer();
1452
		return fFilteredTree.getViewer();
1146
	}
1453
	}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/rows/ExtensionAttributeRow.java (-4 / +18 lines)
Lines 21-29 Link Here
21
import org.eclipse.pde.internal.ui.editor.text.PDETextHover;
21
import org.eclipse.pde.internal.ui.editor.text.PDETextHover;
22
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.SWT;
23
import org.eclipse.swt.widgets.*;
23
import org.eclipse.swt.widgets.*;
24
import org.eclipse.ui.PlatformUI;
25
import org.eclipse.ui.actions.ActionFactory;
24
import org.eclipse.ui.forms.IFormColors;
26
import org.eclipse.ui.forms.IFormColors;
25
import org.eclipse.ui.forms.widgets.FormToolkit;
27
import org.eclipse.ui.forms.widgets.FormToolkit;
26
import org.eclipse.ui.forms.widgets.Hyperlink;
28
import org.eclipse.ui.forms.widgets.Hyperlink;
29
import org.eclipse.ui.keys.IBindingService;
27
30
28
public abstract class ExtensionAttributeRow implements IControlHoverContentProvider {
31
public abstract class ExtensionAttributeRow implements IControlHoverContentProvider {
29
	protected IContextPart part;
32
	protected IContextPart part;
Lines 100-116 Link Here
100
	}
103
	}
101
104
102
	public String getHoverContent(Control c) {
105
	public String getHoverContent(Control c) {
103
		if (c instanceof Label || c instanceof Hyperlink)
106
		if (c instanceof Label || c instanceof Hyperlink) {
104
			return getDescription();
107
			// reveal keybinding for shortcut to filtering
108
			String filterBinding = ((IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class)).getBestActiveBindingFormattedFor(ActionFactory.FIND.getCommandId());
109
			String findKeybinding = (getValue().length() > 0) ? "<br><br>Press " + filterBinding + " within text to filter for this attribute." : ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
110
			String description = getDescription().trim(); // prettify help text
111
			if (description.length() > 0) {
112
				String first = String.valueOf(description.charAt(0)); // always make first letter uppercase
113
				return getDescription().replaceFirst(first, first.toUpperCase()) + findKeybinding;
114
			}
115
			return description;
116
		}
105
		if (c instanceof Text) {
117
		if (c instanceof Text) {
106
			String text = ((Text) c).getText();
118
			String text = ((Text) c).getText();
107
			ISchemaAttribute sAtt = getAttribute();
119
			ISchemaAttribute sAtt = getAttribute();
108
			String translated = null;
120
			String translated = null;
109
			if (input != null && sAtt != null && sAtt.isTranslatable() && text.startsWith("%")) //$NON-NLS-1$
121
			if (input != null && sAtt != null && sAtt.isTranslatable() && text.startsWith("%")) { //$NON-NLS-1$
110
				translated = input.getResourceString(text);
122
				translated = input.getResourceString(text);
111
			if (!text.equals(translated))
123
			}
124
			if (!text.equals(translated)) {
112
				return translated;
125
				return translated;
113
		}
126
		}
127
		}
114
		return null;
128
		return null;
115
	}
129
	}
116
130
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties (+6 lines)
Lines 1189-1194 Link Here
1189
EditorActions_revert = Re&vert
1189
EditorActions_revert = Re&vert
1190
Actions_open_label = &Open
1190
Actions_open_label = &Open
1191
Actions_delete_label = &Delete
1191
Actions_delete_label = &Delete
1192
Actions_filter_relatedPluginElements=&Filter Related
1193
Actions_search_relatedPluginElements=Search &Related
1192
Actions_synchronizeVersions_label = S&ynchronize Versions...
1194
Actions_synchronizeVersions_label = S&ynchronize Versions...
1193
1195
1194
Menus_new_label = &New
1196
Menus_new_label = &New
Lines 1275-1280 Link Here
1275
SearchAction_Declaration = Find Declaratio&n
1277
SearchAction_Declaration = Find Declaratio&n
1276
ShowDescriptionAction_label = Sho&w Description
1278
ShowDescriptionAction_label = Sho&w Description
1277
ShowDescriptionAction_title=Extension Point Description
1279
ShowDescriptionAction_title=Extension Point Description
1280
ShowAllExtensionsAction_label=Show all extensions
1281
HideUnfilteredExtensionsAction_label=Hide unfiltered extensions
1278
DefaultJUnitWorkspaceBlock_name=JUnit workspace location
1282
DefaultJUnitWorkspaceBlock_name=JUnit workspace location
1279
DefinitionPage_0=Definition
1283
DefinitionPage_0=Definition
1280
DefinitionPage_1=Target Definition
1284
DefinitionPage_1=Target Definition
Lines 1536-1541 Link Here
1536
ExtensionsPage_title=Extensions
1540
ExtensionsPage_title=Extensions
1537
ExtensionsPage_tabName=Extensions
1541
ExtensionsPage_tabName=Extensions
1538
ExtensionsPage_sortAlpha=Sort the Extensions alphabetically
1542
ExtensionsPage_sortAlpha=Sort the Extensions alphabetically
1543
ExtensionsPage_toggleExpandState=Toggle Expand State
1544
ExtensionsPage_searchWithExtensionsFilter=Extension Element Search
1539
ExtensionDetails_title=Extension Details
1545
ExtensionDetails_title=Extension Details
1540
ExtensionDetails_desc=Set the properties of the selected extension. Required fields are denoted by "*".
1546
ExtensionDetails_desc=Set the properties of the selected extension. Required fields are denoted by "*".
1541
ExtensionDetails_id=ID
1547
ExtensionDetails_id=ID
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/AttributesMatch.java (+45 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.search;
12
13
import org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor;
14
import org.eclipse.search.ui.text.Match;
15
16
/**
17
 * An extension to {@link Match} in order to present matching plugins which resulted 
18
 * in a search queried from the extensions page of the {@link ManifestEditor} 
19
 * 
20
 * @author Sascha Becher
21
 */
22
public class AttributesMatch extends Match {
23
24
	/**
25
	 * A constant expressing that the {@link Match} resulted in a search queried from 
26
	 * the extensions page of the {@link ManifestEditor} 
27
	 */
28
	public static final int UNIT_ATTRIBUTE_SEARCH_PATTERN = 3;
29
30
	protected String searchPattern;
31
32
	public AttributesMatch(Object element, String searchPattern) {
33
		super(element, UNIT_LINE, 0, 0);
34
		this.searchPattern = searchPattern;
35
	}
36
37
	public String getSearchPattern() {
38
		return searchPattern;
39
	}
40
41
	public int getBaseUnit() {
42
		return UNIT_ATTRIBUTE_SEARCH_PATTERN;
43
	}
44
45
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/ExtensionElementSearchOperation.java (+106 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.search;
12
13
import java.util.ArrayList;
14
import org.eclipse.core.runtime.IProgressMonitor;
15
import org.eclipse.pde.core.plugin.*;
16
import org.eclipse.pde.internal.core.plugin.PluginExtension;
17
import org.eclipse.pde.internal.core.plugin.PluginParent;
18
import org.eclipse.pde.internal.core.search.ISearchResultCollector;
19
import org.eclipse.pde.internal.core.search.PluginSearchInput;
20
21
/**
22
 * Search operation for finding extension elements within a plugin using the {@link ExtensionsPatternFilter}.
23
 * 
24
 * @author Sascha Becher
25
 */
26
public class ExtensionElementSearchOperation {
27
28
	protected PluginSearchInput fInput;
29
	private ISearchResultCollector fCollector;
30
31
	public ExtensionElementSearchOperation(PluginSearchInput input, ISearchResultCollector collector) {
32
		this.fInput = input;
33
		this.fCollector = collector;
34
	}
35
36
	public void execute(IProgressMonitor monitor) {
37
		IPluginModelBase[] entries = fInput.getSearchScope().getMatchingModels();
38
		monitor.beginTask("", entries.length); //$NON-NLS-1$
39
40
		try {
41
			for (int i = 0; i < entries.length; i++) {
42
				IPluginModelBase candidate = entries[i];
43
				visit(candidate);
44
				monitor.worked(1);
45
			}
46
		} finally {
47
			monitor.done();
48
		}
49
	}
50
51
	private void visit(IPluginModelBase model) {
52
		ArrayList matches = findMatch(model);
53
		for (int i = 0; i < matches.size(); i++) {
54
			fCollector.accept(matches.get(i));
55
		}
56
	}
57
58
	private ArrayList findMatch(IPluginModelBase model) {
59
		ArrayList result = new ArrayList();
60
		int searchLimit = fInput.getSearchLimit();
61
		if (fInput.getSearchElement() == PluginSearchInput.ELEMENT_PLUGIN) {
62
			if (searchLimit != PluginSearchInput.LIMIT_REFERENCES)
63
				findPluginDeclaration(model, result);
64
			if (searchLimit != PluginSearchInput.LIMIT_DECLARATIONS)
65
				findPluginReferences(model, result);
66
		}
67
		return result;
68
	}
69
70
	private void findPluginDeclaration(IPluginModelBase model, ArrayList result) {
71
		IPluginBase pluginBase = model.getPluginBase();
72
		ExtensionsPatternFilter filter = new ExtensionsPatternFilter();
73
		filter.setPattern(fInput.getSearchString());
74
		IPluginExtension[] extensions = pluginBase.getExtensions();
75
		for (int i = 0; i < extensions.length; i++) {
76
			PluginExtension pluginExtension = (PluginExtension) extensions[i];
77
			boolean foundAny = traversePluginElements(pluginExtension, filter);
78
			if (foundAny && pluginBase instanceof IPlugin) {
79
				result.add(pluginBase);
80
				return;
81
			}
82
		}
83
	}
84
85
	private boolean traversePluginElements(PluginParent pluginParent, ExtensionsPatternFilter filter) {
86
		IPluginObject[] pluginObjects = pluginParent.getChildren();
87
		if (pluginObjects != null) {
88
			for (int i = 0; i < pluginObjects.length; i++) {
89
				boolean foundAny = traversePluginElements((PluginParent) pluginObjects[i], filter);
90
				if (foundAny) {
91
					return true;
92
				}
93
			}
94
		}
95
		return filter.isLeafMatch(null, pluginParent);
96
	}
97
98
	private void findPluginReferences(IPluginModelBase model, ArrayList result) {
99
		IPluginBase pluginBase = model.getPluginBase();
100
		IPluginImport[] imports = pluginBase.getImports();
101
		for (int i = 0; i < imports.length; i++) {
102
			findPluginDeclaration(imports[i].getPluginModel(), result);
103
		}
104
	}
105
106
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/ExtensionsPatternFilter.java (+309 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.search;
12
13
import java.util.*;
14
import java.util.regex.Matcher;
15
import java.util.regex.Pattern;
16
import org.eclipse.jface.viewers.Viewer;
17
import org.eclipse.pde.core.plugin.*;
18
import org.eclipse.pde.internal.core.bundle.BundlePlugin;
19
import org.eclipse.pde.internal.ui.util.ExtensionsFilterUtil;
20
import org.eclipse.ui.dialogs.PatternFilter;
21
22
/**
23
 * An extended filtering capability for the filtered tree of ExtensionsPage. The
24
 * search criteria is splitted by / first. The resulting values are used to
25
 * perform a search on all node's values. All elements fitting at least one of
26
 * the split values will be displayed. This extensions does not compromise the
27
 * default filtering behaviour of the tree while providing the ability to
28
 * highlight related items such as commands along with their command images,
29
 * handlers, menu entries and activities.
30
 * 
31
 * @see org.eclipse.ui.dialogs.FilteredTree
32
 * @since 3.8
33
 * 
34
 */
35
public class ExtensionsPatternFilter extends PatternFilter {
36
37
	/**
38
	 * Limits the maximum number of attributes handled by the filter
39
	 */
40
	public static final int ATTRIBUTE_LIMIT = 30;
41
42
	protected String fSearchPattern;
43
44
	protected Set fAttributes = new HashSet();
45
	protected final Set fMatchingLeafs = new HashSet();
46
	protected final Set fFoundAnyElementsCache = new HashSet();
47
48
	/**
49
	 * Check if the leaf element is a match with the filter text. The
50
	 * default behavior checks that the label of the element is a match.
51
	 * 
52
	 * Subclasses should override this method.
53
	 * 
54
	 * @param viewer
55
	 *            the viewer that contains the element
56
	 * @param element
57
	 *            the tree element to check
58
	 * @return true if the given element's label matches the filter text
59
	 */
60
	protected boolean isLeafMatch(Viewer viewer, Object element) {
61
		// match label; default behaviour
62
		if (viewer != null && super.isLeafMatch(viewer, element)) {
63
			return true;
64
		}
65
66
		// match all splitted attribute's values of IPluginElement against splitted filter patterns
67
		if (element instanceof IPluginElement) {
68
			return doIsLeafMatch((IPluginElement) element);
69
		}
70
		return false;
71
	}
72
73
	protected boolean doIsLeafMatch(IPluginElement pluginElement) {
74
		List syntheticAttributes = ExtensionsFilterUtil.handlePropertyTester(pluginElement);
75
		if (fAttributes != null && fAttributes.size() > 0) {
76
			int attributeNumber = 0;
77
			for (Iterator iterator = fAttributes.iterator(); iterator.hasNext();) {
78
				String valuePattern = (String) iterator.next();
79
				if (attributeNumber < fAttributes.size() && attributeNumber < ATTRIBUTE_LIMIT) {
80
					boolean quoted = isQuoted(valuePattern);
81
					if (valuePattern != null && valuePattern.length() > 0) {
82
						int attributeCount = pluginElement.getAttributeCount();
83
						IPluginAttribute[] pluginAttributes = pluginElement.getAttributes();
84
85
						for (int i = 0; i < attributeCount; i++) {
86
							IPluginAttribute attributeElement = pluginAttributes[i];
87
							if (attributeElement != null && attributeElement.getValue() != null) {
88
								String[] attributes = getAttributeSplit(attributeElement.getValue(), quoted);
89
								if (attributes != null) {
90
									List attributeList = new ArrayList(Arrays.asList(attributes));
91
									attributeList.addAll(syntheticAttributes);
92
									if (matchWithAttributes(pluginElement, valuePattern, attributeList, quoted)) {
93
										return true;
94
									}
95
								}
96
							}
97
						}
98
						if (valuePattern.equalsIgnoreCase(pluginElement.getName())) {
99
							return true;
100
						}
101
					}
102
				}
103
				attributeNumber++;
104
			}
105
		}
106
		return false;
107
	}
108
109
	private boolean matchWithAttributes(IPluginElement pluginElement, String valuePattern, List attributeList, boolean quoted) {
110
		for (int k = 0; k < attributeList.size(); k++) {
111
			String attribute = (String) attributeList.get(k);
112
			if (attribute != null && attribute.length() > 0) {
113
				if (!attribute.startsWith("%")) { //$NON-NLS-1$
114
					int delimiterPosition = attribute.indexOf('?'); // strip right of '?'
115
					if (delimiterPosition != -1) {
116
						attribute = attribute.substring(0, delimiterPosition);
117
					}
118
				} else {
119
					String resourceValue = pluginElement.getResourceString(attribute);
120
					attribute = (resourceValue != null && resourceValue.length() > 0) ? resourceValue : attribute;
121
				}
122
				String pattern = valuePattern.toLowerCase();
123
				if (quoted) {
124
					pattern = pattern.substring(1, pattern.length() - 1);
125
				}
126
				if (attribute.toLowerCase().equals(pattern)) {
127
					return true;
128
				}
129
			}
130
		}
131
		return false;
132
	}
133
134
	private static boolean isQuoted(String value) {
135
		return value.startsWith("\"") && value.endsWith("\""); //$NON-NLS-1$ //$NON-NLS-2$
136
	}
137
138
	private static String[] getAttributeSplit(String text, boolean quoted) {
139
		if (text.length() < 2) {
140
			return null;
141
		}
142
		if (!quoted) {
143
			return text.replaceAll("/{1,}", "/").split("/"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
144
		}
145
		return new String[] {text};
146
	}
147
148
	public boolean isElementVisible(Viewer viewer, Object element) {
149
		if (fFoundAnyElementsCache.contains(element)) {
150
			return true;
151
		}
152
		return isLeafMatch(viewer, element);
153
	}
154
155
	public Object[] filter(Viewer viewer, Object parent, Object[] elements) {
156
		if (parent != null && parent instanceof BundlePlugin) {
157
			if (fFoundAnyElementsCache.size() == 0 && fSearchPattern != null && fSearchPattern.length() > 0) {
158
				BundlePlugin pluginPlugin = (BundlePlugin) parent;
159
				doFilter(viewer, pluginPlugin, pluginPlugin.getExtensions(), false);
160
			}
161
		}
162
		if (fFoundAnyElementsCache.size() > 0) {
163
			List found = new ArrayList();
164
			for (int i = 0; i < elements.length; i++) {
165
				if (fFoundAnyElementsCache.contains(elements[i])) {
166
					found.add(elements[i]);
167
				}
168
			}
169
			return found.toArray();
170
		}
171
		return super.filter(viewer, parent, elements);
172
	}
173
174
	protected boolean doFilter(Viewer viewer, Object parent, IPluginObject[] children, boolean addChildren) {
175
		boolean isParentMatch = fFoundAnyElementsCache.contains(parent) ? true : false;
176
177
		// find leaf matches
178
		boolean isAnyLeafMatch = false;
179
		for (int j = 0; j < children.length; j++) {
180
			IPluginObject iPluginObject = children[j];
181
			boolean isChildMatch = true;
182
			if (!isParentMatch || children.length > 0) {
183
				isChildMatch = this.isLeafMatch(viewer, iPluginObject);
184
				isAnyLeafMatch |= isChildMatch;
185
				if (isChildMatch) {
186
					fMatchingLeafs.add(iPluginObject);
187
				}
188
			}
189
			if (isChildMatch || addChildren) {
190
				fFoundAnyElementsCache.add(iPluginObject);
191
			}
192
		}
193
194
		// traverse children when available
195
		boolean isAnyChildMatch = false;
196
		for (int i = 0; i < children.length; i++) {
197
			IPluginObject iPluginObject = children[i];
198
			if (iPluginObject instanceof IPluginParent) {
199
				IPluginParent pluginElement = (IPluginParent) iPluginObject;
200
				if (pluginElement.getChildren().length > 0) {
201
					boolean isChildrenMatch = doFilter(viewer, pluginElement, pluginElement.getChildren(), addChildren | fMatchingLeafs.contains(pluginElement));
202
					isAnyChildMatch |= isChildrenMatch;
203
					if (isChildrenMatch) {
204
						fFoundAnyElementsCache.add(pluginElement);
205
					}
206
				}
207
			}
208
		}
209
		return isAnyChildMatch | isAnyLeafMatch;
210
	}
211
212
	/**
213
	 * Splits a string at the occurrences of <code>/</code>. Any quoted parts of the <code>filterText</code>
214
	 * are not to be splitted but remain as a whole along with the quotation.
215
	 *   
216
	 * @param filterText text to split
217
	 * @return split array
218
	 */
219
	protected String[] splitWithQuoting(String filterText) {
220
		// remove multiple separators
221
		String text = filterText.replaceAll("/{1,}", "/"); //$NON-NLS-1$//$NON-NLS-2$ 
222
		boolean containsQuoting = text.indexOf('\"') != -1;
223
		if (containsQuoting) {
224
			// remove multiple quotes
225
			text = text.replaceAll("\"{1,}", "\""); //$NON-NLS-1$//$NON-NLS-2$
226
			// treat quoted text as a whole, thus enables searching for file paths
227
			if (text.replaceAll("[^\"]", "").length() % 2 == 0) { //$NON-NLS-1$//$NON-NLS-2$
228
				List patterns = new ArrayList();
229
				List matchList = new ArrayList();
230
				Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'"); //$NON-NLS-1$
231
				Matcher regexMatcher = regex.matcher(text);
232
				while (regexMatcher.find()) {
233
					matchList.add(regexMatcher.group());
234
				}
235
				for (int i = 0; i < matchList.size(); i++) {
236
					String element = (String) matchList.get(i);
237
					if (isQuoted(element)) {
238
						patterns.add(element);
239
					} else {
240
						String[] elements = element.split("/"); //$NON-NLS-1$
241
						for (int k = 0; k < elements.length; k++) {
242
							String splitted = elements[k];
243
							if (splitted.length() > 0) {
244
								patterns.add(splitted);
245
							}
246
						}
247
					}
248
				}
249
				return (String[]) patterns.toArray(new String[0]);
250
			} // filter text must have erroneous quoting, replacing all
251
			text = text.replaceAll("[\"]", ""); //$NON-NLS-1$ //$NON-NLS-2$
252
		}
253
		return text.split("/"); //$NON-NLS-1$
254
	}
255
256
	/**
257
	 * Enables the filter to temporarily display arbitrary elements
258
	 * 
259
	 * @param element
260
	 */
261
	public boolean addElement(Object element) {
262
		return fFoundAnyElementsCache.add(element);
263
	}
264
265
	/**
266
	 * Removes elements from the filter
267
	 * 
268
	 * @param element
269
	 */
270
	public boolean removeElement(Object element) {
271
		return fFoundAnyElementsCache.remove(element);
272
	}
273
274
	/*
275
	 * The pattern string for which this filter should select 
276
	 * elements in the viewer.
277
	 * 
278
	 * @see org.eclipse.ui.dialogs.PatternFilter#setPattern(java.lang.String)
279
	 */
280
	public final void setPattern(String patternString) {
281
		super.setPattern(patternString);
282
		fSearchPattern = patternString;
283
		String[] patterns = (patternString != null) ? splitWithQuoting(patternString) : new String[] {};
284
		fAttributes.clear();
285
		fAttributes.addAll(Arrays.asList(patterns));
286
		fFoundAnyElementsCache.clear();
287
	}
288
289
	public String getPattern() {
290
		return fSearchPattern;
291
	}
292
293
	public void clearMatchingLeafs() {
294
		fMatchingLeafs.clear();
295
	}
296
297
	public Object[] getMatchingLeafsAsArray() {
298
		return fMatchingLeafs.toArray();
299
	}
300
301
	public Set getMatchingLeafs() {
302
		return fMatchingLeafs;
303
	}
304
305
	public boolean containsElement(Object element) {
306
		return fFoundAnyElementsCache.contains(element);
307
	}
308
309
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/FindExtensionsByAttributeQuery.java (+88 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.search;
12
13
import org.eclipse.core.runtime.*;
14
import org.eclipse.pde.core.plugin.IPlugin;
15
import org.eclipse.pde.internal.core.search.ISearchResultCollector;
16
import org.eclipse.pde.internal.core.search.PluginSearchInput;
17
import org.eclipse.search.ui.ISearchQuery;
18
import org.eclipse.search.ui.ISearchResult;
19
import org.eclipse.search.ui.text.AbstractTextSearchResult;
20
21
/**
22
 * @author Sascha Becher
23
 */
24
public class FindExtensionsByAttributeQuery implements ISearchQuery {
25
26
	private SearchResult fSearchResult;
27
28
	private PluginSearchInput fSearchInput;
29
30
	public FindExtensionsByAttributeQuery(PluginSearchInput input) {
31
		fSearchInput = input;
32
	}
33
34
	/* (non-Javadoc)
35
	 * @see org.eclipse.search.ui.ISearchQuery#run(org.eclipse.core.runtime.IProgressMonitor)
36
	 */
37
	public IStatus run(IProgressMonitor monitor) throws OperationCanceledException {
38
		final AbstractTextSearchResult result = (AbstractTextSearchResult) getSearchResult();
39
		result.removeAll();
40
		ISearchResultCollector collector = new ISearchResultCollector() {
41
			public void accept(Object match) {
42
				if (match instanceof IPlugin) {
43
					IPlugin plugin = (IPlugin) match;
44
					result.addMatch(new AttributesMatch(plugin, fSearchInput.getSearchString()));
45
				}
46
			}
47
		};
48
		ExtensionElementSearchOperation op = new ExtensionElementSearchOperation(fSearchInput, collector);
49
		op.execute(monitor);
50
		monitor.done();
51
		return Status.OK_STATUS;
52
	}
53
54
	/* (non-Javadoc)
55
	 * @see org.eclipse.search.ui.ISearchQuery#getLabel()
56
	 */
57
	public String getLabel() {
58
		return fSearchInput.getSearchString();
59
	}
60
61
	/* (non-Javadoc)
62
	 * @see org.eclipse.search.ui.ISearchQuery#canRerun()
63
	 */
64
	public boolean canRerun() {
65
		return true;
66
	}
67
68
	/* (non-Javadoc)
69
	 * @see org.eclipse.search.ui.ISearchQuery#canRunInBackground()
70
	 */
71
	public boolean canRunInBackground() {
72
		return true;
73
	}
74
75
	/* (non-Javadoc)
76
	 * @see org.eclipse.search.ui.ISearchQuery#getSearchResult()
77
	 */
78
	public ISearchResult getSearchResult() {
79
		if (fSearchResult == null)
80
			fSearchResult = new SearchResult(this);
81
		return fSearchResult;
82
	}
83
84
	public PluginSearchInput getPluginSearchInput() {
85
		return fSearchInput;
86
	}
87
88
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/ManifestEditorOpener.java (-5 / +25 lines)
Lines 7-12 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.search;
12
package org.eclipse.pde.internal.ui.search;
12
13
Lines 16-25 Link Here
16
import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
17
import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
17
import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
18
import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
18
import org.eclipse.pde.internal.core.text.plugin.PluginObjectNode;
19
import org.eclipse.pde.internal.core.text.plugin.PluginObjectNode;
19
import org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor;
20
import org.eclipse.pde.internal.ui.editor.plugin.*;
20
import org.eclipse.search.ui.text.Match;
21
import org.eclipse.search.ui.text.Match;
22
import org.eclipse.swt.widgets.Text;
21
import org.eclipse.ui.IEditorPart;
23
import org.eclipse.ui.IEditorPart;
22
import org.eclipse.ui.PartInitException;
24
import org.eclipse.ui.PartInitException;
25
import org.eclipse.ui.forms.IFormPart;
26
import org.eclipse.ui.forms.IManagedForm;
27
import org.eclipse.ui.forms.editor.IFormPage;
23
import org.osgi.framework.Constants;
28
import org.osgi.framework.Constants;
24
29
25
// TODO this needs a rewrite
30
// TODO this needs a rewrite
Lines 30-39 Link Here
30
		editorPart = ManifestEditor.open(match.getElement(), true);
35
		editorPart = ManifestEditor.open(match.getElement(), true);
31
		if (editorPart != null && editorPart instanceof ManifestEditor) {
36
		if (editorPart != null && editorPart instanceof ManifestEditor) {
32
			ManifestEditor editor = (ManifestEditor) editorPart;
37
			ManifestEditor editor = (ManifestEditor) editorPart;
33
			IDocument doc = editor.getDocument(match);
38
			if (match.getBaseUnit() != AttributesMatch.UNIT_ATTRIBUTE_SEARCH_PATTERN) {
34
			if (doc != null) {
39
				IDocument doc = editor.getDocument(match);
35
				Match exact = findExactMatch(doc, match, editor);
40
				if (doc != null) {
36
				editor.openToSourcePage(match.getElement(), exact.getOffset(), exact.getLength());
41
					Match exact = findExactMatch(doc, match, editor);
42
					editor.openToSourcePage(match.getElement(), exact.getOffset(), exact.getLength());
43
				}
44
			} else { // open to extensions page and initialize filter with search result's pattern text
45
				IFormPage page = editor.setActivePage(ExtensionsPage.PAGE_ID);
46
				IManagedForm form = page.getManagedForm();
47
				IFormPart parts[] = form.getParts();
48
				if (parts != null && parts.length > 0) {
49
					ExtensionsSection section = (ExtensionsSection) parts[0];
50
					String searchPattern = ((AttributesMatch) match).getSearchPattern();
51
					Text filterText = section.getFormFilteredTree().getFilterControl();
52
					if (!filterText.getText().equals(searchPattern)) {
53
						section.setBypassFilterDelay(true); // force immediate job run
54
						filterText.setText(searchPattern);
55
					}
56
				}
37
			}
57
			}
38
		}
58
		}
39
		return editorPart;
59
		return editorPart;
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/SearchResult.java (-1 / +8 lines)
Lines 7-12 Link Here
7
 * 
7
 * 
8
 *  Contributors:
8
 *  Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.search;
12
package org.eclipse.pde.internal.ui.search;
12
13
Lines 29-37 Link Here
29
30
30
public class SearchResult extends AbstractTextSearchResult implements IEditorMatchAdapter {
31
public class SearchResult extends AbstractTextSearchResult implements IEditorMatchAdapter {
31
	protected ISearchQuery fQuery;
32
	protected ISearchQuery fQuery;
33
	private final ImageDescriptor fImage;
32
34
33
	public SearchResult(ISearchQuery query) {
35
	public SearchResult(ISearchQuery query) {
34
		fQuery = query;
36
		fQuery = query;
37
		if (fQuery instanceof FindExtensionsByAttributeQuery) {
38
			fImage = PDEPluginImages.DESC_ESEARCH_OBJ;
39
		} else {
40
			fImage = PDEPluginImages.DESC_PSEARCH_OBJ;
41
		}
35
	}
42
	}
36
43
37
	/* (non-Javadoc)
44
	/* (non-Javadoc)
Lines 60-66 Link Here
60
	 * @see org.eclipse.search.ui.ISearchResult#getImageDescriptor()
67
	 * @see org.eclipse.search.ui.ISearchResult#getImageDescriptor()
61
	 */
68
	 */
62
	public ImageDescriptor getImageDescriptor() {
69
	public ImageDescriptor getImageDescriptor() {
63
		return PDEPluginImages.DESC_PSEARCH_OBJ;
70
		return fImage;
64
	}
71
	}
65
72
66
	/* (non-Javadoc)
73
	/* (non-Javadoc)
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/util/AcceleratedTreeScrolling.java (+104 lines)
Added Link Here
1
/*******************************************************************************
2
 *  Copyright (c) 2011, 2012 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
7
 * 
8
 *  Contributors:
9
 *     Sascha Becher <s.becher@qualitype.de> - bug 360894
10
 *******************************************************************************/
11
package org.eclipse.pde.internal.ui.util;
12
13
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.events.MouseEvent;
15
import org.eclipse.swt.events.MouseWheelListener;
16
import org.eclipse.swt.widgets.Tree;
17
import org.eclipse.swt.widgets.TreeItem;
18
19
/**
20
 * Accelerated tree scrolling with the mouse wheel during which MOD1 (Ctrl) key modifier has been pressed
21
 *  
22
 * @author Sascha Becher
23
 */
24
public class AcceleratedTreeScrolling implements MouseWheelListener {
25
26
	private Tree fTree;
27
	private int fSkipLines;
28
29
	/**
30
	 *  Accelerated mouse wheel scrolling during which the MOD1 (Ctrl) key modifier has been pressed
31
	 *  
32
	 * @param tree tree to scroll
33
	 * @param skipLines lines to scroll
34
	 */
35
	public AcceleratedTreeScrolling(Tree tree, int skipLines) {
36
		fTree = tree;
37
		fSkipLines = (skipLines > 1) ? skipLines : 2;
38
	}
39
40
	public void mouseScrolled(MouseEvent e) {
41
		// scroll only when MOD1 is pressed
42
		if ((e.stateMask & SWT.MOD1) == SWT.MOD1 && fTree != null) {
43
			TreeItem item = fTree.getTopItem();
44
			if (item != null) {
45
				TreeItem nextItem = item;
46
				for (int i = 0; i < fSkipLines; i++) {
47
					TreeItem foundItem = null;
48
					if (e.count < 0) // determines scrolling direction
49
						foundItem = NextItem(fTree, nextItem);
50
					else
51
						foundItem = PreviousItem(fTree, nextItem);
52
					if (foundItem == null) {
53
						break;
54
					}
55
					nextItem = foundItem;
56
				}
57
				fTree.setTopItem(nextItem);
58
			}
59
		}
60
	}
61
62
	TreeItem PreviousItem(Tree tree, TreeItem item) {
63
		if (item == null)
64
			return null;
65
		TreeItem childItem = item;
66
		TreeItem parentItem = childItem.getParentItem();
67
		int index = parentItem == null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
68
		if (index == 0) {
69
			return parentItem;
70
		}
71
		TreeItem nextItem = parentItem == null ? tree.getItem(index - 1) : parentItem.getItem(index - 1);
72
		int count = nextItem.getItemCount();
73
		while (count > 0 && nextItem.getExpanded()) {
74
			nextItem = nextItem.getItem(count - 1);
75
			count = nextItem.getItemCount();
76
		}
77
		return nextItem;
78
	}
79
80
	TreeItem NextItem(Tree tree, TreeItem item) {
81
		if (item == null)
82
			return null;
83
		if (item.getExpanded()) {
84
			return item.getItem(0);
85
		}
86
		TreeItem childItem = item;
87
		TreeItem parentItem = childItem.getParentItem();
88
		int index = parentItem == null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
89
		int count = parentItem == null ? tree.getItemCount() : parentItem.getItemCount();
90
		while (true) {
91
			if (index + 1 < count) {
92
				return parentItem == null ? tree.getItem(index + 1) : parentItem.getItem(index + 1);
93
			}
94
			if (parentItem == null) {
95
				return null;
96
			}
97
			childItem = parentItem;
98
			parentItem = childItem.getParentItem();
99
			index = parentItem == null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
100
			count = parentItem == null ? tree.getItemCount() : parentItem.getItemCount();
101
		}
102
	}
103
104
}
(-)a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/util/ExtensionsFilterUtil.java (+294 lines)
Added Link Here
1
package org.eclipse.pde.internal.ui.util;
2
3
import java.util.*;
4
import org.eclipse.jface.viewers.IStructuredSelection;
5
import org.eclipse.pde.core.plugin.*;
6
import org.eclipse.pde.internal.core.text.plugin.PluginNode;
7
import org.eclipse.pde.internal.ui.search.ExtensionsPatternFilter;
8
9
public class ExtensionsFilterUtil {
10
11
	/**
12
	 * <code>id, class, commandId, pattern, locationURI, defaultHandler, variable
13
	 * property, contentTypeId, path, plugin, perspective, targetID</code>
14
	 */
15
	// TODO related attributes might be configured through preferences
16
	public static final String[] RELATED_ATTRIBUTES = {"id", //$NON-NLS-1$
17
			"class", "commandId", "pattern", "locationURI", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 
18
			"defaultHandler", "variable", "property", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
19
			"contentTypeId", "path", "plugin", "perspective", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
20
			"targetID"}; //$NON-NLS-1$
21
22
	public static final String ATTRIBUTE_ACTIVITYID = "activityId"; //$NON-NLS-1$
23
	public static final String ATTRIBUTE_CATEGORY = "category"; //$NON-NLS-1$
24
	public static final String ATTRIBUTE_CATEGORYID = "categoryId"; //$NON-NLS-1$
25
	public static final String ATTRIBUTE_COMMANDID = "commandId"; //$NON-NLS-1$
26
	public static final String ATTRIBUTE_DEFAULTHANDLER = "defaultHandler"; //$NON-NLS-1$
27
	public static final String ATTRIBUTE_ID = "id"; //$NON-NLS-1$
28
	public static final String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
29
	public static final String ATTRIBUTE_NAMESPACE = "namespace"; //$NON-NLS-1$
30
	public static final String ATTRIBUTE_PROPERTIES = "properties"; //$NON-NLS-1$
31
	public static final String ATTRIBUTE_PATTERN = "pattern"; //$NON-NLS-1$
32
	public static final String ATTRIBUTE_REQUIREDACTIVITYID = "requiredActivityId"; //$NON-NLS-1$
33
	public static final String ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$
34
35
	public static final String ELEMENT_ACATEGORY = "org.eclipse.ui.activities.category"; //$NON-NLS-1$
36
	public static final String ELEMENT_ACTIVITY = "org.eclipse.ui.activities.activity"; //$NON-NLS-1$
37
	public static final String ELEMENT_AR_BINDING = "org.eclipse.ui.activities.activityRequirementBinding"; //$NON-NLS-1$
38
	public static final String ELEMENT_CA_BINDING = "org.eclipse.ui.activities.categoryActivityBinding"; //$NON-NLS-1$
39
	public static final String ELEMENT_COMMAND = "org.eclipse.ui.commands.command"; //$NON-NLS-1$
40
	public static final String ELEMENT_EQUALS = "org.eclipse.ui.handlers.equals"; //$NON-NLS-1$
41
	public static final String ELEMENT_HELP_TOC = "org.eclipse.help.toc.toc"; //$NON-NLS-1$
42
	public static final String ELEMENT_INSTANCEOF = "org.eclipse.ui.handlers.instanceof"; //$NON-NLS-1$
43
	public static final String ELEMENT_MENU_COMMAND = "org.eclipse.ui.menus.command"; //$NON-NLS-1$
44
	public static final String ELEMENT_PATTERNBINDING = "org.eclipse.ui.activities.activityPatternBinding"; //$NON-NLS-1$
45
	public static final String ELEMENT_PROPERTYTESTER = "org.eclipse.core.expressions.propertyTesters.propertyTester"; //$NON-NLS-1$
46
47
	public static final String[] HIGH_PRIORITY_ELEMENTS = new String[] {ELEMENT_COMMAND, ELEMENT_MENU_COMMAND, ELEMENT_INSTANCEOF, ELEMENT_EQUALS};
48
	public static final String[] LOW_PRIORITY_ELEMENTS = new String[] {ELEMENT_CA_BINDING, ELEMENT_AR_BINDING, ELEMENT_HELP_TOC};
49
50
	public static final Map CUSTOM_RELATIONS;
51
52
	static {
53
		CUSTOM_RELATIONS = new HashMap();
54
		CUSTOM_RELATIONS.put(ELEMENT_COMMAND, new String[] {ATTRIBUTE_ID, ATTRIBUTE_DEFAULTHANDLER});
55
		CUSTOM_RELATIONS.put(ELEMENT_INSTANCEOF, new String[] {ATTRIBUTE_VALUE});
56
		CUSTOM_RELATIONS.put(ELEMENT_EQUALS, new String[] {ATTRIBUTE_VALUE});
57
		CUSTOM_RELATIONS.put(ELEMENT_MENU_COMMAND, new String[] {ATTRIBUTE_COMMANDID, ATTRIBUTE_ID});
58
		CUSTOM_RELATIONS.put(ELEMENT_CA_BINDING, new String[] {ATTRIBUTE_ACTIVITYID, ATTRIBUTE_CATEGORYID});
59
		CUSTOM_RELATIONS.put(ELEMENT_AR_BINDING, new String[] {ATTRIBUTE_REQUIREDACTIVITYID, ATTRIBUTE_ACTIVITYID});
60
		CUSTOM_RELATIONS.put(ELEMENT_HELP_TOC, new String[] {ATTRIBUTE_CATEGORY});
61
	}
62
63
	public static boolean add(Set pattern, IPluginElement pluginElement, String attributeName) {
64
		IPluginAttribute attribute = pluginElement.getAttribute(attributeName);
65
		if (attribute != null) {
66
			return add(pattern, attribute.getValue());
67
		}
68
		return false;
69
	}
70
71
	public static boolean add(Set pattern, String value) {
72
		if (value != null && value.length() > 0) {
73
			String trimmed = value.trim();
74
			if (isNotBoolean(trimmed)) {
75
				return pattern.add(trimmed);
76
			}
77
		}
78
		return false;
79
	}
80
81
	public static void addAll(Set pattern, IPluginElement pluginElement, String elementName) {
82
		Object attributes = CUSTOM_RELATIONS.get(elementName);
83
		if (attributes != null) {
84
			String[] attributesArray = (String[]) attributes;
85
			for (int i = 0; i < attributesArray.length; i++) {
86
				add(pattern, pluginElement, attributesArray[i]);
87
			}
88
		}
89
	}
90
91
	/**
92
	 * Get unique plugin element name. This will work only with 
93
	 * editable plugin models, otherwise <code>null</code> is returned.
94
	 * 
95
	 * @param pluginElement the element to get the unique name from
96
	 * @return extensionpoint name concatenated with the element name
97
	 */
98
	public static String getElementPath(IPluginElement pluginElement) {
99
		IPluginObject element = pluginElement;
100
		while (element.getParent() != null && !(element.getParent() instanceof PluginNode)) {
101
			element = element.getParent();
102
		}
103
		if (element instanceof IPluginExtension) {
104
			IPluginExtension extension = (IPluginExtension) element;
105
			return extension.getPoint() + '.' + pluginElement.getName();
106
		}
107
		return null;
108
	}
109
110
	/**
111
	 * Obtains common attributes from selected plugin element to filter tree for; 
112
	 * attribute values are concatenated with a slash and set as filter text
113
	 * 
114
	 * @param selection selected items to filter for related plugin elements 
115
	 */
116
	public static String getFilterRelatedPattern(IStructuredSelection selection) {
117
		Iterator it = selection.iterator();
118
		Set filterPatterns = new HashSet();
119
		while (it.hasNext()) {
120
			Object treeElement = it.next();
121
			if (treeElement instanceof IPluginElement) {
122
				IPluginElement pluginElement = (IPluginElement) treeElement;
123
				Set customAttributes = getCustomRelations(pluginElement);
124
				if (customAttributes.size() == 0) {
125
					for (int i = 0; i < RELATED_ATTRIBUTES.length; i++) {
126
						String property = RELATED_ATTRIBUTES[i];
127
						IPluginAttribute attribute = pluginElement.getAttribute(property);
128
						if (attribute != null && attribute.getValue() != null && attribute.getValue().length() > 0) {
129
							String value = attribute.getValue();
130
							if (!value.startsWith("%")) { //$NON-NLS-1$
131
								int delimiterPosition = value.indexOf('?'); // split before '?' and right after last '='
132
								if (delimiterPosition == -1) {
133
									if (!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) { //$NON-NLS-1$ //$NON-NLS-2$
134
										filterPatterns.add(value);
135
									}
136
								} else {
137
									filterPatterns.add(value.substring(0, delimiterPosition));
138
									int position = value.lastIndexOf('=');
139
									if (position != -1) {
140
										filterPatterns.add(value.substring(position + 1, value.length()));
141
									}
142
								}
143
							} else {
144
								String resourceValue = pluginElement.getResourceString(value);
145
								if ((resourceValue != null && resourceValue.length() > 0)) {
146
									filterPatterns.add(resourceValue);
147
								}
148
							}
149
						}
150
					}
151
				} else {
152
					filterPatterns.addAll(customAttributes);
153
				}
154
			}
155
		}
156
		StringBuffer patternBuffer = new StringBuffer();
157
		int attributeCount = 0;
158
		for (Iterator iterator = filterPatterns.iterator(); iterator.hasNext();) {
159
			attributeCount++;
160
			Object pattern = iterator.next();
161
			if (attributeCount < ExtensionsPatternFilter.ATTRIBUTE_LIMIT) {
162
				if (pattern != null) {
163
					patternBuffer.append(pattern);
164
					patternBuffer.append('/');
165
				}
166
			}
167
		}
168
169
		String filterPattern = patternBuffer.toString();
170
		if (filterPattern.endsWith("/")) { //$NON-NLS-1$
171
			filterPattern = filterPattern.substring(0, filterPattern.length() - 1);
172
		}
173
		return filterPattern;
174
	}
175
176
	public static Set getCustomRelations(IPluginElement pluginElement) {
177
		Set customAttributes = new TreeSet();
178
		String elementName = (pluginElement != null) ? getElementPath(pluginElement) : null;
179
		if (elementName == null) {
180
			return customAttributes;
181
		} else if (addMatchingElements(customAttributes, pluginElement, elementName, HIGH_PRIORITY_ELEMENTS)) {
182
		} else if (ELEMENT_ACTIVITY.equalsIgnoreCase(elementName) || ELEMENT_ACATEGORY.equals(elementName)) {
183
			if (!add(customAttributes, pluginElement, ATTRIBUTE_ID)) {
184
				add(customAttributes, pluginElement, ATTRIBUTE_NAME);
185
			}
186
		} else if (ELEMENT_PROPERTYTESTER.equalsIgnoreCase(elementName)) {
187
			customAttributes = handlePropertyTester(customAttributes, pluginElement);
188
			add(customAttributes, pluginElement, ATTRIBUTE_ID);
189
		} else if (ELEMENT_PATTERNBINDING.equals(elementName)) {
190
			add(customAttributes, pluginElement, ATTRIBUTE_ACTIVITYID);
191
			String attributeValue = pluginElement.getAttribute(ATTRIBUTE_PATTERN).getValue();
192
			if (attributeValue.length() > 0) {
193
				int lastSeparator = attributeValue.lastIndexOf('/');
194
				if (lastSeparator > 0 && attributeValue.length() > lastSeparator + 1) {
195
					customAttributes.add(attributeValue.substring(lastSeparator + 1, attributeValue.length()));
196
				}
197
			}
198
		} else {
199
			addMatchingElements(customAttributes, pluginElement, elementName, LOW_PRIORITY_ELEMENTS);
200
		}
201
		return customAttributes;
202
	}
203
204
	private static boolean addMatchingElements(Set customAttributes, IPluginElement pluginElement, String elementName, final String[] elements) {
205
		boolean elementMatch = false;
206
		for (int i = 0; i < elements.length; i++) {
207
			if (elements[i].equals(elementName)) {
208
				addAll(customAttributes, pluginElement, elements[i]);
209
				elementMatch = true;
210
			}
211
		}
212
		return elementMatch;
213
	}
214
215
	private static Set handlePropertyTester(Set customAttributes, IPluginElement pluginElement) {
216
		String namespace = pluginElement.getAttribute(ATTRIBUTE_NAMESPACE).getValue();
217
		String properties = pluginElement.getAttribute(ATTRIBUTE_PROPERTIES).getValue();
218
		if (namespace.length() > 0) {
219
			String[] propertiesArray = properties.split(","); //$NON-NLS-1$
220
			for (int i = 0; i < propertiesArray.length; i++) {
221
				String property = propertiesArray[i].trim();
222
				if (property.length() > 0) {
223
					customAttributes.add(namespace + '.' + property);
224
				}
225
			}
226
			if (propertiesArray.length == 0) {
227
				customAttributes.add(namespace);
228
			}
229
		}
230
		return customAttributes;
231
	}
232
233
	public static List handlePropertyTester(IPluginElement pluginElement) {
234
		List propertyTestAttributes = new ArrayList();
235
		String elementName = getElementPath(pluginElement);
236
		boolean elementMatch = false;
237
		if (elementName == null) {
238
			// workaround for non-editable plugins of the target platform
239
			if (ELEMENT_PROPERTYTESTER.endsWith(pluginElement.getName())) {
240
				elementMatch = true;
241
			}
242
		} else if (ELEMENT_PROPERTYTESTER.equalsIgnoreCase(elementName)) {
243
			elementMatch = true;
244
		}
245
		if (elementMatch) {
246
			Set attributes = handlePropertyTester(new HashSet(), pluginElement);
247
			for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
248
				propertyTestAttributes.add(iterator.next());
249
			}
250
		}
251
		return propertyTestAttributes;
252
	}
253
254
	public static boolean isFilterRelatedEnabled(IPluginElement pluginElement) {
255
		for (int i = 0; i < RELATED_ATTRIBUTES.length; i++) {
256
			String property = RELATED_ATTRIBUTES[i];
257
			IPluginAttribute attribute = pluginElement.getAttribute(property);
258
			if (attribute != null) {
259
				return true;
260
			}
261
		}
262
		// test for custom relations
263
		Object attributes = CUSTOM_RELATIONS.get(getElementPath(pluginElement));
264
		if (attributes != null) {
265
			String[] attributesArray = (String[]) attributes;
266
			for (int i = 0; i < attributesArray.length; i++) {
267
				IPluginAttribute attribute = pluginElement.getAttribute(attributesArray[i]);
268
				if (attribute != null) {
269
					return true;
270
				}
271
			}
272
		}
273
		return false;
274
	}
275
276
	public static boolean isFilterRelatedEnabled(IStructuredSelection structuredSelection) {
277
		boolean createFilterRelatedAction = false;
278
		if (structuredSelection != null && !structuredSelection.isEmpty()) {
279
			Iterator it = structuredSelection.iterator();
280
			while (it.hasNext()) {
281
				Object treeElement = it.next();
282
				if (treeElement instanceof IPluginElement) {
283
					createFilterRelatedAction |= isFilterRelatedEnabled((IPluginElement) treeElement);
284
				}
285
			}
286
		}
287
		return createFilterRelatedAction;
288
	}
289
290
	public static boolean isNotBoolean(String bool) {
291
		return !bool.equalsIgnoreCase(Boolean.TRUE.toString()) && !bool.equalsIgnoreCase(Boolean.FALSE.toString());
292
	}
293
294
}

Return to bug 360894