Source code: org/eclipse/ui/internal/ObjectActionContributor.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.ui.internal;
12
13
14 import java.util.List;
15
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IAdaptable;
18 import org.eclipse.core.runtime.IConfigurationElement;
19
20 import org.eclipse.core.expressions.EvaluationContext;
21 import org.eclipse.core.expressions.EvaluationResult;
22 import org.eclipse.core.expressions.Expression;
23 import org.eclipse.core.expressions.ExpressionConverter;
24 import org.eclipse.core.expressions.IEvaluationContext;
25
26 import org.eclipse.jface.action.IMenuManager;
27 import org.eclipse.jface.viewers.ISelection;
28 import org.eclipse.jface.viewers.ISelectionProvider;
29 import org.eclipse.jface.viewers.IStructuredSelection;
30
31 import org.eclipse.ui.IWorkbenchPart;
32 import org.eclipse.ui.SelectionEnabler;
33 import org.eclipse.ui.model.IWorkbenchAdapter;
34
35 /**
36 * This class describes the object contribution element within the popup menu
37 * action registry.
38 */
39 public class ObjectActionContributor extends PluginActionBuilder implements IObjectActionContributor {
40 private static final String ATT_NAME_FILTER = "nameFilter"; //$NON-NLS-1$
41 private static final String ATT_ADAPTABLE = "adaptable"; //$NON-NLS-1$
42 private static final String P_TRUE = "true"; //$NON-NLS-1$
43 private static final String TAG_ENABLEMENT= "enablement"; //$NON-NLS-1$
44
45 private IConfigurationElement config;
46 private boolean configRead = false;
47 private boolean adaptable = false;
48
49 /**
50 * The constructor.
51 */
52 public ObjectActionContributor(IConfigurationElement config) {
53 this.config = config;
54 this.adaptable = P_TRUE.equalsIgnoreCase(config.getAttribute(ATT_ADAPTABLE));
55 }
56
57 /* (non-Javadoc)
58 * Method declared on IObjectContributor.
59 */
60 public boolean canAdapt() {
61 return adaptable;
62 }
63
64
65 /* (non-Javadoc)
66 * Method declared on IObjectActionContributor.
67 */
68 public void contributeObjectActionIdOverrides(List actionIdOverrides) {
69 if (!configRead)
70 readConfigElement();
71
72 // Easy case out if no actions
73 if (currentContribution.actions != null) {
74 for (int i = 0; i < currentContribution.actions.size(); i++) {
75 ActionDescriptor ad = (ActionDescriptor)currentContribution.actions.get(i);
76 String id = ad.getAction().getOverrideActionId();
77 if (id != null)
78 actionIdOverrides.add(id);
79 }
80 }
81 }
82
83 /**
84 * Contributes actions applicable for the current selection.
85 */
86 public boolean contributeObjectActions(IWorkbenchPart part, IMenuManager menu, ISelectionProvider selProv, List actionIdOverrides) {
87 if (!configRead)
88 readConfigElement();
89
90 // Easy case out if no actions
91 if (currentContribution.actions == null)
92 return false;
93
94 // Get a structured selection.
95 ISelection sel = selProv.getSelection();
96 if ((sel == null) || !(sel instanceof IStructuredSelection))
97 return false;
98 IStructuredSelection selection = (IStructuredSelection) sel;
99
100 // Generate menu.
101 for (int i = 0; i < currentContribution.actions.size(); i++) {
102 ActionDescriptor ad = (ActionDescriptor)currentContribution.actions.get(i);
103 if (!actionIdOverrides.contains(ad.getId())) {
104 currentContribution.contributeMenuAction(ad, menu, true);
105 // Update action for the current selection and part.
106 if (ad.getAction() instanceof ObjectPluginAction) {
107 ObjectPluginAction action = (ObjectPluginAction) ad.getAction();
108 action.setActivePart(part);
109 action.selectionChanged(selection);
110 }
111 }
112 }
113 return true;
114 }
115
116 /**
117 * Contributes menus applicable for the current selection.
118 */
119 public boolean contributeObjectMenus(IMenuManager menu, ISelectionProvider selProv) {
120 if (!configRead)
121 readConfigElement();
122
123 // Easy case out if no menus
124 if (currentContribution.menus == null)
125 return false;
126
127 // Get a structured selection.
128 ISelection sel = selProv.getSelection();
129 if ((sel == null) || !(sel instanceof IStructuredSelection))
130 return false;
131
132 // Generate menu.
133 for (int i = 0; i < currentContribution.menus.size(); i++) {
134 IConfigurationElement menuElement = (IConfigurationElement)currentContribution.menus.get(i);
135 currentContribution.contributeMenu(menuElement, menu, true);
136 }
137 return true;
138 }
139
140 /* (non-Javadoc)
141 * Method declared on PluginActionBuilder.
142 */
143 protected ActionDescriptor createActionDescriptor(IConfigurationElement element) {
144 return new ActionDescriptor(element, ActionDescriptor.T_POPUP);
145 }
146
147 /* (non-Javadoc)
148 * Method declared on PluginActionBuilder.
149 */
150 protected BasicContribution createContribution() {
151 return new ObjectContribution();
152 }
153
154 /**
155 * Returns true if name filter is not specified for the contribution
156 * or the current selection matches the filter.
157 */
158 public boolean isApplicableTo(Object object) {
159 if (!configRead)
160 readConfigElement();
161
162 if (!testName(object))
163 return false;
164
165 return ((ObjectContribution)currentContribution).isApplicableTo(object);
166 }
167
168 /**
169 * Reads the configuration element and all the children.
170 * This creates an action descriptor for every action in the extension.
171 */
172 private void readConfigElement() {
173 currentContribution = createContribution();
174 readElementChildren(config);
175 configRead = true;
176 }
177
178 /* (non-Javadoc)
179 * Method declared on PluginActionBuilder.
180 */
181 protected boolean readElement(IConfigurationElement element) {
182 String tag = element.getName();
183
184 // Found visibility sub-element
185 if (tag.equals(PluginActionBuilder.TAG_VISIBILITY)) {
186 ((ObjectContribution)currentContribution).setVisibilityTest(element);
187 return true;
188 }
189
190 // Found filter sub-element
191 if (tag.equals(PluginActionBuilder.TAG_FILTER)) {
192 ((ObjectContribution)currentContribution).addFilterTest(element);
193 return true;
194 }
195
196 if (tag.equals(TAG_ENABLEMENT)) {
197 ((ObjectContribution)currentContribution).setEnablementTest(element);
198 return true;
199 }
200
201 return super.readElement(element);
202 }
203
204 /**
205 * Returns whether the current selection matches the contribution name filter.
206 */
207 private boolean testName(Object object) {
208 String nameFilter = config.getAttribute(ATT_NAME_FILTER);
209 if (nameFilter == null)
210 return true;
211 String objectName = null;
212 if (object instanceof IAdaptable) {
213 IAdaptable element = (IAdaptable) object;
214 IWorkbenchAdapter de = (IWorkbenchAdapter) element.getAdapter(IWorkbenchAdapter.class);
215 if (de != null)
216 objectName = de.getLabel(element);
217 }
218 if (objectName == null) {
219 objectName = object.toString();
220 }
221 return SelectionEnabler.verifyNameMatch(objectName, nameFilter);
222 }
223
224
225 /**
226 * Helper class to collect the menus and actions defined within a
227 * contribution element.
228 */
229 private static class ObjectContribution extends BasicContribution {
230 private ObjectFilterTest filterTest;
231 private ActionExpression visibilityTest;
232 private Expression enablement;
233
234 public void addFilterTest(IConfigurationElement element) {
235 if (filterTest == null)
236 filterTest = new ObjectFilterTest();
237 filterTest.addFilterElement(element);
238 }
239
240 public void setVisibilityTest(IConfigurationElement element) {
241 visibilityTest = new ActionExpression(element);
242 }
243
244 public void setEnablementTest(IConfigurationElement element) {
245 try {
246 enablement= ExpressionConverter.getDefault().perform(element);
247 } catch (CoreException e) {
248 WorkbenchPlugin.getDefault().getLog().log(e.getStatus());
249 }
250 }
251
252 /**
253 * Returns true if name filter is not specified for the contribution
254 * or the current selection matches the filter.
255 */
256 public boolean isApplicableTo(Object object) {
257 boolean result= true;
258 if (visibilityTest != null) {
259 result= result && visibilityTest.isEnabledFor(object);
260 if (!result)
261 return result;
262 } else if (filterTest != null) {
263 result= result && filterTest.matches(object, true);
264 if (!result)
265 return result;
266 }
267 if (enablement != null) {
268 try {
269 IEvaluationContext context= new EvaluationContext(null, object);
270 context.addVariable("selection", object); //$NON-NLS-1$
271 EvaluationResult evalResult= enablement.evaluate(context);
272 if (evalResult == EvaluationResult.FALSE)
273 return false;
274 } catch (CoreException e) {
275 enablement= null;
276 WorkbenchPlugin.getDefault().getLog().log(e.getStatus());
277 result= false;
278 }
279 }
280 return result;
281 }
282 }
283 }