001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.navigator;
011:
012: import java.util.Iterator;
013: import java.util.Set;
014:
015: import org.eclipse.core.commands.common.EventManager;
016: import org.eclipse.core.runtime.SafeRunner;
017: import org.eclipse.jface.util.SafeRunnable;
018: import org.eclipse.jface.viewers.IColorProvider;
019: import org.eclipse.jface.viewers.IFontProvider;
020: import org.eclipse.jface.viewers.ILabelProvider;
021: import org.eclipse.jface.viewers.ILabelProviderListener;
022: import org.eclipse.jface.viewers.ITreePathLabelProvider;
023: import org.eclipse.jface.viewers.LabelProviderChangedEvent;
024: import org.eclipse.jface.viewers.TreePath;
025: import org.eclipse.jface.viewers.ViewerLabel;
026: import org.eclipse.osgi.util.NLS;
027: import org.eclipse.swt.graphics.Color;
028: import org.eclipse.swt.graphics.Font;
029: import org.eclipse.swt.graphics.Image;
030: import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension;
031: import org.eclipse.ui.navigator.CommonViewer;
032: import org.eclipse.ui.navigator.INavigatorContentDescriptor;
033: import org.eclipse.ui.navigator.INavigatorContentService;
034:
035: /**
036: * <p>
037: * Provides relevant labels based on the associated
038: * {@link INavigatorContentService}for the contents of a
039: * TreeViewer .
040: * <p>
041: *
042: * <p>
043: * Except for the dependency on
044: * {@link INavigatorContentService}, this class has no
045: * dependencies on the rest of the Common Navigator framework. Tree viewers that would like to use
046: * the extensions defined by the Common Navigator, without using the actual view part or other
047: * pieces of functionality (filters, sorting, etc) may choose to use this class, in effect using an
048: * extensible label provider.
049: * </p>
050: * <p>
051: * <strong>EXPERIMENTAL</strong>. This class or interface has been added as part of a work in
052: * progress. There is a guarantee neither that this API will work nor that it will remain the same.
053: * Please do not use this API without consulting with the Platform/UI team.
054: * </p>
055: *
056: * @since 3.2
057: *
058: * @see org.eclipse.ui.internal.navigator.NavigatorContentService
059: * @see org.eclipse.ui.internal.navigator.NavigatorContentServiceContentProvider
060: */
061: public class NavigatorContentServiceLabelProvider extends EventManager
062: implements ILabelProvider, IColorProvider, IFontProvider,
063: ITreePathLabelProvider, ILabelProviderListener {
064:
065: private final NavigatorContentService contentService;
066: private final boolean isContentServiceSelfManaged;
067: private final ReusableViewerLabel reusableLabel = new ReusableViewerLabel();
068:
069: /**
070: * <p>
071: * Uses the supplied content service to acquire the available extensions.
072: * </p>
073: *
074: * @param aContentService
075: * The associated NavigatorContentService that should be used to acquire information.
076: */
077: public NavigatorContentServiceLabelProvider(
078: NavigatorContentService aContentService) {
079: contentService = aContentService;
080: isContentServiceSelfManaged = false;
081: }
082:
083: /**
084: * <p>
085: * Return the appropriate image for anElement. The image will be used as the icon for anElement
086: * when displayed in the tree viewer. This method uses information from its contentService to
087: * know what extensions to use to supply the correct label.
088: * </p>
089: * {@inheritDoc}
090: *
091: * @param anElement
092: * An element from the Tree Viewer
093: * @return The Image that will be used as the icon when anElement is displayed in the viewer.
094: * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
095: */
096: public Image getImage(Object anElement) {
097:
098: Set contentExtensions = contentService
099: .findContentExtensionsWithPossibleChild(anElement);
100: Image image = null;
101: for (Iterator itr = contentExtensions.iterator(); itr.hasNext()
102: && image == null;) {
103: image = findImage((NavigatorContentExtension) itr.next(),
104: anElement);
105: }
106: return image;
107: }
108:
109: /**
110: * <p>
111: * Return a String representation of anElement to be used as the display name in the tree
112: * viewer.
113: * </p>
114: * {@inheritDoc}
115: *
116: * @param anElement
117: * An element from the Tree Viewer
118: * @return The String label to display for the object when represented in the viewer.
119: * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
120: */
121: public String getText(Object anElement) {
122: Set contentExtensions = contentService
123: .findContentExtensionsWithPossibleChild(anElement);
124: String text = null;
125: for (Iterator itr = contentExtensions.iterator(); itr.hasNext()
126: && text == null;) {
127: text = findText((NavigatorContentExtension) itr.next(),
128: anElement);
129: }
130: // decorate the element
131: return text == null ? (NLS
132: .bind(
133: CommonNavigatorMessages.NavigatorContentServiceLabelProvider_Error_no_label_provider_for_0_,
134: anElement))
135: : text;
136: }
137:
138: /**
139: * Search for text label and take overrides into account.
140: * Uses only simple ITreeContentProvider.getParent() style semantics.
141: */
142: private String findText(NavigatorContentExtension foundExtension,
143: Object anElement) {
144: String text = null;
145: INavigatorContentDescriptor foundDescriptor;
146: text = foundExtension.getLabelProvider().getText(anElement);
147: if (text == null
148: && (foundDescriptor = foundExtension.getDescriptor())
149: .getOverriddenDescriptor() != null) {
150: return findText(contentService.getExtension(foundDescriptor
151: .getOverriddenDescriptor()), anElement);
152: }
153: return text;
154: }
155:
156: /**
157: * Search for image and take overrides into account.
158: * Uses only simple ITreeContentProvider.getParent() style semantics.
159: */
160: private Image findImage(NavigatorContentExtension foundExtension,
161: Object anElement) {
162: Image image = null;
163: INavigatorContentDescriptor foundDescriptor;
164: image = foundExtension.getLabelProvider().getImage(anElement);
165: if (image == null
166: && (foundDescriptor = foundExtension.getDescriptor())
167: .getOverriddenDescriptor() != null) {
168: return findImage(contentService
169: .getExtension(foundDescriptor
170: .getOverriddenDescriptor()), anElement);
171: }
172: return image;
173: }
174:
175: /* (non-Javadoc)
176: * @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
177: */
178: public Font getFont(Object anElement) {
179: ILabelProvider[] labelProviders = contentService
180: .findRelevantLabelProviders(anElement);
181: for (int i = 0; i < labelProviders.length; i++) {
182: ILabelProvider provider = labelProviders[i];
183: if (provider instanceof IFontProvider) {
184: IFontProvider fontProvider = (IFontProvider) provider;
185: Font font = fontProvider.getFont(anElement);
186: if (font != null) {
187: return font;
188: }
189: }
190: }
191: return null;
192: }
193:
194: /* (non-Javadoc)
195: * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
196: */
197: public Color getForeground(Object anElement) {
198: ILabelProvider[] labelProviders = contentService
199: .findRelevantLabelProviders(anElement);
200: for (int i = 0; i < labelProviders.length; i++) {
201: ILabelProvider provider = labelProviders[i];
202: if (provider instanceof IColorProvider) {
203: IColorProvider colorProvider = (IColorProvider) provider;
204: Color color = colorProvider.getForeground(anElement);
205: if (color != null) {
206: return color;
207: }
208: }
209: }
210: return null;
211: }
212:
213: /* (non-Javadoc)
214: * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
215: */
216: public Color getBackground(Object anElement) {
217: ILabelProvider[] labelProviders = contentService
218: .findRelevantLabelProviders(anElement);
219: for (int i = 0; i < labelProviders.length; i++) {
220: ILabelProvider provider = labelProviders[i];
221: if (provider instanceof IColorProvider) {
222: IColorProvider colorProvider = (IColorProvider) provider;
223: Color color = colorProvider.getBackground(anElement);
224: if (color != null) {
225: return color;
226: }
227: }
228: }
229: return null;
230: }
231:
232: /**
233: * <p>
234: * Indicates whether anElelement has aProperty that affects the display of the label.
235: * </p>
236: * {@inheritDoc}
237: *
238: * @param anElement
239: * An element from the Tree Viewer
240: * @param aProperty
241: * A property of the given element that could be a label provider
242: * @return True if any of the extensions enabled on anElement consider aProperty a
243: * label-changing property.
244: * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
245: * java.lang.String)
246: */
247: public boolean isLabelProperty(Object anElement, String aProperty) {
248: boolean result = false;
249: ILabelProvider[] labelProviders = contentService
250: .findRelevantLabelProviders(anElement);
251: for (int i = 0; i < labelProviders.length && !result; i++) {
252: result = labelProviders[i].isLabelProperty(anElement,
253: aProperty);
254: }
255: return result;
256: }
257:
258: /**
259: * <p>
260: * Label provider listeners are currently supported.
261: * </p>
262: *
263: * {@inheritDoc}
264: * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
265: */
266: public void addListener(ILabelProviderListener aListener) {
267: addListenerObject(aListener);
268: }
269:
270: /**
271: * <p>
272: * Label provider listeners are currently supported.
273: * </p>
274: *
275: * {@inheritDoc}
276: * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
277: */
278: public void removeListener(ILabelProviderListener aListener) {
279: removeListenerObject(aListener);
280: }
281:
282: /**
283: * <p>
284: * Dispose of the content service, if it was created and not supplied.
285: * </p>
286: * <p>
287: * <b>If a client uses this class outside of the framework of {@link CommonViewer}, this method
288: * must be called when finished. </b>
289: * </p>
290: *
291: * {@inheritDoc}
292: * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
293: */
294: public void dispose() {
295: if (isContentServiceSelfManaged) {
296: contentService.dispose();
297: }
298:
299: }
300:
301: /**
302: * Fires a label provider changed event to all registered listeners
303: * Only listeners registered at the time this method is called are notified.
304: *
305: * @param event a label provider changed event
306: *
307: * @see ILabelProviderListener#labelProviderChanged
308: */
309: protected void fireLabelProviderChanged(
310: final LabelProviderChangedEvent event) {
311: Object[] theListeners = getListeners();
312: for (int i = 0; i < theListeners.length; ++i) {
313: final ILabelProviderListener l = (ILabelProviderListener) theListeners[i];
314: SafeRunner.run(new SafeRunnable() {
315: public void run() {
316: l.labelProviderChanged(event);
317: }
318: });
319:
320: }
321: }
322:
323: /* (non-Javadoc)
324: * @see org.eclipse.jface.viewers.ITreePathLabelProvider#updateLabel(org.eclipse.jface.viewers.ViewerLabel, org.eclipse.jface.viewers.TreePath)
325: */
326: public void updateLabel(ViewerLabel label, TreePath elementPath) {
327:
328: Set contentExtensions = contentService
329: .findContentExtensionsWithPossibleChild(elementPath
330: .getLastSegment());
331: reusableLabel.reset(label);
332: for (Iterator itr = contentExtensions.iterator(); itr.hasNext()
333: && !(reusableLabel.isValid() && reusableLabel
334: .hasChanged());) {
335: findUpdateLabel((NavigatorContentExtension) itr.next(),
336: reusableLabel, elementPath);
337: }
338: reusableLabel.fill(label);
339: }
340:
341: /**
342: * Search for text label and take overrides into account.
343: * Uses only simple ITreeContentProvider.getParent() style semantics.
344: */
345: private void findUpdateLabel(
346: NavigatorContentExtension foundExtension,
347: ReusableViewerLabel label, TreePath elementPath) {
348:
349: ILabelProvider labelProvider = foundExtension
350: .getLabelProvider();
351: if (labelProvider instanceof ITreePathLabelProvider) {
352: ITreePathLabelProvider tplp = (ITreePathLabelProvider) labelProvider;
353: tplp.updateLabel(label, elementPath);
354: } else {
355: label.setImage(labelProvider.getImage(elementPath
356: .getLastSegment()));
357: label.setText(labelProvider.getText(elementPath
358: .getLastSegment()));
359: }
360:
361: if (shouldContinue(label, foundExtension)) {
362: findUpdateLabel(contentService.getExtension(foundExtension
363: .getDescriptor().getOverriddenDescriptor()), label,
364: elementPath);
365: }
366: }
367:
368: private boolean shouldContinue(ReusableViewerLabel label,
369: NavigatorContentExtension foundExtension) {
370:
371: if (foundExtension.getDescriptor().getOverriddenDescriptor() != null) {
372: return !(label.isValid() && label.hasChanged());
373: }
374: return false;
375: }
376:
377: /* (non-Javadoc)
378: * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
379: */
380: public void labelProviderChanged(LabelProviderChangedEvent event) {
381: fireLabelProviderChanged(event);
382: }
383:
384: }
|