Project

General

Profile

Download (39.9 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
 * Fair Issac Corp - bug 287103 - NCSLabelProvider does not properly handle overrides
11
 *******************************************************************************/
12
package org.eclipse.ui.internal.navigator;
13

    
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.Iterator;
20
import java.util.LinkedHashSet;
21
import java.util.List;
22
import java.util.ListIterator;
23
import java.util.Map;
24
import java.util.Set;
25
import java.util.SortedSet;
26
import java.util.TreeSet;
27

    
28
import org.osgi.service.prefs.BackingStoreException;
29

    
30
import org.eclipse.swt.widgets.Shell;
31

    
32
import org.eclipse.core.runtime.IStatus;
33
import org.eclipse.core.runtime.Platform;
34
import org.eclipse.core.runtime.SafeRunner;
35
import org.eclipse.core.runtime.Status;
36
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
37
import org.eclipse.core.runtime.preferences.InstanceScope;
38

    
39
import org.eclipse.jface.viewers.ILabelProvider;
40
import org.eclipse.jface.viewers.ITreeContentProvider;
41
import org.eclipse.jface.viewers.StructuredViewer;
42
import org.eclipse.jface.viewers.Viewer;
43

    
44
import org.eclipse.ui.IMemento;
45
import org.eclipse.ui.internal.navigator.dnd.NavigatorDnDService;
46
import org.eclipse.ui.internal.navigator.extensions.ExtensionSequenceNumberComparator;
47
import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor;
48
import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptorManager;
49
import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension;
50
import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptor;
51
import org.eclipse.ui.internal.navigator.extensions.NavigatorViewerDescriptorManager;
52
import org.eclipse.ui.internal.navigator.extensions.StructuredViewerManager;
53
import org.eclipse.ui.internal.navigator.sorters.NavigatorSorterService;
54
import org.eclipse.ui.navigator.IDescriptionProvider;
55
import org.eclipse.ui.navigator.IExtensionActivationListener;
56
import org.eclipse.ui.navigator.IExtensionStateModel;
57
import org.eclipse.ui.navigator.IMementoAware;
58
import org.eclipse.ui.navigator.INavigatorActivationService;
59
import org.eclipse.ui.navigator.INavigatorContentDescriptor;
60
import org.eclipse.ui.navigator.INavigatorContentExtension;
61
import org.eclipse.ui.navigator.INavigatorContentService;
62
import org.eclipse.ui.navigator.INavigatorContentServiceListener;
63
import org.eclipse.ui.navigator.INavigatorDnDService;
64
import org.eclipse.ui.navigator.INavigatorFilterService;
65
import org.eclipse.ui.navigator.INavigatorPipelineService;
66
import org.eclipse.ui.navigator.INavigatorSaveablesService;
67
import org.eclipse.ui.navigator.INavigatorSorterService;
68
import org.eclipse.ui.navigator.INavigatorViewerDescriptor;
69

    
70
/**
71
 * <p>
72
 * Provides centralized access to the information provided by
73
 * NavigatorContentExtensions. Can be instantiated as needed, but should be
74
 * cached for active viewers. Information specific to a given viewer will be
75
 * cached by the NavigatorContentService, not including ContentProviders and
76
 * Label Providers created by {@link #createCommonContentProvider()}and
77
 * {@link #createCommonLabelProvider()}respectively.
78
 * </p>
79
 * 
80
 * <p>
81
 * The following class is experimental until fully documented.
82
 * </p>
83
 */
84
public class NavigatorContentService implements IExtensionActivationListener,
85
		IMementoAware, INavigatorContentService {
86

    
87
	/**
88
	 * 
89
	 */
90
	public static final String WIDGET_KEY = "org.eclipse.ui.navigator"; //$NON-NLS-1$
91
	
92
	private static final NavigatorContentDescriptorManager CONTENT_DESCRIPTOR_REGISTRY = NavigatorContentDescriptorManager
93
			.getInstance();
94

    
95
	private static final NavigatorViewerDescriptorManager VIEWER_DESCRIPTOR_REGISTRY = NavigatorViewerDescriptorManager
96
			.getInstance();
97

    
98
	private static final ITreeContentProvider[] NO_CONTENT_PROVIDERS = new ITreeContentProvider[0];
99

    
100
	private static final ILabelProvider[] NO_LABEL_PROVIDERS = new ILabelProvider[0];
101

    
102
	private static final INavigatorContentDescriptor[] NO_DESCRIPTORS = new INavigatorContentDescriptor[0];
103

    
104
	private static final String[] NO_EXTENSION_IDS = new String[0];
105

    
106
	private final NavigatorViewerDescriptor viewerDescriptor;
107

    
108
	private final List listeners = new ArrayList();
109

    
110
	/*
111
	 * A map of (String-based-Navigator-Content-Extension-IDs,
112
	 * NavigatorContentExtension-objects)-pairs
113
	 */
114
	private final Map contentExtensions = new HashMap();
115

    
116
	private StructuredViewerManager structuredViewerManager;
117

    
118
	private ITreeContentProvider[] rootContentProviders;
119

    
120
	private ITreeContentProvider contentProvider;
121

    
122
	/*
123
	 * Used when providing objects to the CommonViewer by the contentProvider
124
	 * to record the object/description associations which are when stored
125
	 * in the Tree associated with the viewer.
126
	 */
127
	private Map contributionMemory;
128
	private Map contributionMemoryFirstClass;
129
	
130
	private ILabelProvider labelProvider;
131

    
132
	private final VisibilityAssistant assistant;
133

    
134
	private NavigatorFilterService navigatorFilterService;
135

    
136
	private NavigatorSorterService navigatorSorterService;
137

    
138
	private INavigatorPipelineService navigatorPipelineService;
139

    
140
	private INavigatorDnDService navigatorDnDService;
141

    
142
	private INavigatorActivationService navigatorActivationService;
143

    
144
	private NavigatorSaveablesService navigatorSaveablesService;
145

    
146
	private NavigatorExtensionStateService navigatorExtensionStateService;
147

    
148
	private IDescriptionProvider descriptionProvider;
149

    
150
	private boolean contentProviderInitialized;
151

    
152
	private boolean labelProviderInitialized;
153

    
154
	private boolean isDisposed;
155
	
156
	/**
157
	 * @param aViewerId
158
	 *            The viewer id for this content service; normally from the
159
	 *            <b>org.eclipse.ui.views</b> extension.
160
	 */
161
	public NavigatorContentService(String aViewerId) {
162
		super();
163
		aViewerId = aViewerId != null ? aViewerId : ""; //$NON-NLS-1$
164
		viewerDescriptor = VIEWER_DESCRIPTOR_REGISTRY
165
				.getNavigatorViewerDescriptor(aViewerId);
166
		assistant = new VisibilityAssistant(viewerDescriptor,
167
				getActivationService());
168
		getActivationService().addExtensionActivationListener(this);
169
		contributionMemory = new HashMap();
170
		contributionMemoryFirstClass = new HashMap();
171
	}
172

    
173
	/**
174
	 * @param aViewerId
175
	 *            The viewer id for this content service; normally from the
176
	 *            <b>org.eclipse.ui.views</b> extension.
177
	 * @param aViewer
178
	 *            The viewer that this content service will be associated with.
179
	 */
180
	public NavigatorContentService(String aViewerId, StructuredViewer aViewer) {
181
		this(aViewerId);
182
		structuredViewerManager = new StructuredViewerManager(aViewer, this);
183
	}
184

    
185
	public String[] getVisibleExtensionIds() {
186

    
187
		List visibleExtensionIds = new ArrayList();
188

    
189
		NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
190
				.getAllContentDescriptors();
191
		for (int i = 0; i < descriptors.length; i++) {
192
			if (assistant.isVisible(descriptors[i].getId())) {
193
				visibleExtensionIds.add(descriptors[i].getId());
194
			}
195
		}
196
		if (visibleExtensionIds.isEmpty()) {
197
			return NO_EXTENSION_IDS;
198
		}
199
		return (String[]) visibleExtensionIds
200
				.toArray(new String[visibleExtensionIds.size()]);
201

    
202
	}
203

    
204
	public INavigatorContentDescriptor[] getVisibleExtensions() {
205
		List visibleDescriptors = new ArrayList();
206

    
207
		NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
208
				.getAllContentDescriptors();
209
		for (int i = 0; i < descriptors.length; i++) {
210
			if (assistant.isVisible(descriptors[i].getId())) {
211
				visibleDescriptors.add(descriptors[i]);
212
			}
213
		}
214
		if (visibleDescriptors.isEmpty()) {
215
			return NO_DESCRIPTORS;
216
		}
217
		return (INavigatorContentDescriptor[]) visibleDescriptors
218
				.toArray(new INavigatorContentDescriptor[visibleDescriptors
219
						.size()]);
220

    
221
	}
222

    
223
	/* package */INavigatorContentDescriptor[] getActiveDescriptorsWithSaveables() {
224
		List result = new ArrayList();
225

    
226
		NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
227
				.getContentDescriptorsWithSaveables();
228
		for (int i = 0; i < descriptors.length; i++) {
229
			if (assistant.isVisible(descriptors[i].getId())
230
					&& assistant.isActive(descriptors[i])) {
231
				result.add(descriptors[i]);
232
			}
233
		}
234
		if (result.isEmpty()) {
235
			return NO_DESCRIPTORS;
236
		}
237
		return (INavigatorContentDescriptor[]) result
238
				.toArray(new INavigatorContentDescriptor[result.size()]);
239

    
240
	}
241

    
242
	/*
243
	 * (non-Javadoc)
244
	 * 
245
	 * @see
246
	 * org.eclipse.ui.navigator.INavigatorContentService#bindExtensions(java
247
	 * .lang.String[], boolean)
248
	 */
249
	public INavigatorContentDescriptor[] bindExtensions(String[] extensionIds,
250
			boolean isRoot) {
251
		if (extensionIds == null || extensionIds.length == 0) {
252
			return NO_DESCRIPTORS;
253
		}
254

    
255
		for (int i = 0; i < extensionIds.length; i++) {
256
			assistant.bindExtensions(extensionIds, isRoot);
257
		}
258
		Set boundDescriptors = new HashSet();
259
		INavigatorContentDescriptor descriptor;
260
		for (int i = 0; i < extensionIds.length; i++) {
261
			descriptor = CONTENT_DESCRIPTOR_REGISTRY
262
					.getContentDescriptor(extensionIds[i]);
263
			if (descriptor != null) {
264
				boundDescriptors.add(descriptor);
265
			}
266
		}
267

    
268
		if (boundDescriptors.size() == 0) {
269
			return NO_DESCRIPTORS;
270
		}
271
		
272
		if (Policy.DEBUG_EXTENSION_SETUP) {
273
			System.out.println("bindExtensions: " + //$NON-NLS-1$
274
					boundDescriptors);
275
		}
276
		return (INavigatorContentDescriptor[]) boundDescriptors
277
				.toArray(new INavigatorContentDescriptor[boundDescriptors
278
						.size()]);
279

    
280
	}
281

    
282
	/*
283
	 * (non-Javadoc)
284
	 * 
285
	 * @seeorg.eclipse.ui.internal.navigator.INavigatorContentService#
286
	 * createCommonContentProvider()
287
	 */
288
	public ITreeContentProvider createCommonContentProvider() {
289
		if (contentProviderInitialized) {
290
			return contentProvider;
291
		}
292
		synchronized (this) {
293
			if (contentProvider == null) {
294
				contentProvider = new NavigatorContentServiceContentProvider(
295
						this);
296
			}
297
			contentProviderInitialized = true;
298
		}
299
		return contentProvider;
300
	}
301

    
302
	/*
303
	 * (non-Javadoc)
304
	 * 
305
	 * @seeorg.eclipse.ui.internal.navigator.INavigatorContentService#
306
	 * createCommonLabelProvider()
307
	 */
308
	public ILabelProvider createCommonLabelProvider() {
309
		if (labelProviderInitialized) {
310
			return labelProvider;
311
		}
312
		synchronized (this) {
313
			if (labelProvider == null) {
314
				labelProvider = new NavigatorContentServiceLabelProvider(this);
315
			}
316
			labelProviderInitialized = true;
317
		}
318
		return labelProvider;
319
	}
320

    
321
	/*
322
	 * (non-Javadoc)
323
	 * 
324
	 * @seeorg.eclipse.ui.navigator.INavigatorContentService#
325
	 * createCommonDescriptionProvider()
326
	 */
327
	public IDescriptionProvider createCommonDescriptionProvider() {
328
		if (descriptionProvider != null) {
329
			return descriptionProvider;
330
		}
331
		synchronized (this) {
332
			if (descriptionProvider == null) {
333
				descriptionProvider = new NavigatorContentServiceDescriptionProvider(
334
						this);
335
			}
336
		}
337
		return descriptionProvider;
338
	}
339

    
340
	/*
341
	 * (non-Javadoc)
342
	 * 
343
	 * @see org.eclipse.ui.internal.navigator.INavigatorContentService#dispose()
344
	 */
345
	public void dispose() {
346
		if (navigatorSaveablesService != null) {
347
			assistant.removeListener(navigatorSaveablesService);
348
		}
349
		if (navigatorSorterService != null) {
350
			assistant.removeListener(navigatorSorterService);
351
		}
352
		synchronized (this) {
353
			for (Iterator contentItr = contentExtensions.values().iterator(); contentItr
354
					.hasNext();) {
355
				((NavigatorContentExtension) contentItr.next()).dispose();
356
			}
357
		}
358
		getActivationService().removeExtensionActivationListener(this);
359
		assistant.dispose();
360
		isDisposed = true;
361
	}
362

    
363
	protected void updateService(Viewer aViewer, Object anOldInput,
364
			Object aNewInput) {
365

    
366
		// Prevents the world from being started again once we have been disposed.  In
367
		// the dispose process, the ContentViewer will call setInput() on the
368
		// NavigatorContentServiceContentProvider, which gets us here
369
		if (isDisposed)
370
			return;
371
		synchronized (this) {
372

    
373
			if (structuredViewerManager == null) {
374
				structuredViewerManager = new StructuredViewerManager((StructuredViewer) aViewer, this);
375
				structuredViewerManager.inputChanged(anOldInput, aNewInput);
376
			} else {
377
				structuredViewerManager.inputChanged(aViewer, anOldInput,
378
						aNewInput);
379
			}
380

    
381
			for (Iterator contentItr = contentExtensions.values().iterator(); contentItr
382
					.hasNext();) {
383
				NavigatorContentExtension ext = (NavigatorContentExtension) contentItr
384
						.next();
385
				if (ext.isLoaded()) {
386
					structuredViewerManager
387
							.initialize(ext.internalGetContentProvider());
388
				}
389
			}
390

    
391
			rootContentProviders = extractContentProviders(findRootContentExtensions(aNewInput));
392
		}
393
	}
394

    
395
	public IExtensionStateModel findStateModel(String anExtensionId) {
396
		if (anExtensionId == null) {
397
			return null;
398
		}
399
		INavigatorContentDescriptor desc = CONTENT_DESCRIPTOR_REGISTRY
400
				.getContentDescriptor(anExtensionId);
401
		if (desc == null) {
402
			return null;
403
		}
404
		INavigatorContentExtension ext = getExtension(desc);
405
		if (ext == null) {
406
			return null;
407
		}
408
		return ext.getStateModel();
409
	}
410

    
411
	/**
412
	 * <p>
413
	 * Return all of the content providers that are relevant for the viewer. The
414
	 * viewer is determined by the ID used to create the
415
	 * INavigatorContentService ({@link #getViewerId() }). See
416
	 * {@link #createCommonContentProvider() } for more information about how
417
	 * content providers are located for the root of the viewer. The root
418
	 * content providers are calculated once. If a new element is supplied, a
419
	 * client must call {@link #update() } prior in order to reset the calculated
420
	 * root providers.
421
	 * </p>
422
	 * 
423
	 * @param anElement
424
	 *            An element from the tree (generally the input of the viewer)
425
	 * @return The set of content providers that can provide root elements for a
426
	 *         viewer.
427
	 */
428
	public ITreeContentProvider[] findRootContentProviders(Object anElement) {
429
		if (rootContentProviders != null) {
430
			return rootContentProviders;
431
		}
432
		synchronized (this) {
433
			if (rootContentProviders == null) {
434
				rootContentProviders = extractContentProviders(findRootContentExtensions(anElement));
435

    
436
			}
437
		}
438
		return rootContentProviders;
439
	}
440
	
441
	/**
442
	 * Returns the list of extensions that should be considered as possible
443
	 * contributors of CNF artifacts (labels, sorters, ...). The algorithm
444
	 * first considers the source of contribution and its overrides, and then
445
	 * any possibleChildren and their overrides in order.
446
	 * 
447
	 * @param anElement
448
	 *            An element from the tree (any element contributed to the
449
	 *            tree).
450
	 * @return A Collection of NCEs sorted in the correct order for label provider application
451
	 */
452
	public Collection findPossibleLabelExtensions(Object anElement) {
453
		LinkedHashSet contributors = new LinkedHashSet();
454
		INavigatorContentDescriptor sourceDescriptor = getSourceOfContribution(anElement);
455
		
456
		// This is a TreeSet sorted ascending
457
		Set possibleChildDescriptors = findDescriptorsWithPossibleChild(anElement, false);
458

    
459
		// Add the source so that it gets sorted into the right place
460
		if (sourceDescriptor != null) {
461
			possibleChildDescriptors.add(sourceDescriptor);
462
		}
463

    
464
		for (Iterator iter = possibleChildDescriptors.iterator(); iter.hasNext();) {
465
			NavigatorContentDescriptor ncd = (NavigatorContentDescriptor) iter.next();
466
			findOverridingLabelExtensions(anElement, ncd, contributors);
467
		}
468
		
469
		return contributors;
470
	}
471

    
472
	private void findOverridingLabelExtensions(Object anElement,
473
			INavigatorContentDescriptor descriptor, LinkedHashSet contributors) {
474
		ListIterator iter = ((NavigatorContentDescriptor) descriptor).getOverridingExtensionsListIterator(false);
475
		while (iter.hasPrevious()) {
476
			INavigatorContentDescriptor child = (INavigatorContentDescriptor) iter.previous();
477
			if (assistant.isVisibleAndActive(child) && child.isPossibleChild(anElement)) {
478
				findOverridingLabelExtensions(anElement, child, contributors);
479
			}
480
		}
481
		contributors.add(getExtension(descriptor));
482
	}
483
	
484
	/**
485
	 * 
486
	 * The label provider that is are enabled for the given element.
487
	 * A label provider is 'enabled' if its corresponding content provider
488
	 * returned the element.
489
	 * 
490
	 * @param anElement
491
	 *            An element from the tree (any element contributed to the
492
	 *            tree).
493
	 * @return The label provider
494
	 */
495
	public ILabelProvider[] findRelevantLabelProviders(Object anElement) {
496
		Collection extensions = findPossibleLabelExtensions(anElement);
497
		
498
		if (extensions.size() == 0) {
499
			return NO_LABEL_PROVIDERS;
500
		}
501
		List resultProvidersList = new ArrayList();
502
		for (Iterator itr = extensions.iterator(); itr.hasNext();) {
503
			resultProvidersList.add(((NavigatorContentExtension) itr.next()).getLabelProvider());
504
		}
505
		return (ILabelProvider[]) resultProvidersList.toArray(new ILabelProvider[resultProvidersList.size()]);
506
	}
507

    
508
	/**
509
	 * Search for extensions that declare the given element in their
510
	 * <b>triggerPoints</b> expression.
511
	 * 
512
	 * @param anElement
513
	 *            The element to use in the query
514
	 * @return The set of {@link INavigatorContentExtension}s that are
515
	 *         <i>visible</i> and <i>active</i> for this content service and
516
	 *         either declared through a
517
	 *         <b>org.eclipse.ui.navigator.viewer/viewerContentBinding</b> to be
518
	 *         a root element or have a <b>triggerPoints</b> expression that is
519
	 *         <i>enabled</i> for the given element.
520
	 */
521
	public Set findRootContentExtensions(Object anElement) {
522
		return findRootContentExtensions(anElement, true);
523
	}
524

    
525
	/**
526
	 * Search for extensions that declare the given element in their
527
	 * <b>triggerPoints</b> expression.
528
	 * 
529
	 * @param anElement
530
	 *            The element to use in the query
531
	 * @param toRespectViewerRoots
532
	 *            True respect the <b>viewerContentBinding</b>s, False will look
533
	 *            only for matching <b>triggerPoints</b> expressions.
534
	 * @return The set of {@link INavigatorContentExtension}s that are
535
	 *         <i>visible</i> and <i>active</i> for this content service and
536
	 *         either declared through a
537
	 *         <b>org.eclipse.ui.navigator.viewer/viewerContentBinding</b> to be
538
	 *         a root element or have a <b>triggerPoints</b> expression that is
539
	 *         <i>enabled</i> for the given element.
540
	 */
541
	public Set findRootContentExtensions(Object anElement,
542
			boolean toRespectViewerRoots) {
543

    
544
		SortedSet rootExtensions = new TreeSet(
545
				ExtensionSequenceNumberComparator.INSTANCE);
546
		if (toRespectViewerRoots
547
				/*&& viewerDescriptor.hasOverriddenRootExtensions()*/) {
548

    
549
			NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
550
					.getAllContentDescriptors();
551

    
552
			NavigatorContentExtension extension = null;
553
			for (int i = 0; i < descriptors.length; i++) {
554
				if (isActive(descriptors[i].getId())
555
						&& isRootExtension(descriptors[i].getId())) {
556
					extension = getExtension(descriptors[i]);
557
					if (!extension.hasLoadingFailed()) {
558
						rootExtensions.add(extension);
559
					}
560
				}
561
			}
562
		}
563
		if (rootExtensions.isEmpty()) {
564
			return findContentExtensionsByTriggerPoint(anElement);
565
		}
566
		return rootExtensions;
567
	}
568

    
569
	/**
570
	 * Search for extensions that declare the given element in their
571
	 * <b>possibleChildren</b> expression.
572
	 * 
573
	 * @param anElement
574
	 *            The element to use in the query
575
	 * @return The set of {@link INavigatorContentExtension}s that are
576
	 *         <i>visible</i> and <i>active</i> for this content service and
577
	 *         have a <b>possibleChildren</b> expression that is <i>enabled</i>
578
	 *         for the given element.
579
	 */
580
	public Set findOverrideableContentExtensionsForPossibleChild(
581
			Object anElement) {
582
		Set overrideableExtensions = new TreeSet(
583
				ExtensionSequenceNumberComparator.INSTANCE);
584
		Set descriptors = findDescriptorsWithPossibleChild(anElement, false);
585
		for (Iterator iter = descriptors.iterator(); iter.hasNext();) {
586
			INavigatorContentDescriptor descriptor = (INavigatorContentDescriptor) iter
587
					.next();
588
			if (descriptor.hasOverridingExtensions()) {
589
				overrideableExtensions.add(getExtension(descriptor));
590
			}
591
		}
592
		return overrideableExtensions;
593
	}
594

    
595
	/*
596
	 * (Non-Javadoc)
597
	 * 
598
	 * @see INavigatorContentService#getContentDescriptorById(String)
599
	 */
600
	public INavigatorContentDescriptor getContentDescriptorById(
601
			String anExtensionId) {
602
		return CONTENT_DESCRIPTOR_REGISTRY.getContentDescriptor(anExtensionId);
603
	}
604

    
605
	/**
606
	 * 
607
	 * @param anExtensionId
608
	 *            The id used to define the
609
	 *            <b>org.eclipse.ui.navigator.navigatorContent
610
	 *            /navigatorContent</b> extension.
611
	 * @return An instance of the content extension for the given extension id.
612
	 *         May return <b>null</b> if the id is invalid.
613
	 */
614
	public INavigatorContentExtension getContentExtensionById(
615
			String anExtensionId) {
616
		NavigatorContentDescriptor descriptor = CONTENT_DESCRIPTOR_REGISTRY
617
				.getContentDescriptor(anExtensionId);
618
		if (descriptor != null)
619
			return getExtension(descriptor);
620
		return null;
621
	}
622

    
623
	/**
624
	 * Search for extensions that declare the given element in their
625
	 * <b>triggerPoints</b> expression.
626
	 * 
627
	 * @param anElement
628
	 *            The element to use in the query
629
	 * @return The set of {@link INavigatorContentExtension}s that are
630
	 *         <i>visible</i> and <i>active</i> for this content service and
631
	 *         have a <b>triggerPoints</b> expression that is <i>enabled</i> for
632
	 *         the given element.
633
	 */
634
	public Set findContentExtensionsByTriggerPoint(Object anElement) {
635
		return findContentExtensionsByTriggerPoint(anElement, true, !CONSIDER_OVERRIDES);
636
	}
637

    
638
	/**
639
	 * Search for extensions that declare the given element in their
640
	 * <b>triggerPoints</b> expression.
641
	 * 
642
	 * @param anElement
643
	 *            The element to use in the query
644
	 * @param toLoadIfNecessary
645
	 *            True will force the load of the extension, False will not
646
	 * @param computeOverrides
647
	 * @return The set of {@link INavigatorContentExtension}s that are
648
	 *         <i>visible</i> and <i>active</i> for this content service and
649
	 *         have a <b>triggerPoints</b> expression that is <i>enabled</i> for
650
	 *         the given element.
651
	 */
652
	public Set findContentExtensionsByTriggerPoint(Object anElement,
653
			boolean toLoadIfNecessary, boolean computeOverrides) {
654
		Set enabledDescriptors = findDescriptorsByTriggerPoint(anElement, computeOverrides);
655
		return extractDescriptorInstances(enabledDescriptors, toLoadIfNecessary);
656
	}
657

    
658
	/**
659
	 * Search for extensions that declare the given element in their
660
	 * <b>possibleChildren</b> expression.
661
	 * 
662
	 * @param anElement
663
	 *            The element to use in the query
664
	 * @return The set of {@link INavigatorContentExtension}s that are
665
	 *         <i>visible</i> and <i>active</i> for this content service and
666
	 *         have a <b>possibleChildren</b> expression that is <i>enabled</i>
667
	 *         for the given element.
668
	 */
669
	public Set findContentExtensionsWithPossibleChild(Object anElement) {
670
		return findContentExtensionsWithPossibleChild(anElement, true);
671
	}
672

    
673
	/**
674
	 * Search for extensions that declare the given element in their
675
	 * <b>possibleChildren</b> expression.
676
	 * 
677
	 * @param anElement
678
	 *            The element to use in the query
679
	 * @param toLoadIfNecessary
680
	 *            True will force the load of the extension, False will not
681
	 * @return The set of {@link INavigatorContentExtension}s that are
682
	 *         <i>visible</i> and <i>active</i> for this content service and
683
	 *         have a <b>possibleChildren</b> expression that is <i>enabled</i>
684
	 *         for the given element.
685
	 */
686
	public Set findContentExtensionsWithPossibleChild(Object anElement,
687
			boolean toLoadIfNecessary) {
688
		Set enabledDescriptors = findDescriptorsWithPossibleChild(anElement);
689
		return extractDescriptorInstances(enabledDescriptors, toLoadIfNecessary);
690
	}
691

    
692
	/**
693
	 * 
694
	 * 
695
	 * @param firstClassSource
696
	 * @param source
697
	 * @param element
698
	 */
699
	public void rememberContribution(INavigatorContentDescriptor source,
700
			INavigatorContentDescriptor firstClassSource, Object element) {
701
		/*
702
		 * We want to write to (overwrite) the contributionMemory only if we
703
		 * have never heard of the element before, or if the element is coming
704
		 * from the same first class NCE, which means that the subsequent NCE is
705
		 * an override. The override will take precedence over the originally
706
		 * contributing NCE. However in the case of different first class NCEs,
707
		 * the first one wins, so we don't update the contribution memory.
708
		 */
709
		synchronized (this) {
710
			if (contributionMemory.get(element) == null
711
					|| contributionMemoryFirstClass.get(element) == firstClassSource) {
712
				if (Policy.DEBUG_RESOLUTION)
713
					System.out
714
							.println("rememberContribution: " + Policy.getObjectString(element) + " source: " + source); //$NON-NLS-1$//$NON-NLS-2$
715
				contributionMemory.put(element, source);
716
				contributionMemoryFirstClass.put(element, firstClassSource);
717
			}
718
		}
719
	}
720

    
721
	/**
722
	 * Forget about the specified element
723
	 * 
724
	 * @param element
725
	 *            The element to forget.
726
	 */
727
	public void forgetContribution(Object element) {
728
		synchronized (this) {
729
			contributionMemory.remove(element);
730
			contributionMemoryFirstClass.remove(element);
731
		}
732
	}
733

    
734
	/**
735
	 * @param element
736
	 * @return the remembered NavigatorContentDescriptor
737
	 */
738
	public NavigatorContentDescriptor getContribution(Object element)
739
	{
740
		NavigatorContentDescriptor desc;
741
		synchronized (this) {
742
			desc = (NavigatorContentDescriptor) contributionMemory.get(element);
743
		}
744
		return desc;
745
	}
746
	
747
	/**
748
	 * Used only for the tests
749
	 * @return the size of the contribution memory
750
	 */
751
	public int getContributionMemorySize() {
752
		synchronized (this) {
753
			return contributionMemory.size();
754
		}
755
	}
756
	
757
	/**
758
	 * 
759
	 * @param element
760
	 *            The element contributed by the descriptor to be returned
761
	 * @return The descriptor that contributed the element or null.
762
	 * @see #findContentExtensionsByTriggerPoint(Object)
763
	 */
764
	public synchronized NavigatorContentDescriptor getSourceOfContribution(Object element) {
765
		if (element == null)
766
			return null;
767
		if (structuredViewerManager == null)
768
			return null;
769
		// Try here first because it might not yet be in the tree
770
		NavigatorContentDescriptor src;
771
		synchronized (this) {
772
			src = (NavigatorContentDescriptor) contributionMemory.get(element);
773
		}
774
		if (src != null)
775
			return src;
776
		return (NavigatorContentDescriptor) structuredViewerManager.getData(element);
777
	}
778
	/**
779
	 * 
780
	 */
781
	public static final boolean CONSIDER_OVERRIDES = true;
782
	
783
	/**
784
	 * Search for extensions that declare the given element in their
785
	 * <b>triggerPoints</b> expression.
786
	 * 
787
	 * @param anElement
788
	 *            The element to use in the query
789
	 * @param considerOverrides
790
	 * 
791
	 * @return The set of {@link INavigatorContentDescriptor}s that are
792
	 *         <i>visible</i> and <i>active</i> for this content service and
793
	 *         have a <b>triggerPoints</b> expression that is <i>enabled</i> for
794
	 *         the given element.
795
	 */
796
	public Set findDescriptorsByTriggerPoint(Object anElement, boolean considerOverrides) {
797
		// Here we use the cache, since objects are inserted into the
798
		// cache in response to the trigger point
799
		NavigatorContentDescriptor descriptor = getSourceOfContribution(anElement);
800
		Set result = new TreeSet(ExtensionSequenceNumberComparator.INSTANCE);
801
		if (descriptor != null) {
802
			result.add(descriptor);
803
		}
804
		result.addAll(CONTENT_DESCRIPTOR_REGISTRY
805
				.findDescriptorsForTriggerPoint(anElement, assistant, considerOverrides));
806
		return result;
807
	}
808

    
809
	/**
810
	 * Search for extensions that declare the given element in their
811
	 * <b>possibleChildren</b> expression.
812
	 * 
813
	 * @param anElement
814
	 *            The element to use in the query
815
	 * @return The set of {@link INavigatorContentDescriptor}s that are
816
	 *         <i>visible</i> and <i>active</i> for this content service and
817
	 *         have a <b>possibleChildren</b> expression that is <i>enabled</i>
818
	 *         for the given element.
819
	 */
820
	public Set findDescriptorsWithPossibleChild(Object anElement) {
821
		return findDescriptorsWithPossibleChild(anElement, true);
822
	}
823

    
824
	/**
825
	 * Search for extensions that declare the given element in their
826
	 * <b>possibleChildren</b> expression.
827
	 * 
828
	 * @param anElement
829
	 *            The element to use in the query
830
	 * @param toComputeOverrides
831
	 *            True indicates the overridden tree should be traversed.
832
	 * @return The set of {@link INavigatorContentDescriptor}s that are
833
	 *         <i>visible</i> and <i>active</i> for this content service and
834
	 *         have a <b>possibleChildren</b> expression that is <i>enabled</i>
835
	 *         for the given element.
836
	 */
837
	public Set findDescriptorsWithPossibleChild(Object anElement,
838
			boolean toComputeOverrides) {
839
		// Don't use the cache which is only used for triggerPoints
840
		Set result = new TreeSet(ExtensionSequenceNumberComparator.INSTANCE);
841
		result.addAll(CONTENT_DESCRIPTOR_REGISTRY
842
				.findDescriptorsForPossibleChild(anElement, assistant,
843
						toComputeOverrides));
844
		return result;
845
	}
846

    
847
	/*
848
	 * (non-Javadoc)
849
	 * 
850
	 * @seeorg.eclipse.ui.internal.navigator.INavigatorContentService#
851
	 * onExtensionActivation(java.lang.String, java.lang.String, boolean)
852
	 */
853
	public void onExtensionActivation(String aViewerId,
854
			String[] aNavigatorExtensionId, boolean toEnable) {
855
		synchronized (this) {
856
			SafeRunner.run(new NavigatorSafeRunnable() {
857
				public void run() throws Exception {
858
					NavigatorContentDescriptor key;
859
					NavigatorContentExtension extension;
860
					for (Iterator iter = contentExtensions.keySet().iterator(); iter
861
							.hasNext();) {
862
						key = (NavigatorContentDescriptor) iter.next();
863
						INavigatorActivationService activation = getActivationService();
864
						if (!activation.isNavigatorExtensionActive(key.getId())) {
865
							extension = (NavigatorContentExtension) contentExtensions
866
									.get(key);
867
							iter.remove();
868
							extension.dispose();
869
						}
870
					}
871
				}
872
			});
873
		}
874
		if (structuredViewerManager != null) {
875
			structuredViewerManager.resetViewerData();
876
		}
877
		update();
878
	}
879

    
880
	/*
881
	 * (non-Javadoc)
882
	 * 
883
	 * @see org.eclipse.ui.internal.navigator.INavigatorContentService#update()
884
	 */
885
	public void update() {
886
		rootContentProviders = null;
887
		if (structuredViewerManager != null) {
888
			structuredViewerManager.safeRefresh();
889
		}
890
	}
891

    
892
	/*
893
	 * (non-Javadoc)
894
	 * 
895
	 * @see
896
	 * org.eclipse.ui.internal.navigator.INavigatorContentService#getViewerId()
897
	 */
898
	public final String getViewerId() {
899
		return viewerDescriptor.getViewerId();
900
	}
901

    
902
	/**
903
	 * Returns the remembered data (the NavigatorContentDescriptor) associated with
904
	 * an object in the viewer. This can be used to test an object's presence in the viewer.
905
	 * @param element
906
	 * @return the object stored as data in the viewer
907
	 */
908
	public Object getViewerElementData(Object element) {
909
		if (structuredViewerManager != null) {
910
			return structuredViewerManager.getData(element);
911
		}
912
		return null;
913
	}
914
	
915
	/**
916
	 * 
917
	 * @param aDescriptorKey
918
	 *            A descriptor
919
	 * @return The cached NavigatorContentExtension from the descriptor
920
	 */
921
	public final NavigatorContentExtension getExtension(
922
			INavigatorContentDescriptor aDescriptorKey) {
923
		return getExtension(aDescriptorKey, true);
924
	}
925

    
926
	/**
927
	 * 
928
	 * @param aDescriptorKey
929
	 * @param toLoadIfNecessary
930
	 *            True if the extension should be loaded if it is not already.
931
	 * @return The instance of the extension for the given descriptor key.
932
	 */
933
	public final NavigatorContentExtension getExtension(
934
			INavigatorContentDescriptor aDescriptorKey,
935
			boolean toLoadIfNecessary) {
936
		/* Query and return the relevant descriptor instance */
937
		NavigatorContentExtension extension = (NavigatorContentExtension) contentExtensions
938
				.get(aDescriptorKey);
939
		if (extension != null || !toLoadIfNecessary) {
940
			return extension;
941
		}
942

    
943
		/*
944
		 * If the descriptor instance hasn't been created yet, then we need to
945
		 * (1) verify that it wasn't added by another thread, (2) create and add
946
		 * the result into the map
947
		 */
948
		synchronized (this) {
949
			extension = (NavigatorContentExtension) contentExtensions
950
					.get(aDescriptorKey);
951
			if (extension == null) {
952
				contentExtensions.put(aDescriptorKey,
953
						(extension = new NavigatorContentExtension(
954
								(NavigatorContentDescriptor) aDescriptorKey,
955
								this, structuredViewerManager)));
956
				notifyListeners(extension);
957
			}
958
		}
959
		return extension;
960

    
961
	}
962

    
963
	/*
964
	 * (non-Javadoc)
965
	 * 
966
	 * @seeorg.eclipse.ui.internal.navigator.INavigatorContentService#
967
	 * getViewerDescriptor()
968
	 */
969
	public INavigatorViewerDescriptor getViewerDescriptor() {
970
		return viewerDescriptor;
971
	}
972

    
973
	/*
974
	 * (non-Javadoc)
975
	 * 
976
	 * @see
977
	 * org.eclipse.ui.internal.navigator.INavigatorContentService#restoreState
978
	 * (org.eclipse.ui.IMemento)
979
	 */
980
	public void restoreState(final IMemento aMemento) {
981
		synchronized (this) {
982
			for (Iterator extensionItr = getExtensions().iterator(); extensionItr.hasNext();) {
983
				final NavigatorContentExtension element = (NavigatorContentExtension) extensionItr
984
						.next();
985
				SafeRunner.run(new NavigatorSafeRunnable(((NavigatorContentDescriptor) element
986
						.getDescriptor()).getConfigElement()) {
987
					public void run() throws Exception {
988
						element.restoreState(aMemento);
989
					}
990
				});
991
			}
992
		}
993
	}
994

    
995
	/*
996
	 * (non-Javadoc)
997
	 * 
998
	 * @see
999
	 * org.eclipse.ui.internal.navigator.INavigatorContentService#saveState(
1000
	 * org.eclipse.ui.IMemento)
1001
	 */
1002
	public void saveState(final IMemento aMemento) {
1003
		synchronized (this) {
1004
			for (Iterator extensionItr = getExtensions().iterator(); extensionItr.hasNext();) {
1005
				final NavigatorContentExtension element = (NavigatorContentExtension) extensionItr
1006
						.next();
1007
				SafeRunner.run(new NavigatorSafeRunnable(((NavigatorContentDescriptor) element
1008
						.getDescriptor()).getConfigElement()) {
1009
					public void run() throws Exception {
1010
						element.saveState(aMemento);
1011
					}
1012
				});
1013
			}
1014
		}
1015
	}
1016

    
1017
	public boolean isActive(String anExtensionId) {
1018
		return assistant.isActive(anExtensionId);
1019
	}
1020

    
1021
	public boolean isVisible(String anExtensionId) {
1022
		return assistant.isVisible(anExtensionId);
1023
	}
1024

    
1025
	protected final Collection getExtensions() {
1026
		return (contentExtensions.size() > 0) ? Collections
1027
				.unmodifiableCollection(contentExtensions.values())
1028
				: Collections.EMPTY_LIST;
1029
	}
1030

    
1031
	/*
1032
	 * (non-Javadoc)
1033
	 * 
1034
	 * @see
1035
	 * org.eclipse.ui.internal.navigator.INavigatorContentService#addListener
1036
	 * (org
1037
	 * .eclipse.ui.internal.navigator.extensions.INavigatorContentServiceListener
1038
	 * )
1039
	 */
1040
	public void addListener(INavigatorContentServiceListener aListener) {
1041
		listeners.add(aListener);
1042
	}
1043

    
1044
	/*
1045
	 * (non-Javadoc)
1046
	 * 
1047
	 * @see org.eclipse.ui.navigator.INavigatorContentService#getFilterService()
1048
	 */
1049
	public INavigatorFilterService getFilterService() {
1050
		if (navigatorFilterService == null) {
1051
			navigatorFilterService = new NavigatorFilterService(this);
1052
		}
1053
		return navigatorFilterService;
1054
	}
1055

    
1056
	/*
1057
	 * (non-Javadoc)
1058
	 * 
1059
	 * @see org.eclipse.ui.navigator.INavigatorContentService#getFilterService()
1060
	 */
1061
	public INavigatorSorterService getSorterService() {
1062
		if (navigatorSorterService == null) {
1063
			navigatorSorterService = new NavigatorSorterService(this);
1064
			assistant.addListener(navigatorSorterService);
1065
		}
1066
		return navigatorSorterService;
1067
	}
1068

    
1069
	/*
1070
	 * (non-Javadoc)
1071
	 * 
1072
	 * @see org.eclipse.ui.navigator.INavigatorContentService#getFilterService()
1073
	 */
1074
	public INavigatorPipelineService getPipelineService() {
1075
		if (navigatorPipelineService == null) {
1076
			navigatorPipelineService = new NavigatorPipelineService(this);
1077
		}
1078
		return navigatorPipelineService;
1079
	}
1080

    
1081
	/*
1082
	 * (non-Javadoc)
1083
	 * 
1084
	 * @see org.eclipse.ui.navigator.INavigatorContentService#getDnDService()
1085
	 */
1086
	public INavigatorDnDService getDnDService() {
1087
		if (navigatorDnDService == null) {
1088
			navigatorDnDService = new NavigatorDnDService(this);
1089
		}
1090
		return navigatorDnDService;
1091
	}
1092

    
1093
	/*
1094
	 * (non-Javadoc)
1095
	 * 
1096
	 * @see
1097
	 * org.eclipse.ui.navigator.INavigatorContentService#getActivationService()
1098
	 */
1099
	public INavigatorActivationService getActivationService() {
1100

    
1101
		if (navigatorActivationService == null) {
1102
			navigatorActivationService = new NavigatorActivationService(this);
1103
		}
1104
		return navigatorActivationService;
1105
	}
1106

    
1107
	/*
1108
	 * (non-Javadoc)
1109
	 * 
1110
	 * @see
1111
	 * org.eclipse.ui.navigator.INavigatorContentService#getSaveableService()
1112
	 */
1113
	public INavigatorSaveablesService getSaveablesService() {
1114
		synchronized (this) {
1115
			if (navigatorSaveablesService == null) {
1116
				navigatorSaveablesService = new NavigatorSaveablesService(this);
1117
				assistant.addListener(navigatorSaveablesService);
1118
			}
1119
			return navigatorSaveablesService;
1120
		}
1121
	}
1122

    
1123
	/**
1124
	 * Not API as of 3.3.
1125
	 * 
1126
	 * @return The extension state service for this content service.
1127
	 * 
1128
	 */
1129
	public NavigatorExtensionStateService getExtensionStateService() {
1130
		if (navigatorExtensionStateService == null) {
1131
			navigatorExtensionStateService = new NavigatorExtensionStateService(
1132
					this);
1133
		}
1134
		return navigatorExtensionStateService;
1135
	}
1136

    
1137
	/**
1138
	 * Non-API method to return a shell.
1139
	 * 
1140
	 * @return A shell associated with the current viewer (if any) or
1141
	 *         <b>null</b>.
1142
	 */
1143
	public Shell getShell() {
1144
		if (structuredViewerManager != null
1145
				&& structuredViewerManager.getViewer() != null) {
1146
			return structuredViewerManager.getViewer().getControl().getShell();
1147
		}
1148
		return null;
1149
	}
1150

    
1151
	protected boolean isRootExtension(String anExtensionId) {
1152
		return assistant.isRootExtension(anExtensionId);
1153
	}
1154

    
1155
	/*
1156
	 * (non-Javadoc)
1157
	 * 
1158
	 * @see
1159
	 * org.eclipse.ui.internal.navigator.INavigatorContentService#removeListener
1160
	 * (
1161
	 * org.eclipse.ui.internal.navigator.extensions.INavigatorContentServiceListener
1162
	 * )
1163
	 */
1164
	public void removeListener(INavigatorContentServiceListener aListener) {
1165
		listeners.remove(aListener);
1166
	}
1167

    
1168
	/*
1169
	 * (non-Javadoc)
1170
	 * 
1171
	 * @see java.lang.Object#toString()
1172
	 */
1173
	public String toString() {
1174
		return "ContentService[" + viewerDescriptor.getViewerId() + "]"; //$NON-NLS-1$//$NON-NLS-2$
1175
	}
1176

    
1177
	private void notifyListeners(final NavigatorContentExtension aDescriptorInstance) {
1178

    
1179
		if (listeners.size() == 0) {
1180
			return;
1181
		}
1182

    
1183
		final List failedListeners = new ArrayList();
1184

    
1185
		for (Iterator listenersItr = listeners.iterator(); listenersItr.hasNext();) {
1186
			final INavigatorContentServiceListener listener = (INavigatorContentServiceListener) listenersItr
1187
					.next();
1188
			SafeRunner.run(new NavigatorSafeRunnable() {
1189

    
1190
				public void run() throws Exception {
1191
					listener.onLoad(aDescriptorInstance);
1192
				}
1193

    
1194
				public void handleException(Throwable e) {
1195
					super.handleException(e);
1196
					failedListeners.add(listener);
1197
				}
1198
			});
1199
		}
1200

    
1201
		if (failedListeners.size() > 0) {
1202
			listeners.removeAll(failedListeners);
1203
		}		
1204
	}
1205

    
1206
	private ITreeContentProvider[] extractContentProviders(
1207
			Set theDescriptorInstances) {
1208
		if (theDescriptorInstances.size() == 0) {
1209
			return NO_CONTENT_PROVIDERS;
1210
		}
1211
		List resultProvidersList = new ArrayList();
1212
		for (Iterator itr = theDescriptorInstances.iterator(); itr.hasNext();) {
1213
			resultProvidersList.add(((NavigatorContentExtension) itr.next())
1214
					.internalGetContentProvider());
1215
		}
1216
		return (ITreeContentProvider[]) resultProvidersList
1217
				.toArray(new ITreeContentProvider[resultProvidersList.size()]);
1218
	}
1219

    
1220
	private Set extractDescriptorInstances(Set theDescriptors,
1221
			boolean toLoadAllIfNecessary) {
1222
		if (theDescriptors.size() == 0) {
1223
			return Collections.EMPTY_SET;
1224
		}
1225
		Set resultInstances = new TreeSet(ExtensionSequenceNumberComparator.INSTANCE);
1226
		for (Iterator descriptorIter = theDescriptors.iterator(); descriptorIter
1227
				.hasNext();) {
1228
			NavigatorContentExtension extension = getExtension(
1229
					(NavigatorContentDescriptor) descriptorIter.next(),
1230
					toLoadAllIfNecessary);
1231
			if (extension != null) {
1232
				resultInstances.add(extension);
1233

    
1234
			}
1235
		}
1236
		return resultInstances;
1237
	}
1238

    
1239
	/**
1240
	 * @return the viewer
1241
	 */
1242
	public Viewer getViewer() {
1243
		return structuredViewerManager.getViewer();
1244
	}
1245

    
1246
	
1247
	/**
1248
	 * Get our preferences
1249
	 */
1250
	static IEclipsePreferences getPreferencesRoot() {
1251
		IEclipsePreferences root = (IEclipsePreferences) Platform.getPreferencesService().getRootNode().node(
1252
				InstanceScope.SCOPE);
1253
		return (IEclipsePreferences) root.node(NavigatorPlugin.PLUGIN_ID);
1254
	}
1255
	
1256
	
1257
	static void flushPreferences(IEclipsePreferences prefs) {
1258
		try {
1259
			prefs.flush();
1260
		} catch (BackingStoreException e) {
1261
			IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.ERROR,
1262
					CommonNavigatorMessages.NavigatorContentService_problemSavingPreferences, e);
1263
			Platform.getLog(Platform.getBundle(NavigatorPlugin.PLUGIN_ID)).log(status);
1264
		}
1265
	}
1266

    
1267
}
(13-13/31)