Project

General

Profile

Download (13.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2009 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
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.navigator.actions;
12

    
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.LinkedHashMap;
18
import java.util.LinkedHashSet;
19
import java.util.LinkedList;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.Set;
23

    
24
import org.eclipse.core.runtime.Assert;
25
import org.eclipse.core.runtime.IConfigurationElement;
26
import org.eclipse.core.runtime.ISafeRunnable;
27
import org.eclipse.core.runtime.IStatus;
28
import org.eclipse.core.runtime.SafeRunner;
29
import org.eclipse.jface.viewers.IStructuredSelection;
30
import org.eclipse.jface.viewers.StructuredSelection;
31
import org.eclipse.ui.actions.ActionContext;
32
import org.eclipse.ui.internal.navigator.NavigatorPlugin;
33
import org.eclipse.ui.internal.navigator.extensions.NavigatorContentRegistryReader;
34
import org.eclipse.ui.navigator.INavigatorContentService;
35
import org.eclipse.ui.navigator.Priority;
36

    
37
/**
38
 * Manages descriptors consumed from the 'actionProvider' elements of the
39
 * <b>org.eclipse.ui.navigator.navigatorContent</b> extension point.
40
 * 
41
 * @since 3.2
42
 * 
43
 */
44
public class CommonActionDescriptorManager {
45

    
46
	private static final CommonActionProviderDescriptor[] NO_DESCRIPTORS = new CommonActionProviderDescriptor[0];
47

    
48
	private static final CommonActionDescriptorManager INSTANCE = new CommonActionDescriptorManager();
49

    
50
	private CommonActionDescriptorManager() {
51

    
52
		new ActionProviderRegistry().readRegistry();
53
	}
54

    
55
	/**
56
	 * @return the singleton instance of the registry
57
	 */
58
	public static CommonActionDescriptorManager getInstance() {
59
		return INSTANCE;
60
	}
61
	
62
	/* Provides a map of (ids, CommonActionProviderDescriptor)-pairs. */
63
	private final Map dependentDescriptors = new LinkedHashMap();
64

    
65
	/* Provides a map of (ids, CommonActionProviderDescriptor)-pairs. */
66
	private final Map rootDescriptors = new LinkedHashMap();
67

    
68
	/* Provides a map of (ids, CommonActionProviderDescriptor)-pairs. */
69
	private final Set overridingDescriptors = new LinkedHashSet();
70

    
71
	
72
	private final LinkedList rootDescriptorsList = new LinkedList();
73
	private final LinkedList dependentDescriptorsList = new LinkedList();
74

    
75
	
76
	/**
77
	 * 
78
	 * @param aDescriptor
79
	 *            A valid descriptor to begin managing.
80
	 */
81
	protected void addActionDescriptor(
82
			CommonActionProviderDescriptor aDescriptor) {
83

    
84
		if (aDescriptor.getDependsOnId() == null) {
85
			rootDescriptorsList.add(aDescriptor);
86
		} else {
87
			dependentDescriptorsList.add(aDescriptor);
88
		}
89

    
90
		if (aDescriptor.getOverridesId() != null) {
91
			overridingDescriptors.add(aDescriptor);
92
		}
93
	}
94

    
95
	private int findId(List list, String id) {
96
		for (int i= 0, len = list.size(); i< len; i++) {
97
			CommonActionProviderDescriptor desc = (CommonActionProviderDescriptor) list.get(i);
98
			if (desc.getId().equals(id))
99
				return i;
100
		}
101
		return -1;
102
	}
103
	
104
	
105
	
106
	/**
107
	 * Sorts the descriptors according to the appearsBefore property
108
	 */
109
	private void sortDescriptors(LinkedList list, Map outMap) {
110
		boolean changed = true;
111
		while (changed) {
112
			changed = false;
113
			for (int i = 0, len = list.size(); i < len; i++) {
114
				CommonActionProviderDescriptor desc = (CommonActionProviderDescriptor) list.get(i);
115
				if (desc.getAppearsBeforeId() != null) {
116
					int beforeInd = findId(list, desc.getAppearsBeforeId());
117
					if (beforeInd < i) {
118
						list.add(beforeInd, desc);
119
						list.remove(i + 1);
120
						changed = true;
121
					}
122
				}
123
			}
124
		}
125
		for (int i = 0, len = list.size(); i < len; i++) {
126
			CommonActionProviderDescriptor desc = (CommonActionProviderDescriptor) list.get(i);
127
			outMap.put(desc.getDefinedId(), desc);
128
		}
129
	}
130
	
131
	
132
	/**
133
	 * Orders the set of available descriptors based on the order defined by the
134
	 * <i>dependsOn</i> attribute from the <actionProvider /> element in
135
	 * <b>org.eclipse.ui.navigator.navigatorContent</b>
136
	 * 
137
	 */
138
	protected void computeOrdering() {
139
		sortDescriptors(rootDescriptorsList, rootDescriptors);
140
		sortDescriptors(dependentDescriptorsList, dependentDescriptors);
141
		
142
		CommonActionProviderDescriptor dependentDescriptor;
143
		CommonActionProviderDescriptor requiredDescriptor;
144

    
145
		CommonActionProviderDescriptor descriptor;
146
		CommonActionProviderDescriptor overriddenDescriptor;
147
		for (Iterator iter = overridingDescriptors.iterator(); iter.hasNext();) {
148
			descriptor = (CommonActionProviderDescriptor) iter.next();
149
			if (rootDescriptors.containsKey(descriptor.getOverridesId())) {
150
				overriddenDescriptor = (CommonActionProviderDescriptor) rootDescriptors
151
						.get(descriptor.getOverridesId());
152
				overriddenDescriptor.addOverridingDescriptor(descriptor);
153
			} else if (dependentDescriptors.containsKey(descriptor
154
					.getOverridesId())) {
155
				overriddenDescriptor = (CommonActionProviderDescriptor) dependentDescriptors
156
						.get(descriptor.getOverridesId());
157
				overriddenDescriptor.addOverridingDescriptor(descriptor);
158
			}
159

    
160
		}
161

    
162
		Collection unresolvedDependentDescriptors = new ArrayList(
163
				dependentDescriptors.values());
164

    
165
		for (Iterator iter = dependentDescriptors.values().iterator(); iter
166
				.hasNext();) {
167
			dependentDescriptor = (CommonActionProviderDescriptor) iter.next();
168
			requiredDescriptor = (CommonActionProviderDescriptor) rootDescriptors
169
					.get(dependentDescriptor.getDependsOnId());
170
			if (requiredDescriptor == null) {
171
				requiredDescriptor = (CommonActionProviderDescriptor) dependentDescriptors
172
						.get(dependentDescriptor.getDependsOnId());
173
			}
174
			if (requiredDescriptor != null) {
175
				requiredDescriptor.addDependentDescriptor(dependentDescriptor);
176
				unresolvedDependentDescriptors.remove(dependentDescriptor);
177
			}
178

    
179
		}
180

    
181
		dependentDescriptors.clear();
182

    
183
		if (!unresolvedDependentDescriptors.isEmpty()) {
184
			StringBuffer errorMessage = new StringBuffer(
185
					"There were unresolved dependencies for action provider extensions to a Common Navigator.\n" + //$NON-NLS-1$
186
							"Verify that the \"dependsOn\" attribute for each <actionProvider /> element is valid."); //$NON-NLS-1$
187

    
188
			CommonActionProviderDescriptor[] unresolvedDescriptors = (CommonActionProviderDescriptor[]) unresolvedDependentDescriptors
189
					.toArray(new CommonActionProviderDescriptor[unresolvedDependentDescriptors
190
							.size()]);
191
			for (int i = 0; i < unresolvedDescriptors.length; i++) {
192
				errorMessage
193
						.append(
194
								"\nUnresolved dependency specified for actionProvider: ").append(unresolvedDescriptors[i].getDefinedId()); //$NON-NLS-1$
195
			}
196

    
197
			NavigatorPlugin.log(IStatus.WARNING, 0, errorMessage.toString(),
198
					null);
199

    
200
		}
201
		unresolvedDependentDescriptors.clear();
202

    
203
	}
204

    
205
	/**
206
	 * 
207
	 * @param aContentService
208
	 *            The content service to use when filtering action providers;
209
	 *            only action providers bound directly or indirectly will be
210
	 *            returned.
211
	 * @param aContext
212
	 *            The action context that contains a valid selection.
213
	 * @return An array of visible, active, and enabled CommonActionProviders.
214
	 *         See <b>org.eclipse.ui.navigator.navigatorContent</b> for the
215
	 *         details of what each of these adjectives implies.
216
	 */
217
	public CommonActionProviderDescriptor[] findRelevantActionDescriptors(
218
			INavigatorContentService aContentService, ActionContext aContext) {
219
		Assert.isNotNull(aContext);
220
		IStructuredSelection structuredSelection = null;
221
		if (aContext.getSelection() instanceof IStructuredSelection) {
222
			structuredSelection = (IStructuredSelection) aContext
223
					.getSelection();
224
		} else {
225
			structuredSelection = StructuredSelection.EMPTY;
226
		}
227

    
228
		Set blockedProviders = new HashSet();
229
		CommonActionProviderDescriptor actionDescriptor = null;
230
		Set providers = new LinkedHashSet();
231
		for (Iterator providerItr = rootDescriptors.values().iterator(); providerItr
232
				.hasNext();) {
233
			actionDescriptor = (CommonActionProviderDescriptor) providerItr
234
					.next();
235
			addProviderIfRelevant(aContentService, structuredSelection,
236
					actionDescriptor, providers, blockedProviders);
237
		}
238
		if (providers.size() > 0) {
239
			providers.removeAll(blockedProviders);
240
			return (CommonActionProviderDescriptor[]) providers
241
					.toArray(new CommonActionProviderDescriptor[providers
242
							.size()]);
243
		}
244
		return NO_DESCRIPTORS;
245
	}
246

    
247
	/**
248
	 * @param aContentService
249
	 * @param structuredSelection
250
	 * @param actionDescriptor
251
	 * @param providers
252
	 */
253
	private boolean addProviderIfRelevant(
254
			INavigatorContentService aContentService,
255
			IStructuredSelection structuredSelection,
256
			CommonActionProviderDescriptor actionDescriptor, Set providers, Set blockedProviders) {
257
		if (isVisible(aContentService, actionDescriptor)
258
				&& actionDescriptor.isEnabledFor(structuredSelection)) {
259
			
260
			if(actionDescriptor.hasOverridingDescriptors()) {
261
				for (Iterator iter = actionDescriptor.overridingDescriptors(); iter.hasNext();) {
262
					CommonActionProviderDescriptor descriptor = (CommonActionProviderDescriptor) iter.next();
263
					if(addProviderIfRelevant(aContentService, structuredSelection, descriptor, providers, blockedProviders)) {
264
						while(iter.hasNext())
265
							blockedProviders.add(iter.next());
266
						return true;
267
					}
268
					
269
				}
270
			}			
271
			providers.add(actionDescriptor);
272
			if (actionDescriptor.hasDependentDescriptors()) {
273
				for (Iterator iter = actionDescriptor.dependentDescriptors(); iter
274
						.hasNext();) {
275
					addProviderIfRelevant(aContentService, structuredSelection,
276
							(CommonActionProviderDescriptor) iter.next(),
277
							providers, blockedProviders);
278
				}
279
			}
280
			return true;
281
		}
282
		return false;
283
	}
284

    
285
	private boolean isVisible(INavigatorContentService aContentService,
286
			CommonActionProviderDescriptor descriptor) {
287
		if (descriptor.isNested()) {
288
			return aContentService.isActive(descriptor.getId())
289
					&& aContentService.isVisible(descriptor.getId());
290
		}
291
		return aContentService.getViewerDescriptor().isVisibleActionExtension(
292
				descriptor.getId());
293
	}
294

    
295
	private class ActionProviderRegistry extends NavigatorContentRegistryReader {
296

    
297
		public void readRegistry() {
298
			super.readRegistry();
299
			computeOrdering();
300
		}
301

    
302
		protected boolean readElement(IConfigurationElement anElement) {
303
			if (TAG_ACTION_PROVIDER.equals(anElement.getName())) {
304
				addActionDescriptor(new CommonActionProviderDescriptor(
305
						anElement));
306
				return true;
307
			} else if (TAG_NAVIGATOR_CONTENT.equals(anElement.getName())) {
308
				
309
				IConfigurationElement[] actionProviders = anElement.getChildren(TAG_ACTION_PROVIDER);
310
				
311
				if (actionProviders.length > 0) {
312
					
313
					IConfigurationElement defaultEnablement = null;
314
					IConfigurationElement[] inheritedEnablement = anElement.getChildren(TAG_ENABLEMENT);
315
					if (inheritedEnablement.length == 0) {
316
						inheritedEnablement = anElement.getChildren(TAG_POSSIBLE_CHILDREN);
317
					}
318
					
319
					defaultEnablement = inheritedEnablement.length == 1 ? inheritedEnablement[0] : null;
320
  
321
					Priority defaultPriority = Priority.get(anElement.getAttribute(ATT_PRIORITY));
322
					
323
					
324
					if(defaultEnablement == null) {
325
						NavigatorPlugin.logError(0, 
326
							"An actionProvider has been defined as the child " + //$NON-NLS-1$
327
							"of a navigatorContent extension that does not specify " + //$NON-NLS-1$
328
							"an <enablement/> or <possibleChildren /> expression. Please " + //$NON-NLS-1$
329
							"review the documentation and correct this error.", null); //$NON-NLS-1$
330
					}
331
					for (int i = 0; i < actionProviders.length; i++) { 
332
						if(defaultEnablement == null) { 
333
							NavigatorPlugin.logError(0, 
334
											"Disabling actionProvider: " + actionProviders[i].getAttribute(ATT_ID), null); //$NON-NLS-1$
335
						} else {
336
							SafeRunner.run(new AddProviderSafeRunner(actionProviders[i], defaultEnablement, defaultPriority, anElement));
337
						}
338
					}
339
				}
340
				return true;
341
			}
342
			return super.readElement(anElement);
343
		}
344
	
345
		private class AddProviderSafeRunner implements ISafeRunnable {
346
			
347
			private IConfigurationElement parentElement;
348
			private IConfigurationElement defaultEnablement;
349
			private IConfigurationElement actionProvider;
350
			private Priority defaultPriority;
351

    
352
			protected AddProviderSafeRunner(IConfigurationElement actionProvider, 
353
											 IConfigurationElement defaultEnablement, 
354
											 Priority defaultPriority,
355
											 IConfigurationElement parentElement) {
356
				this.actionProvider = actionProvider;
357
				this.defaultEnablement = defaultEnablement;
358
				this.defaultPriority = defaultPriority;
359
				this.parentElement = parentElement;
360
			}
361
			
362
			/* (non-Javadoc)
363
			 * @see org.eclipse.core.runtime.ISafeRunnable#run()
364
			 */
365
			public void run() throws Exception { 
366
				addActionDescriptor(new CommonActionProviderDescriptor(
367
							actionProvider, defaultEnablement, defaultPriority, parentElement
368
									.getAttribute(ATT_ID), true));
369
			}
370
			
371
			/* (non-Javadoc)
372
			 * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
373
			 */
374
			public void handleException(Throwable t) {
375
				NavigatorPlugin.logError(0, "Recovering from error while parsing actionProviders.", t); //$NON-NLS-1$ 
376
			}
377
			
378
			
379
		}
380
	}
381

    
382

    
383
}
(2-2/4)