1 /*******************************************************************************
2  * Copyright (c) 2000, 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  *     Fair Isaac Corporation <Hemant.Singh@Gmail.com> - Bug 326695
14  *******************************************************************************/
15 package org.eclipse.ui.model;
16 
17 import org.eclipse.core.runtime.Adapters;
18 import org.eclipse.jface.resource.ColorDescriptor;
19 import org.eclipse.jface.resource.FontDescriptor;
20 import org.eclipse.jface.resource.ImageDescriptor;
21 import org.eclipse.jface.resource.JFaceResources;
22 import org.eclipse.jface.resource.LocalResourceManager;
23 import org.eclipse.jface.resource.ResourceManager;
24 import org.eclipse.jface.viewers.DecoratingLabelProvider;
25 import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
26 import org.eclipse.jface.viewers.IColorProvider;
27 import org.eclipse.jface.viewers.IFontProvider;
28 import org.eclipse.jface.viewers.ILabelProvider;
29 import org.eclipse.jface.viewers.LabelProvider;
30 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
31 import org.eclipse.jface.viewers.StyledCellLabelProvider;
32 import org.eclipse.jface.viewers.StyledString;
33 import org.eclipse.jface.viewers.StyledString.Styler;
34 import org.eclipse.swt.graphics.Color;
35 import org.eclipse.swt.graphics.Font;
36 import org.eclipse.swt.graphics.FontData;
37 import org.eclipse.swt.graphics.Image;
38 import org.eclipse.swt.graphics.RGB;
39 import org.eclipse.ui.IEditorRegistry;
40 import org.eclipse.ui.IPropertyListener;
41 import org.eclipse.ui.PlatformUI;
42 
43 /**
44  * Provides basic labels for adaptable objects that have the
45  * <code>IWorkbenchAdapter</code> adapter associated with them. All dispensed
46  * images are cached until the label provider is explicitly disposed. This class
47  * provides a facility for subclasses to define annotations on the labels and
48  * icons of adaptable objects.
49  */
50 public class WorkbenchLabelProvider extends LabelProvider
51 		implements IColorProvider, IFontProvider, IStyledLabelProvider {
52 
53 	/**
54 	 * Returns a workbench label provider that is hooked up to the decorator
55 	 * mechanism.
56 	 *
57 	 * @return a new <code>DecoratingLabelProvider</code> which wraps a new
58 	 *         <code>WorkbenchLabelProvider</code>
59 	 */
getDecoratingWorkbenchLabelProvider()60 	public static ILabelProvider getDecoratingWorkbenchLabelProvider() {
61 		return new DecoratingLabelProvider(new WorkbenchLabelProvider(),
62 				PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator());
63 	}
64 
65 	/**
66 	 * Listener that tracks changes to the editor registry and does a full update
67 	 * when it changes, since many workbench adapters derive their icon from the
68 	 * file associations in the registry.
69 	 */
70 	private IPropertyListener editorRegistryListener = (source, propId) -> {
71 		if (propId == IEditorRegistry.PROP_CONTENTS) {
72 			fireLabelProviderChanged(new LabelProviderChangedEvent(WorkbenchLabelProvider.this));
73 		}
74 	};
75 	private ResourceManager resourceManager;
76 
77 	/**
78 	 * Creates a new workbench label provider.
79 	 */
WorkbenchLabelProvider()80 	public WorkbenchLabelProvider() {
81 		PlatformUI.getWorkbench().getEditorRegistry().addPropertyListener(editorRegistryListener);
82 	}
83 
84 	/**
85 	 * Returns an image descriptor that is based on the given descriptor, but
86 	 * decorated with additional information relating to the state of the provided
87 	 * object.
88 	 *
89 	 * Subclasses may reimplement this method to decorate an object's image.
90 	 *
91 	 * @param input   The base image to decorate.
92 	 * @param element The element used to look up decorations.
93 	 * @return the resuling ImageDescriptor.
94 	 * @see org.eclipse.jface.resource.CompositeImageDescriptor
95 	 */
decorateImage(ImageDescriptor input, Object element)96 	protected ImageDescriptor decorateImage(ImageDescriptor input, Object element) {
97 		return input;
98 	}
99 
100 	/**
101 	 * Returns a label that is based on the given label, but decorated with
102 	 * additional information relating to the state of the provided object.
103 	 *
104 	 * Subclasses may implement this method to decorate an object's label.
105 	 *
106 	 * @param input   The base text to decorate.
107 	 * @param element The element used to look up decorations.
108 	 * @return the resulting text
109 	 */
decorateText(String input, Object element)110 	protected String decorateText(String input, Object element) {
111 		return input;
112 	}
113 
114 	@Override
dispose()115 	public void dispose() {
116 		PlatformUI.getWorkbench().getEditorRegistry().removePropertyListener(editorRegistryListener);
117 		if (resourceManager != null)
118 			resourceManager.dispose();
119 		resourceManager = null;
120 		super.dispose();
121 	}
122 
123 	/**
124 	 * Returns the implementation of IWorkbenchAdapter for the given object.
125 	 *
126 	 * @param o the object to look up.
127 	 * @return IWorkbenchAdapter or<code>null</code> if the adapter is not defined
128 	 *         or the object is not adaptable.
129 	 */
getAdapter(Object o)130 	protected final IWorkbenchAdapter getAdapter(Object o) {
131 		return Adapters.adapt(o, IWorkbenchAdapter.class);
132 	}
133 
134 	/**
135 	 * Returns the implementation of IWorkbenchAdapter2 for the given object.
136 	 *
137 	 * @param o the object to look up.
138 	 * @return IWorkbenchAdapter2 or<code>null</code> if the adapter is not defined
139 	 *         or the object is not adaptable.
140 	 */
getAdapter2(Object o)141 	protected final IWorkbenchAdapter2 getAdapter2(Object o) {
142 		return Adapters.adapt(o, IWorkbenchAdapter2.class);
143 	}
144 
145 	/**
146 	 * Returns the implementation of IWorkbenchAdapter3 for the given object.
147 	 *
148 	 * @param o the object to look up.
149 	 * @return IWorkbenchAdapter3 or<code>null</code> if the adapter is not defined
150 	 *         or the object is not adaptable.
151 	 * @since 3.7
152 	 */
getAdapter3(Object o)153 	protected final IWorkbenchAdapter3 getAdapter3(Object o) {
154 		return Adapters.adapt(o, IWorkbenchAdapter3.class);
155 	}
156 
157 	/**
158 	 * Lazy load the resource manager
159 	 *
160 	 * @return The resource manager, create one if necessary
161 	 */
getResourceManager()162 	private ResourceManager getResourceManager() {
163 		if (resourceManager == null) {
164 			resourceManager = new LocalResourceManager(JFaceResources.getResources());
165 		}
166 
167 		return resourceManager;
168 	}
169 
170 	@Override
getImage(Object element)171 	public final Image getImage(Object element) {
172 		// obtain the base image by querying the element
173 		IWorkbenchAdapter adapter = getAdapter(element);
174 		if (adapter == null) {
175 			return null;
176 		}
177 		ImageDescriptor descriptor = adapter.getImageDescriptor(element);
178 		if (descriptor == null) {
179 			return null;
180 		}
181 
182 		// add any annotations to the image descriptor
183 		descriptor = decorateImage(descriptor, element);
184 
185 		return (Image) getResourceManager().get(descriptor);
186 	}
187 
188 	/**
189 	 * The default implementation of this returns the styled text label for the
190 	 * given element.
191 	 *
192 	 * @param element the element to evaluate the styled string for
193 	 *
194 	 * @return the styled string.
195 	 *
196 	 * @since 3.7
197 	 */
198 	@Override
getStyledText(Object element)199 	public StyledString getStyledText(Object element) {
200 		IWorkbenchAdapter3 adapter = getAdapter3(element);
201 		if (adapter == null) {
202 			// If adapter class doesn't implement IWorkbenchAdapter3 than use
203 			// StyledString with text of element. Since the output of getText is
204 			// already decorated, so we don't need to call decorateText again
205 			// here.
206 			return new StyledString(getText(element));
207 		}
208 		StyledString styledString = adapter.getStyledText(element);
209 		// Now, re-use any existing decorateText implementation, to decorate
210 		// this styledString.
211 		String decorated = decorateText(styledString.getString(), element);
212 		Styler styler = getDecorationStyle(element);
213 		return StyledCellLabelProvider.styleDecoratedString(decorated, styler, styledString);
214 	}
215 
216 	/**
217 	 * Sets the {@link Styler} to be used for string decorations. By default the
218 	 * {@link StyledString#DECORATIONS_STYLER decoration style}. Clients can
219 	 * override.
220 	 *
221 	 * @param element the element that has been decorated
222 	 *
223 	 * @return return the decoration style
224 	 *
225 	 * @since 3.7
226 	 */
getDecorationStyle(Object element)227 	protected Styler getDecorationStyle(Object element) {
228 		return StyledString.DECORATIONS_STYLER;
229 	}
230 
231 	@Override
getText(Object element)232 	public final String getText(Object element) {
233 		// query the element for its label
234 		IWorkbenchAdapter adapter = getAdapter(element);
235 		if (adapter == null) {
236 			return ""; //$NON-NLS-1$
237 		}
238 		String label = adapter.getLabel(element);
239 
240 		// return the decorated label
241 		return decorateText(label, element);
242 	}
243 
244 	@Override
getForeground(Object element)245 	public Color getForeground(Object element) {
246 		return getColor(element, true);
247 	}
248 
249 	@Override
getBackground(Object element)250 	public Color getBackground(Object element) {
251 		return getColor(element, false);
252 	}
253 
254 	@Override
getFont(Object element)255 	public Font getFont(Object element) {
256 		IWorkbenchAdapter2 adapter = getAdapter2(element);
257 		if (adapter == null) {
258 			return null;
259 		}
260 
261 		FontData descriptor = adapter.getFont(element);
262 		if (descriptor == null) {
263 			return null;
264 		}
265 
266 		return (Font) getResourceManager().get(FontDescriptor.createFrom(descriptor));
267 	}
268 
getColor(Object element, boolean forground)269 	private Color getColor(Object element, boolean forground) {
270 		IWorkbenchAdapter2 adapter = getAdapter2(element);
271 		if (adapter == null) {
272 			return null;
273 		}
274 		RGB descriptor = forground ? adapter.getForeground(element) : adapter.getBackground(element);
275 		if (descriptor == null) {
276 			return null;
277 		}
278 
279 		return (Color) getResourceManager().get(ColorDescriptor.createFrom(descriptor));
280 	}
281 }
282