/******************************************************************************* * Copyright (c) 2003, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Fair Issac Corp - bug 287103 - NCSLabelProvider does not properly handle overrides *******************************************************************************/ package org.eclipse.ui.internal.navigator; import java.util.Collection; import java.util.Iterator; import org.eclipse.core.commands.common.EventManager; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.jface.viewers.IFontProvider; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreePathLabelProvider; import org.eclipse.jface.viewers.LabelProviderChangedEvent; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.ViewerLabel; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension; import org.eclipse.ui.navigator.CommonViewer; import org.eclipse.ui.navigator.ICommonLabelProvider; import org.eclipse.ui.navigator.INavigatorContentService; /** * <p> * Provides relevant labels based on the associated * {@link INavigatorContentService}for the contents of a * TreeViewer . * <p> * * <p> * Except for the dependency on * {@link INavigatorContentService}, this class has no * dependencies on the rest of the Common Navigator framework. Tree viewers that would like to use * the extensions defined by the Common Navigator, without using the actual view part or other * pieces of functionality (filters, sorting, etc) may choose to use this class, in effect using an * extensible label provider. * </p> * <p> * * @since 3.2 * * @see org.eclipse.ui.internal.navigator.NavigatorContentService * @see org.eclipse.ui.internal.navigator.NavigatorContentServiceContentProvider */ public class NavigatorContentServiceLabelProvider extends EventManager implements ILabelProvider, IColorProvider, IFontProvider, ITreePathLabelProvider, ITableLabelProvider, ILabelProviderListener, IStyledLabelProvider { private final NavigatorContentService contentService; private final boolean isContentServiceSelfManaged; private final ReusableViewerLabel reusableLabel = new ReusableViewerLabel(); /** * <p> * Uses the supplied content service to acquire the available extensions. * </p> * * @param aContentService * The associated NavigatorContentService that should be used to acquire information. */ public NavigatorContentServiceLabelProvider(NavigatorContentService aContentService) { contentService = aContentService; isContentServiceSelfManaged = false; } /** * <p> * Return the appropriate image for anElement. The image will be used as the icon for anElement * when displayed in the tree viewer. This method uses information from its contentService to * know what extensions to use to supply the correct label. * </p> * {@inheritDoc} * * @param anElement * An element from the Tree Viewer * @return The Image that will be used as the icon when anElement is displayed in the viewer. * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object) */ @Override public Image getImage(Object anElement) { return getColumnImage(anElement, -1); } @Override public Image getColumnImage(Object element, int columnIndex) { Collection contentExtensions = contentService.findPossibleLabelExtensions(element); Image image = null; for (Iterator itr = contentExtensions.iterator(); itr.hasNext() && image == null; ) { image = findImage((NavigatorContentExtension) itr.next(), element, columnIndex); } return image; } /** * <p> * Return a String representation of anElement to be used as the display name in the tree * viewer. * </p> * * @param anElement * An element from the Tree Viewer * @return The String label to display for the object when represented in the viewer. * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object) */ @Override public String getText(Object anElement) { return getColumnText(anElement, -1); } @Override public String getColumnText(Object anElement, int aColumn) { ILabelProvider[] labelProviders = contentService.findRelevantLabelProviders(anElement); if (labelProviders.length == 0) return NLS.bind(CommonNavigatorMessages.NavigatorContentServiceLabelProvider_Error_no_label_provider_for_0_, makeSmallString(anElement)); String text = null; for (ILabelProvider labelProvider : labelProviders) { if (labelProvider instanceof ITableLabelProvider && aColumn != -1) text = ((ITableLabelProvider)labelProvider).getColumnText(anElement, aColumn); else text = labelProvider.getText(anElement); if (text != null && text.length() > 0) return text; } return text; } @Override public StyledString getStyledText(Object anElement) { Collection extensions = contentService.findPossibleLabelExtensions(anElement); if (extensions.size() == 0) return new StyledString(NLS.bind(CommonNavigatorMessages.NavigatorContentServiceLabelProvider_Error_no_label_provider_for_0_, makeSmallString(anElement))); StyledString text = null; for (Iterator itr = extensions.iterator(); itr.hasNext() && text == null; ) { text = findStyledText((NavigatorContentExtension) itr.next(), anElement); } return text != null ? text : new StyledString(); } /** * Search for a styled text label and take overrides into account. * Uses only simple ITreeContentProvider.getParent() style semantics. * * @returns the styled text or <code>null</code> if no extension has been found that provides a label */ private StyledString findStyledText(NavigatorContentExtension foundExtension, Object anElement) { ICommonLabelProvider labelProvider= foundExtension.getLabelProvider(); if (labelProvider instanceof IStyledLabelProvider) { StyledString styledText= ((IStyledLabelProvider) labelProvider).getStyledText(anElement); // paranoia check for null, although null is not a valid return value for IStyledLabelProvider.getStyledText if (styledText != null && styledText.length() > 0) { return styledText; } } else { String text= labelProvider.getText(anElement); if (text != null && text.length() > 0) { return new StyledString(text); } } return null; } private String makeSmallString(Object obj) { if (obj == null) return "null"; //$NON-NLS-1$ String str = obj.toString(); int len = str.length(); return str.substring(0, len < 50 ? len : 49); } /** * Search for image and take overrides into account. * Uses only simple ITreeContentProvider.getParent() style semantics. */ private Image findImage(NavigatorContentExtension foundExtension, Object anElement, int aColumn) { Image image = null; ICommonLabelProvider provider = foundExtension.getLabelProvider(); if (provider instanceof ITableLabelProvider && aColumn >= 0) image = ((ITableLabelProvider)provider).getColumnImage(anElement, aColumn); else image = provider.getImage(anElement); return image; } @Override public Font getFont(Object anElement) { ILabelProvider[] labelProviders = contentService.findRelevantLabelProviders(anElement); for (ILabelProvider provider : labelProviders) { if (provider instanceof IFontProvider) { IFontProvider fontProvider = (IFontProvider) provider; Font font = fontProvider.getFont(anElement); if (font != null) { return font; } } } return null; } @Override public Color getForeground(Object anElement) { ILabelProvider[] labelProviders = contentService.findRelevantLabelProviders(anElement); for (ILabelProvider provider : labelProviders) { if (provider instanceof IColorProvider) { IColorProvider colorProvider = (IColorProvider) provider; Color color = colorProvider.getForeground(anElement); if (color != null) { return color; } } } return null; } @Override public Color getBackground(Object anElement) { ILabelProvider[] labelProviders = contentService.findRelevantLabelProviders(anElement); for (ILabelProvider provider : labelProviders) { if (provider instanceof IColorProvider) { IColorProvider colorProvider = (IColorProvider) provider; Color color = colorProvider.getBackground(anElement); if (color != null) { return color; } } } return null; } /** * <p> * Indicates whether anElelement has aProperty that affects the display of the label. * </p> * {@inheritDoc} * * @param anElement * An element from the Tree Viewer * @param aProperty * A property of the given element that could be a label provider * @return True if any of the extensions enabled on anElement consider aProperty a * label-changing property. * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, * java.lang.String) */ @Override public boolean isLabelProperty(Object anElement, String aProperty) { boolean result = false; ILabelProvider[] labelProviders = contentService.findRelevantLabelProviders(anElement); for (int i = 0; i < labelProviders.length && !result; i++) { result = labelProviders[i].isLabelProperty(anElement, aProperty); } return result; } /** * <p> * Label provider listeners are currently supported. * </p> * * {@inheritDoc} * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) */ @Override public void addListener(ILabelProviderListener aListener) { addListenerObject(aListener); } /** * <p> * Label provider listeners are currently supported. * </p> * * {@inheritDoc} * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) */ @Override public void removeListener(ILabelProviderListener aListener) { removeListenerObject(aListener); } /** * <p> * Dispose of the content service, if it was created and not supplied. * </p> * <p> * <b>If a client uses this class outside of the framework of {@link CommonViewer}, this method * must be called when finished. </b> * </p> * * {@inheritDoc} * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() */ @Override public void dispose() { if (isContentServiceSelfManaged) { contentService.dispose(); } } /** * Fires a label provider changed event to all registered listeners * Only listeners registered at the time this method is called are notified. * * @param event a label provider changed event * * @see ILabelProviderListener#labelProviderChanged */ protected void fireLabelProviderChanged( final LabelProviderChangedEvent event) { for (Object listener : getListeners()) { final ILabelProviderListener labelProviderListener = (ILabelProviderListener) listener; SafeRunner.run(new SafeRunnable() { @Override public void run() { labelProviderListener.labelProviderChanged(event); } }); } } @Override public void updateLabel(ViewerLabel label, TreePath elementPath) { Collection contentExtensions = contentService.findPossibleLabelExtensions(elementPath.getLastSegment()); reusableLabel.reset(label); for (Iterator itr = contentExtensions.iterator(); itr.hasNext() && !(reusableLabel.isValid() && reusableLabel.hasChanged()); ) { findUpdateLabel((NavigatorContentExtension)itr.next(), reusableLabel, elementPath); } reusableLabel.fill(label); } /** * Search for text label and take overrides into account. * Uses only simple ITreeContentProvider.getParent() style semantics. */ private void findUpdateLabel(NavigatorContentExtension foundExtension, ReusableViewerLabel label, TreePath elementPath) { ILabelProvider labelProvider = foundExtension.getLabelProvider(); if (labelProvider instanceof ITreePathLabelProvider) { ITreePathLabelProvider tplp = (ITreePathLabelProvider) labelProvider; tplp.updateLabel(label, elementPath); } else { label.setImage(labelProvider.getImage(elementPath.getLastSegment())); label.setText(labelProvider.getText(elementPath.getLastSegment())); } } @Override public void labelProviderChanged(LabelProviderChangedEvent event) { fireLabelProviderChanged(event); } }