Project

General

Profile

Download (17.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2003, 2010 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.extensions;
12

    
13
import java.lang.ref.SoftReference;
14
import java.util.Arrays;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.LinkedList;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.TreeSet;
23
import java.util.WeakHashMap;
24

    
25
import org.eclipse.core.runtime.IConfigurationElement;
26
import org.eclipse.core.runtime.SafeRunner;
27
import org.eclipse.jface.resource.ImageDescriptor;
28
import org.eclipse.jface.resource.ImageRegistry;
29
import org.eclipse.swt.graphics.Image;
30
import org.eclipse.ui.internal.navigator.NavigatorPlugin;
31
import org.eclipse.ui.internal.navigator.NavigatorSafeRunnable;
32
import org.eclipse.ui.internal.navigator.Policy;
33
import org.eclipse.ui.internal.navigator.VisibilityAssistant;
34
import org.eclipse.ui.internal.navigator.VisibilityAssistant.VisibilityListener;
35
import org.eclipse.ui.navigator.INavigatorContentDescriptor;
36
import org.eclipse.ui.navigator.OverridePolicy;
37
import org.eclipse.ui.plugin.AbstractUIPlugin;
38

    
39
/**
40
 * @since 3.2
41
 */
42
public class NavigatorContentDescriptorManager {
43

    
44
	private static final NavigatorContentDescriptorManager INSTANCE = new NavigatorContentDescriptorManager();
45

    
46
	private final Map firstClassDescriptorsMap = new HashMap();
47

    
48
	private final Map allDescriptors = new HashMap();
49

    
50
	private class EvaluationCache implements VisibilityListener {
51

    
52
		private final Map evaluations/* <Object, NavigatorContentDescriptor[]> */= new HashMap();
53
		private final Map evaluationsWithOverrides/*<Object, NavigatorContentDescriptor[]>*/ = new HashMap();
54

    
55
		EvaluationCache(VisibilityAssistant anAssistant) {
56
			anAssistant.addListener(this);
57
		}
58

    
59
		protected final NavigatorContentDescriptor[] getDescriptors(Object anElement) {
60
			return getDescriptors(anElement, true);
61
		}
62

    
63
		protected final void setDescriptors(Object anElement, NavigatorContentDescriptor[] theDescriptors) {
64
			setDescriptors(anElement, theDescriptors, true);
65
		}
66

    
67
		protected final NavigatorContentDescriptor[] getDescriptors(Object anElement, boolean toComputeOverrides) {
68

    
69
			if (anElement == null)
70
				return null;
71

    
72
			NavigatorContentDescriptor[] cachedDescriptors = null;
73
			if (toComputeOverrides) {
74
				SoftReference cache = (SoftReference) evaluations.get(anElement);
75
				if (cache != null && (cachedDescriptors = (NavigatorContentDescriptor[]) cache.get()) == null)
76
					evaluations.remove(anElement);
77
				return cachedDescriptors;
78
			}
79
			SoftReference cache = (SoftReference) evaluationsWithOverrides.get(anElement);
80
			if (cache != null && (cachedDescriptors = (NavigatorContentDescriptor[]) cache.get()) == null)
81
				evaluationsWithOverrides.remove(anElement);
82
			return cachedDescriptors;
83

    
84
		}
85

    
86
		protected final void setDescriptors(Object anElement, NavigatorContentDescriptor[] theDescriptors, boolean toComputeOverrides) {
87
			if (anElement != null) {
88
				if (toComputeOverrides)
89
					evaluations.put(new EvalutationReference(anElement), new SoftReference(theDescriptors));
90
				else
91
					evaluationsWithOverrides.put(new EvalutationReference(anElement), new SoftReference(theDescriptors));
92
			}
93
		}
94

    
95
		/*
96
		 * (non-Javadoc)
97
		 * 
98
		 * @see org.eclipse.ui.internal.navigator.VisibilityAssistant.VisibilityListener#onVisibilityOrActivationChange()
99
		 */
100
		public void onVisibilityOrActivationChange() {
101
			evaluations.clear();
102
			evaluationsWithOverrides.clear();
103
		}
104
	}
105

    
106
	/* Map of (VisibilityAssistant, EvaluationCache)-pairs */
107
	private final Map cachedTriggerPointEvaluations = new WeakHashMap();
108

    
109
	/* Map of (VisibilityAssistant, EvaluationCache)-pairs */
110
	private final Map cachedPossibleChildrenEvaluations = new WeakHashMap();
111

    
112
	private ImageRegistry imageRegistry;
113

    
114
	private final Set overridingDescriptors = new HashSet();
115

    
116
	private final Set saveablesProviderDescriptors = new HashSet();
117

    
118
	private final Set sortOnlyDescriptors = new HashSet();
119

    
120
	private final Set firstClassDescriptorsSet = new HashSet();
121

    
122
	/**
123
	 * @return the singleton instance of the manager
124
	 */
125
	public static NavigatorContentDescriptorManager getInstance() {
126
		return INSTANCE;
127
	}
128

    
129
	private NavigatorContentDescriptorManager() {
130
		new NavigatorContentDescriptorRegistry().readRegistry();
131
	}
132

    
133
	/**
134
	 * 
135
	 * @return Returns all content descriptor(s).
136
	 */
137
	public NavigatorContentDescriptor[] getAllContentDescriptors() {
138
		NavigatorContentDescriptor[] finalDescriptors = new NavigatorContentDescriptor[allDescriptors
139
				.size()];
140
		finalDescriptors = (NavigatorContentDescriptor[]) allDescriptors.values().toArray(finalDescriptors);
141
		Arrays.sort(finalDescriptors, ExtensionSequenceNumberComparator.INSTANCE);
142
		return finalDescriptors;
143
	}
144

    
145
	/**
146
	 * 
147
	 * @return Returns all content descriptors that provide saveables.
148
	 */
149
	public NavigatorContentDescriptor[] getContentDescriptorsWithSaveables() {
150
		NavigatorContentDescriptor[] finalDescriptors = new NavigatorContentDescriptor[saveablesProviderDescriptors
151
				.size()];
152
		saveablesProviderDescriptors.toArray(finalDescriptors);
153
		Arrays.sort(finalDescriptors, ExtensionSequenceNumberComparator.INSTANCE);
154
		return finalDescriptors;
155
	}
156

    
157
	/**
158
	 * 
159
	 * @return Returns all content descriptors that are sort only
160
	 */
161
	public NavigatorContentDescriptor[] getSortOnlyContentDescriptors() {
162
		NavigatorContentDescriptor[] finalDescriptors = new NavigatorContentDescriptor[sortOnlyDescriptors
163
				.size()];
164
		sortOnlyDescriptors.toArray(finalDescriptors);
165
		Arrays.sort(finalDescriptors, ExtensionSequenceNumberComparator.INSTANCE);
166
		return finalDescriptors;
167
	}
168

    
169

    
170
	/**
171
	 * 
172
	 * Returns all content descriptor(s) which enable for the given element.
173
	 * 
174
	 * @param anElement
175
	 *            the element to return the best content descriptor for
176
	 * 
177
	 * @param aVisibilityAssistant
178
	 *            The relevant viewer assistant; used to filter out unbound
179
	 *            content descriptors.
180
	 * @param considerOverrides 
181
	 * @return the best content descriptor for the given element.
182
	 */
183
	public Set findDescriptorsForTriggerPoint(Object anElement,
184
			VisibilityAssistant aVisibilityAssistant, boolean considerOverrides) {
185
		return findDescriptors(anElement, cachedTriggerPointEvaluations, aVisibilityAssistant, considerOverrides, !POSSIBLE_CHILD);
186
	}
187

    
188

    
189
	/**
190
	 * 
191
	 * Returns all content descriptor(s) which enable for the given element.
192
	 * 
193
	 * @param anElement
194
	 *            the element to return the best content descriptor for
195
	 * 
196
	 * @param aVisibilityAssistant
197
	 *            The relevant viewer assistant; used to filter out unbound
198
	 *            content descriptors.
199
	 * @param toComputeOverrides
200
	 * @return the best content descriptor for the given element.
201
	 */
202
	public Set findDescriptorsForPossibleChild(Object anElement,
203
			VisibilityAssistant aVisibilityAssistant, boolean toComputeOverrides) {
204
		return findDescriptors(anElement, cachedPossibleChildrenEvaluations, aVisibilityAssistant, toComputeOverrides, POSSIBLE_CHILD);
205
	}
206

    
207
	private static final boolean POSSIBLE_CHILD = true;
208
	
209

    
210
	private Set findDescriptors(Object anElement,
211
			Map cachedEvaluations, VisibilityAssistant aVisibilityAssistant, boolean considerOverrides, boolean possibleChild) {
212
		EvaluationCache cache = getEvaluationCache(
213
				cachedEvaluations, aVisibilityAssistant);
214

    
215
		Set descriptors = new TreeSet(ExtensionSequenceNumberComparator.INSTANCE);
216
		NavigatorContentDescriptor[] cachedDescriptors = null;
217
		if ((cachedDescriptors = cache.getDescriptors(anElement)) != null) {
218
			descriptors.addAll(Arrays.asList(cachedDescriptors));
219
		}
220

    
221
		if (considerOverrides) {
222
			addDescriptorsConsideringOverrides(anElement, firstClassDescriptorsSet, aVisibilityAssistant, descriptors, possibleChild);
223
			if (Policy.DEBUG_RESOLUTION) {
224
				System.out.println("Find descriptors for: " + Policy.getObjectString(anElement) + //$NON-NLS-1$
225
						": " + descriptors); //$NON-NLS-1$
226
			}
227
		} else {
228

    
229
			/* Find other ContentProviders which enable for this object */
230
			for (Iterator contentDescriptorsItr = firstClassDescriptorsSet.iterator(); contentDescriptorsItr.hasNext();) {
231
				NavigatorContentDescriptor descriptor = (NavigatorContentDescriptor) contentDescriptorsItr.next();
232

    
233
				if (aVisibilityAssistant.isActive(descriptor) && aVisibilityAssistant.isVisible(descriptor)
234
						&& (possibleChild ? descriptor.isPossibleChild(anElement) : descriptor.isTriggerPoint(anElement))) {
235
					descriptors.add(descriptor);
236
				}
237
			}
238
		}
239
		cache.setDescriptors(anElement, (NavigatorContentDescriptor[]) descriptors.toArray(new NavigatorContentDescriptor[descriptors.size()]));
240

    
241
		return descriptors;
242
	}
243

    
244
	private EvaluationCache getEvaluationCache(Map anEvaluationMap,
245
			VisibilityAssistant aVisibilityAssistant) {
246
		EvaluationCache c = (EvaluationCache) anEvaluationMap
247
				.get(aVisibilityAssistant);
248
		if (c == null) {
249
			anEvaluationMap.put(aVisibilityAssistant, c = new EvaluationCache(
250
					aVisibilityAssistant));
251
		}
252
		return c;
253

    
254
	}
255

    
256
	private boolean addDescriptorsConsideringOverrides(Object anElement,
257
			Set theChildDescriptors, VisibilityAssistant aVisibilityAssistant,
258
			Set theFoundDescriptors, boolean possibleChild) {
259
		int initialSize = theFoundDescriptors.size();
260

    
261
		NavigatorContentDescriptor descriptor;
262
		/* Find other ContentProviders which enable for this object */
263
		for (Iterator contentDescriptorsItr = theChildDescriptors.iterator(); contentDescriptorsItr
264
				.hasNext();) {
265
			descriptor = (NavigatorContentDescriptor) contentDescriptorsItr
266
					.next();
267

    
268
			boolean isApplicable = aVisibilityAssistant.isActive(descriptor)
269
					&& aVisibilityAssistant.isVisible(descriptor)
270
					&& (possibleChild ? descriptor.isPossibleChild(anElement) : descriptor.isTriggerPoint(anElement));
271

    
272
			if (descriptor.hasOverridingExtensions()) {
273

    
274
				boolean isOverridden;
275

    
276
				Set overridingDescriptors = new TreeSet(ExtensionSequenceNumberComparator.INSTANCE);
277
				isOverridden = addDescriptorsConsideringOverrides(anElement, descriptor.getOverriddingExtensions(),
278
						aVisibilityAssistant, overridingDescriptors, possibleChild);
279

    
280
				if (!isOverridden && isApplicable) {
281
					theFoundDescriptors.add(descriptor);
282
				} else if (isOverridden) {
283
					theFoundDescriptors.addAll(overridingDescriptors);
284
				}
285

    
286
			} else if (isApplicable) {
287
				theFoundDescriptors.add(descriptor);
288
			}
289

    
290
		}
291
		return initialSize < theFoundDescriptors.size();
292

    
293
	}
294

    
295
	/**
296
	 * Returns the navigator content descriptor with the given id.
297
	 * 
298
	 * @param id
299
	 *            The id of the content descriptor that should be returned
300
	 * @return The content descriptor of the given id
301
	 */
302
	public NavigatorContentDescriptor getContentDescriptor(String id) {
303
		return (NavigatorContentDescriptor) allDescriptors.get(id);
304
	}
305

    
306
	/**
307
	 * 
308
	 * @param descriptorId
309
	 *            The unique id of a particular descriptor
310
	 * @return The name (value of the 'name' attribute) of the given descriptor
311
	 */
312
	public String getText(String descriptorId) {
313
		INavigatorContentDescriptor descriptor = getContentDescriptor(descriptorId);
314
		if (descriptor != null) {
315
			return descriptor.getName();
316
		}
317
		return descriptorId;
318
	}
319

    
320
	/**
321
	 * 
322
	 * @param descriptorId
323
	 *            The unique id of a particular descriptor
324
	 * @return The image (corresponding to the value of the 'icon' attribute) of
325
	 *         the given descriptor
326
	 */
327
	public Image getImage(String descriptorId) {
328
		return retrieveAndStoreImage(descriptorId);
329
	}
330

    
331
	protected Image retrieveAndStoreImage(String descriptorId) {
332
		NavigatorContentDescriptor contentDescriptor = getContentDescriptor(descriptorId);
333

    
334
		Image image = null;
335
		if (contentDescriptor != null) {
336
			String icon = contentDescriptor.getIcon();
337
			if (icon != null) {
338
				image = getImageRegistry().get(icon);
339
				if (image == null || image.isDisposed()) {
340
					ImageDescriptor imageDescriptor = AbstractUIPlugin
341
							.imageDescriptorFromPlugin(contentDescriptor
342
							.getContribution().getPluginId(), icon);
343
					if (imageDescriptor != null) {
344
						image = imageDescriptor.createImage();
345
						if (image != null) {
346
							getImageRegistry().put(icon, image);
347
						}
348
					}
349
				}
350
			}
351
		}
352
		return image;
353
	}
354

    
355
	/**
356
	 * @param desc
357
	 */
358
	private void addNavigatorContentDescriptor(NavigatorContentDescriptor desc) {
359
		if (desc == null) {
360
			return;
361
		}
362
		synchronized (firstClassDescriptorsMap) {
363
			if (firstClassDescriptorsMap.containsKey(desc.getId())) {
364
				NavigatorPlugin
365
						.logError(
366
								0,
367
								"An extension already exists with id \"" + desc.getId() + "\".", null); //$NON-NLS-1$ //$NON-NLS-2$
368
			} else {
369
				if (desc.getSuppressedExtensionId() == null) {
370
					firstClassDescriptorsMap.put(desc.getId(), desc);
371
					firstClassDescriptorsSet.add(desc);
372
					if (Policy.DEBUG_EXTENSION_SETUP) {
373
						System.out.println("First class descriptor: " + desc); //$NON-NLS-1$
374
					}
375
				} else {
376
					overridingDescriptors.add(desc);
377
					if (Policy.DEBUG_EXTENSION_SETUP) {
378
						System.out.println("Overriding descriptor: " + desc); //$NON-NLS-1$
379
					}
380
				}
381
				allDescriptors.put(desc.getId(), desc);
382
				if (desc.hasSaveablesProvider()) {
383
					saveablesProviderDescriptors.add(desc);
384
					if (Policy.DEBUG_EXTENSION_SETUP) {
385
						System.out.println("Saveables provider descriptor: " + desc); //$NON-NLS-1$
386
					}
387
				}
388
				if (desc.isSortOnly()) {
389
					sortOnlyDescriptors.add(desc);
390
					if (Policy.DEBUG_EXTENSION_SETUP) {
391
						System.out.println("SortOnly descriptor: " + desc); //$NON-NLS-1$
392
					}
393
				}
394
			}
395
		}
396
	}
397

    
398
	/**
399
	 * 
400
	 */
401
	private void computeOverrides() {
402
		if (overridingDescriptors.size() > 0) {
403
			NavigatorContentDescriptor descriptor;
404
			NavigatorContentDescriptor overriddenDescriptor;
405
			for (Iterator overridingIterator = overridingDescriptors.iterator(); overridingIterator
406
					.hasNext();) {
407
				descriptor = (NavigatorContentDescriptor) overridingIterator
408
						.next();
409
				overriddenDescriptor = (NavigatorContentDescriptor) allDescriptors
410
						.get(descriptor.getSuppressedExtensionId());
411
				if (overriddenDescriptor != null) {
412

    
413
					if (Policy.DEBUG_EXTENSION_SETUP) {
414
						System.out.println(descriptor + " overrides: " + overriddenDescriptor); //$NON-NLS-1$
415
					}
416
					/*
417
					 * add the descriptor as an overriding extension for its
418
					 * suppressed extension
419
					 */
420
					overriddenDescriptor.getOverriddingExtensions().add(
421
							descriptor);
422
					descriptor.setOverriddenDescriptor(overriddenDescriptor);
423
					/*
424
					 * the always policy implies this is also a top-level
425
					 * extension
426
					 */
427
					if (descriptor.getOverridePolicy() == OverridePolicy.InvokeAlwaysRegardlessOfSuppressedExt) {
428
						if (Policy.DEBUG_EXTENSION_SETUP) {
429
							System.out.println(descriptor + " is first class"); //$NON-NLS-1$
430
						}
431
						firstClassDescriptorsMap.put(descriptor.getId(),
432
								descriptor);
433
						firstClassDescriptorsSet.add(descriptor);
434
					}
435

    
436
				} else {
437
					String message = 
438
							"Invalid suppressedExtensionId \"" //$NON-NLS-1$
439
									+ descriptor.getSuppressedExtensionId()
440
									+ "\" specified from \"" //$NON-NLS-1$
441
									+ descriptor.getId() + "\" in \"" + descriptor.getContribution() //$NON-NLS-1$
442
											.getPluginId()
443
									+ "\". No extension with matching id found."; //$NON-NLS-1$
444
					if (Policy.DEBUG_EXTENSION_SETUP) {
445
						System.out.println("Error: " + message); //$NON-NLS-1$
446
					}
447
					NavigatorPlugin.logError(0, message, null);
448
				}
449
			}
450
		}
451
	}
452
	
453
	private int findId(List list, String id) {
454
		for (int i = 0, len = list.size(); i < len; i++) {
455
			NavigatorContentDescriptor desc = (NavigatorContentDescriptor) list.get(i);
456
			if (desc.getId().equals(id))
457
				return i;
458
		}
459
		throw new RuntimeException("Can't find id: " + id); //$NON-NLS-1$
460
	}
461
	
462
	private void computeSequenceNumbers() {
463
		NavigatorContentDescriptor[] descs = getAllContentDescriptors();
464

    
465
		LinkedList list = new LinkedList();
466
		for (int i = 0; i < descs.length; i++) {
467
			list.add(descs[i]);
468
		}
469
		
470
		boolean changed = true;
471
		while (changed) {
472
			changed = false;
473
			for (int i = 0, len = list.size(); i < len; i++) {
474
				NavigatorContentDescriptor desc = (NavigatorContentDescriptor) list.get(i);
475
				if (desc.getAppearsBeforeId() != null) {
476
					int beforeInd = findId(list, desc.getAppearsBeforeId());
477
					if (beforeInd < i) {
478
						list.add(beforeInd, desc);
479
						list.remove(i + 1);
480
						changed = true;
481
					}
482
				}
483
			}
484
		}
485
		
486
		for (int i = 0, len = list.size(); i < len; i++) {
487
			NavigatorContentDescriptor desc = (NavigatorContentDescriptor) list.get(i);
488
			desc.setSequenceNumber(i);
489
			if (Policy.DEBUG_EXTENSION_SETUP) {
490
				System.out.println("Descriptors by sequence: " + desc); //$NON-NLS-1$
491
			}
492
		}
493
	}
494

    
495
	private ImageRegistry getImageRegistry() {
496
		if (imageRegistry == null) {
497
			imageRegistry = new ImageRegistry();
498
		}
499
		return imageRegistry;
500
	}
501

    
502
	private class NavigatorContentDescriptorRegistry extends
503
			NavigatorContentRegistryReader {
504

    
505
		/*
506
		 * (non-Javadoc)
507
		 * 
508
		 * @see org.eclipse.ui.internal.navigator.extensions.RegistryReader#readRegistry()
509
		 */
510
		public void readRegistry() {
511
			super.readRegistry();
512
			computeSequenceNumbers();
513
			computeOverrides();
514
		}
515

    
516
		protected boolean readElement(final IConfigurationElement anElement) {
517
			if (TAG_NAVIGATOR_CONTENT.equals(anElement.getName())) {
518
				SafeRunner.run(new NavigatorSafeRunnable(anElement) {
519
					public void run() throws Exception {
520
						addNavigatorContentDescriptor(new NavigatorContentDescriptor(anElement));
521
					}
522
				});
523
			}
524
			return super.readElement(anElement);
525
		}
526
	}
527

    
528
}
(16-16/29)