1 /******************************************************************************* 2 * Copyright (c) 2003, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.ui.internal.navigator.extensions; 15 16 import java.util.Iterator; 17 import java.util.LinkedHashSet; 18 import java.util.Set; 19 20 import org.eclipse.core.runtime.Assert; 21 import org.eclipse.core.runtime.SafeRunner; 22 import org.eclipse.jface.viewers.ILabelProvider; 23 import org.eclipse.jface.viewers.ILabelProviderListener; 24 import org.eclipse.jface.viewers.ITreeContentProvider; 25 import org.eclipse.ui.IMemento; 26 import org.eclipse.ui.internal.navigator.NavigatorContentService; 27 import org.eclipse.ui.internal.navigator.NavigatorSafeRunnable; 28 import org.eclipse.ui.internal.navigator.Policy; 29 import org.eclipse.ui.navigator.ICommonLabelProvider; 30 import org.eclipse.ui.navigator.IExtensionStateModel; 31 import org.eclipse.ui.navigator.IMementoAware; 32 import org.eclipse.ui.navigator.INavigatorContentDescriptor; 33 import org.eclipse.ui.navigator.INavigatorContentExtension; 34 35 /** 36 * 37 * @since 3.2 38 */ 39 public class NavigatorContentExtension implements IMementoAware, 40 INavigatorContentExtension { 41 42 private static final NavigatorContentExtension[] NO_EXTENSIONS = new NavigatorContentExtension[0]; 43 44 private NavigatorContentService contentService; 45 46 private NavigatorContentDescriptor descriptor; 47 48 private SafeDelegateTreeContentProvider contentProvider; 49 50 private ICommonLabelProvider labelProvider; 51 52 private boolean labelProviderInitializationFailed = false; 53 54 private boolean contentProviderInitializationFailed = false; 55 56 private boolean isDisposed = false; 57 58 private IMemento appliedMemento; 59 60 private StructuredViewerManager viewerManager; 61 62 /** 63 * Create an object to manage the instantiated elements from the extension. 64 * 65 * @param aDescriptor 66 * The descriptor that knows how to create elements and knows the 67 * id of the extension 68 * @param aContentService 69 * The content service that will manage this extension 70 * @param aViewerManager 71 * The viewer manager that knows how to initialize the content 72 * provider created by this extension. 73 */ NavigatorContentExtension(NavigatorContentDescriptor aDescriptor, NavigatorContentService aContentService, StructuredViewerManager aViewerManager)74 public NavigatorContentExtension(NavigatorContentDescriptor aDescriptor, 75 NavigatorContentService aContentService, 76 StructuredViewerManager aViewerManager) { 77 super(); 78 Assert.isNotNull(aDescriptor); 79 80 descriptor = aDescriptor; 81 contentService = aContentService; 82 viewerManager = aViewerManager; 83 } 84 85 @Override getId()86 public String getId() { 87 return descriptor.getId(); 88 } 89 90 @Override getDescriptor()91 public INavigatorContentDescriptor getDescriptor() { 92 return descriptor; 93 } 94 95 @Override getContentProvider()96 public ITreeContentProvider getContentProvider() { 97 return internalGetContentProvider().getDelegateContentProvider(); 98 } 99 100 /** 101 * 102 * @return The internal content provider that is wrapped by this extension. 103 */ internalGetContentProvider()104 public SafeDelegateTreeContentProvider internalGetContentProvider() { 105 if (contentProvider != null || contentProviderInitializationFailed) { 106 return contentProvider; 107 } 108 synchronized (this) { 109 SafeRunner.run(new NavigatorSafeRunnable() { 110 @Override 111 public void run() throws Exception { 112 if (contentProvider == null) { 113 ITreeContentProvider treeContentProvider = descriptor 114 .createContentProvider(); 115 if (treeContentProvider != null) { 116 contentProvider = new SafeDelegateTreeContentProvider( 117 treeContentProvider); 118 contentProvider.init(new CommonContentExtensionSite(getId(), 119 contentService, appliedMemento)); 120 viewerManager.initialize(contentProvider); 121 } else { 122 contentProvider = new SafeDelegateTreeContentProvider( 123 SkeletonTreeContentProvider.INSTANCE); 124 } 125 } 126 } 127 128 @Override 129 public void handleException(Throwable e) { 130 super.handleException(e); 131 contentProviderInitializationFailed = true; 132 } 133 }); 134 135 if (contentProviderInitializationFailed) { 136 contentProvider = new SafeDelegateTreeContentProvider( 137 SkeletonTreeContentProvider.INSTANCE); 138 } 139 } 140 return contentProvider; 141 } 142 143 @Override getLabelProvider()144 public ICommonLabelProvider getLabelProvider() { 145 if (labelProvider != null || labelProviderInitializationFailed) { 146 return labelProvider; 147 } 148 synchronized (this) { 149 SafeRunner.run(new NavigatorSafeRunnable() { 150 @Override 151 public void run() throws Exception { 152 if (labelProvider == null) { 153 ILabelProvider tempLabelProvider = descriptor.createLabelProvider(); 154 155 if (tempLabelProvider instanceof ICommonLabelProvider) { 156 labelProvider = (ICommonLabelProvider) tempLabelProvider; 157 labelProvider.init(new CommonContentExtensionSite(getId(), 158 contentService, appliedMemento)); 159 } else { 160 labelProvider = new SafeDelegateCommonLabelProvider(tempLabelProvider); 161 } 162 163 labelProvider.addListener((ILabelProviderListener) contentService 164 .createCommonLabelProvider()); 165 } 166 } 167 168 @Override 169 public void handleException(Throwable e) { 170 super.handleException(e); 171 labelProviderInitializationFailed = true; 172 } 173 }); 174 if (labelProviderInitializationFailed) { 175 labelProvider = SkeletonLabelProvider.INSTANCE; 176 } 177 } 178 return labelProvider; 179 } 180 181 /** 182 * Dispose of any resources acquired during the lifecycle of the extension. 183 * 184 */ dispose()185 public void dispose() { 186 try { 187 synchronized (this) { 188 189 SafeRunner.run(new NavigatorSafeRunnable() { 190 @Override 191 public void run() throws Exception { 192 if (contentProvider != null) { 193 contentProvider.dispose(); 194 } 195 196 } 197 }); 198 199 SafeRunner.run(new NavigatorSafeRunnable() { 200 @Override 201 public void run() throws Exception { 202 if (labelProvider != null) { 203 labelProvider 204 .removeListener((ILabelProviderListener) contentService 205 .createCommonLabelProvider()); 206 labelProvider.dispose(); 207 } 208 } 209 }); 210 211 } 212 } finally { 213 isDisposed = true; 214 } 215 } 216 217 @Override getAdapter(Class<T> adapter)218 public <T> T getAdapter(Class<T> adapter) { 219 return null; 220 } 221 222 /** 223 * @return Returns the contentProviderInitializationFailed. 224 */ hasContentProviderInitializationFailed()225 public boolean hasContentProviderInitializationFailed() { 226 return contentProviderInitializationFailed; 227 } 228 229 /** 230 * @return Returns the labelProviderInitializationFailed. 231 */ hasLabelProviderInitializationFailed()232 public boolean hasLabelProviderInitializationFailed() { 233 return labelProviderInitializationFailed; 234 } 235 236 /** 237 * 238 * @return True if the loading of the content provider has failed. 239 */ hasLoadingFailed()240 public boolean hasLoadingFailed() { 241 return contentProviderInitializationFailed; 242 } 243 244 @Override isLoaded()245 public boolean isLoaded() { 246 return contentProvider != null; 247 } 248 249 @Override restoreState(IMemento aMemento)250 public void restoreState(IMemento aMemento) { 251 synchronized (this) { 252 appliedMemento = aMemento; 253 applyMemento(contentProvider); 254 applyMemento(labelProvider); 255 256 } 257 } 258 259 @Override saveState(IMemento aMemento)260 public void saveState(IMemento aMemento) { 261 synchronized (this) { 262 if (contentProvider != null) { 263 contentProvider.saveState(aMemento); 264 } 265 if (labelProvider != null) { 266 labelProvider.saveState(aMemento); 267 } 268 } 269 } 270 applyMemento(IMementoAware target)271 private void applyMemento(IMementoAware target) { 272 if (target != null) { 273 target.restoreState(appliedMemento); 274 } 275 276 } 277 complainDisposedIfNecessary()278 protected final void complainDisposedIfNecessary() { 279 if (isDisposed) { 280 throw new IllegalStateException("INavigatorContentExtension " //$NON-NLS-1$ 281 + descriptor.getId() + " is disposed!"); //$NON-NLS-1$ 282 } 283 } 284 285 @Override getStateModel()286 public IExtensionStateModel getStateModel() { 287 return contentService.getExtensionStateService() 288 .getExtensionStateModel(getDescriptor()); 289 } 290 291 /** 292 * @param anElement 293 * The element for the query. 294 * @return Returns the overridingExtensions. 295 */ getOverridingExtensionsForTriggerPoint( Object anElement)296 public NavigatorContentExtension[] getOverridingExtensionsForTriggerPoint( 297 Object anElement) { 298 return getOverridingExtensions(anElement, TRIGGER_POINT); 299 } 300 301 /** 302 * 303 * @param anElement 304 * The element for the query. 305 * @return Returns the overridingExtensions. 306 */ getOverridingExtensionsForPossibleChild( Object anElement)307 public NavigatorContentExtension[] getOverridingExtensionsForPossibleChild( 308 Object anElement) { 309 return getOverridingExtensions(anElement, !TRIGGER_POINT); 310 } 311 312 /** 313 * 314 * @return Returns the overridingExtensions. 315 */ getOverridingExtensions()316 public NavigatorContentExtension[] getOverridingExtensions() { 317 return getOverridingExtensions(null, !TRIGGER_POINT); 318 } 319 320 private static final boolean TRIGGER_POINT = true; 321 322 /** 323 * @param anElement 324 * The element for the query. 325 * @return Returns the overridingExtensions. 326 */ getOverridingExtensions(Object anElement, boolean triggerPoint)327 private NavigatorContentExtension[] getOverridingExtensions(Object anElement, 328 boolean triggerPoint) { 329 if (!descriptor.hasOverridingExtensions()) { 330 return NO_EXTENSIONS; 331 } 332 333 NavigatorContentDescriptor overridingDescriptor; 334 Set overridingExtensions = new LinkedHashSet(); 335 for (Iterator contentDescriptorsItr = descriptor.getOverriddingExtensions().iterator(); contentDescriptorsItr 336 .hasNext();) { 337 overridingDescriptor = (NavigatorContentDescriptor) contentDescriptorsItr.next(); 338 339 if (contentService.isActive(overridingDescriptor.getId()) 340 && contentService.isVisible(overridingDescriptor.getId()) 341 && (anElement == null || (triggerPoint ? overridingDescriptor 342 .isTriggerPoint(anElement) : overridingDescriptor 343 .isPossibleChild(anElement)))) { 344 overridingExtensions.add(contentService.getExtension(overridingDescriptor)); 345 } 346 } 347 if (overridingExtensions.isEmpty()) { 348 return NO_EXTENSIONS; 349 } 350 if (Policy.DEBUG_EXTENSION_SETUP) { 351 System.out 352 .println(this 353 + " overriding: " + //$NON-NLS-1$ 354 (triggerPoint ? "(trigger pt: " : "(poss child: ") + anElement + "): " + overridingExtensions); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ 355 } 356 return (NavigatorContentExtension[]) overridingExtensions 357 .toArray(new NavigatorContentExtension[overridingExtensions.size()]); 358 } 359 360 @Override toString()361 public String toString() { 362 return descriptor + " Instance"; //$NON-NLS-1$ 363 } 364 } 365