]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/ui/org/eclipse/jdt/ui/ProblemsLabelDecorator.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / ui / ProblemsLabelDecorator.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2012 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 *******************************************************************************/
11package org.eclipse.jdt.ui;
12
13import java.util.Iterator;
14
15import org.eclipse.swt.graphics.Image;
16import org.eclipse.swt.graphics.Point;
17import org.eclipse.swt.graphics.Rectangle;
18
19import org.eclipse.core.runtime.CoreException;
20import org.eclipse.core.runtime.IPath;
21import org.eclipse.core.runtime.ListenerList;
22
23import org.eclipse.core.resources.IFile;
24import org.eclipse.core.resources.IMarker;
25import org.eclipse.core.resources.IProject;
26import org.eclipse.core.resources.IResource;
27import org.eclipse.core.resources.IResourceStatus;
28
29import org.eclipse.jface.resource.ImageDescriptor;
30import org.eclipse.jface.viewers.IBaseLabelProvider;
31import org.eclipse.jface.viewers.IDecoration;
32import org.eclipse.jface.viewers.ILabelDecorator;
33import org.eclipse.jface.viewers.ILabelProviderListener;
34import org.eclipse.jface.viewers.ILightweightLabelDecorator;
35import org.eclipse.jface.viewers.LabelProviderChangedEvent;
36
37import org.eclipse.jface.text.Position;
38import org.eclipse.jface.text.source.Annotation;
39import org.eclipse.jface.text.source.IAnnotationModel;
40
41import org.eclipse.ui.part.FileEditorInput;
42
43import org.eclipse.ui.texteditor.MarkerAnnotation;
44
45import org.eclipse.jdt.core.IClasspathAttribute;
46import org.eclipse.jdt.core.IClasspathEntry;
47import org.eclipse.jdt.core.ICompilationUnit;
48import org.eclipse.jdt.core.IJavaElement;
49import org.eclipse.jdt.core.IJavaModelMarker;
50import org.eclipse.jdt.core.IJavaProject;
51import org.eclipse.jdt.core.IPackageFragment;
52import org.eclipse.jdt.core.IPackageFragmentRoot;
53import org.eclipse.jdt.core.ISourceRange;
54import org.eclipse.jdt.core.ISourceReference;
55import org.eclipse.jdt.core.JavaModelException;
56
57import org.eclipse.jdt.launching.JavaRuntime;
58
59import org.eclipse.jdt.internal.ui.JavaPlugin;
60import org.eclipse.jdt.internal.ui.JavaPluginImages;
61import org.eclipse.jdt.internal.ui.viewsupport.IProblemChangedListener;
62import org.eclipse.jdt.internal.ui.viewsupport.ImageDescriptorRegistry;
63import org.eclipse.jdt.internal.ui.viewsupport.ImageImageDescriptor;
64
65/**
66 * LabelDecorator that decorates an element's image with error and warning overlays that
67 * represent the severity of markers attached to the element's underlying resource. To see
68 * a problem decoration for a marker, the marker needs to be a subtype of <code>IMarker.PROBLEM</code>.
69 * <p>
70 * <b>Important</b>: Although this decorator implements ILightweightLabelDecorator, do not contribute this
71 * class as a decorator to the <code>org.eclipse.ui.decorators</code> extension. Only use this class in your
72 * own views and label providers.
73 *
74 * @since 2.0
75 */
76public class ProblemsLabelDecorator implements ILabelDecorator, ILightweightLabelDecorator {
77
78 /**
79 * This is a special <code>LabelProviderChangedEvent</code> carrying additional
80 * information whether the event origins from a maker change.
81 * <p>
82 * <code>ProblemsLabelChangedEvent</code>s are only generated by <code>
83 * ProblemsLabelDecorator</code>s.
84 * </p>
85 */
86 public static class ProblemsLabelChangedEvent extends LabelProviderChangedEvent {
87
88 private static final long serialVersionUID= 1L;
89
90 private boolean fMarkerChange;
91
92 /**
93 * @param eventSource the base label provider
94 * @param changedResource the changed resources
95 * @param isMarkerChange <code>true</code> if the change is a marker change; otherwise
96 * <code>false</code>
97 */
98 public ProblemsLabelChangedEvent(IBaseLabelProvider eventSource, IResource[] changedResource, boolean isMarkerChange) {
99 super(eventSource, changedResource);
100 fMarkerChange= isMarkerChange;
101 }
102
103 /**
104 * Returns whether this event origins from marker changes. If <code>false</code> an annotation
105 * model change is the origin. In this case viewers not displaying working copies can ignore these
106 * events.
107 *
108 * @return if this event origins from a marker change.
109 */
110 public boolean isMarkerChange() {
111 return fMarkerChange;
112 }
113
114 }
115
116 private static final int ERRORTICK_WARNING= JavaElementImageDescriptor.WARNING;
117 private static final int ERRORTICK_ERROR= JavaElementImageDescriptor.ERROR;
118 private static final int ERRORTICK_BUILDPATH_ERROR= JavaElementImageDescriptor.BUILDPATH_ERROR;
119 private static final int ERRORTICK_IGNORE_OPTIONAL_PROBLEMS= JavaElementImageDescriptor.IGNORE_OPTIONAL_PROBLEMS;
120
121 private ImageDescriptorRegistry fRegistry;
122 private boolean fUseNewRegistry= false;
123 private IProblemChangedListener fProblemChangedListener;
124
125 private ListenerList fListeners;
126 private ISourceRange fCachedRange;
127
128 /**
129 * Creates a new <code>ProblemsLabelDecorator</code>.
130 */
131 public ProblemsLabelDecorator() {
132 this(null);
133 fUseNewRegistry= true;
134 }
135
136 /**
137 * Note: This constructor is for internal use only. Clients should not call this constructor.
138 *
139 * @param registry The registry to use or <code>null</code> to use the Java plugin's image
140 * registry
141 * @noreference This constructor is not intended to be referenced by clients.
142 */
143 public ProblemsLabelDecorator(ImageDescriptorRegistry registry) {
144 fRegistry= registry;
145 fProblemChangedListener= null;
146 }
147
148 private ImageDescriptorRegistry getRegistry() {
149 if (fRegistry == null) {
150 fRegistry= fUseNewRegistry ? new ImageDescriptorRegistry() : JavaPlugin.getImageDescriptorRegistry();
151 }
152 return fRegistry;
153 }
154
155
156 /* (non-Javadoc)
157 * @see ILabelDecorator#decorateText(String, Object)
158 */
159 public String decorateText(String text, Object element) {
160 return text;
161 }
162
163 /* (non-Javadoc)
164 * @see ILabelDecorator#decorateImage(Image, Object)
165 */
166 public Image decorateImage(Image image, Object obj) {
167 if (image == null)
168 return null;
169
170 int adornmentFlags= computeAdornmentFlags(obj);
171 if (adornmentFlags != 0) {
172 ImageDescriptor baseImage= new ImageImageDescriptor(image);
173 Rectangle bounds= image.getBounds();
174 return getRegistry().get(new JavaElementImageDescriptor(baseImage, adornmentFlags, new Point(bounds.width, bounds.height)));
175 }
176 return image;
177 }
178
179 /**
180 * Computes the adornment flags for the given element.
181 *
182 * @param obj the element to compute the flags for
183 *
184 * @return the adornment flags
185 */
186 protected int computeAdornmentFlags(Object obj) {
187 try {
188 if (obj instanceof IJavaElement) {
189 IJavaElement element= (IJavaElement) obj;
190 int type= element.getElementType();
191 switch (type) {
192 case IJavaElement.JAVA_MODEL:
193 case IJavaElement.JAVA_PROJECT:
194 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
195 int flags= getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_INFINITE, null);
196 switch (type) {
197 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
198 IPackageFragmentRoot root= (IPackageFragmentRoot) element;
199 if (flags != ERRORTICK_ERROR && root.getKind() == IPackageFragmentRoot.K_SOURCE && isIgnoringOptionalProblems(root.getRawClasspathEntry())) {
200 flags= ERRORTICK_IGNORE_OPTIONAL_PROBLEMS;
201 }
202 break;
203 case IJavaElement.JAVA_PROJECT:
204 IJavaProject project= (IJavaProject) element;
205 if (flags != ERRORTICK_ERROR && flags != ERRORTICK_BUILDPATH_ERROR && isIgnoringOptionalProblems(project)) {
206 flags= ERRORTICK_IGNORE_OPTIONAL_PROBLEMS;
207 }
208 break;
209 }
210 return flags;
211 case IJavaElement.PACKAGE_FRAGMENT:
212 return getPackageErrorTicksFromMarkers((IPackageFragment) element);
213 case IJavaElement.COMPILATION_UNIT:
214 case IJavaElement.CLASS_FILE:
215 return getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_ONE, null);
216 case IJavaElement.PACKAGE_DECLARATION:
217 case IJavaElement.IMPORT_DECLARATION:
218 case IJavaElement.IMPORT_CONTAINER:
219 case IJavaElement.TYPE:
220 case IJavaElement.INITIALIZER:
221 case IJavaElement.METHOD:
222 case IJavaElement.FIELD:
223 case IJavaElement.LOCAL_VARIABLE:
224 ICompilationUnit cu= (ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT);
225 if (cu != null) {
226 ISourceReference ref= (type == IJavaElement.COMPILATION_UNIT) ? null : (ISourceReference) element;
227 // The assumption is that only source elements in compilation unit can have markers
228 IAnnotationModel model= isInJavaAnnotationModel(cu);
229 int result= 0;
230 if (model != null) {
231 // open in Java editor: look at annotation model
232 result= getErrorTicksFromAnnotationModel(model, ref);
233 } else {
234 result= getErrorTicksFromMarkers(cu.getResource(), IResource.DEPTH_ONE, ref);
235 }
236 fCachedRange= null;
237 return result;
238 }
239 break;
240 default:
241 }
242 } else if (obj instanceof IResource) {
243 return getErrorTicksFromMarkers((IResource) obj, IResource.DEPTH_INFINITE, null);
244 }
245 } catch (CoreException e) {
246 if (e instanceof JavaModelException) {
247 if (((JavaModelException) e).isDoesNotExist()) {
248 return 0;
249 }
250 }
251 if (e.getStatus().getCode() == IResourceStatus.MARKER_NOT_FOUND) {
252 return 0;
253 }
254
255 JavaPlugin.log(e);
256 }
257 return 0;
258 }
259
260 private boolean isIgnoringOptionalProblems(IClasspathEntry entry) {
261 if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
262 IClasspathAttribute[] extraAttributes= entry.getExtraAttributes();
263 for (int i= 0; i < extraAttributes.length; i++) {
264 IClasspathAttribute attrib= extraAttributes[i];
265 if (IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS.equals(attrib.getName())) {
266 return "true".equals(attrib.getValue()); //$NON-NLS-1$
267 }
268 }
269 }
270 return false;
271 }
272
273 private boolean isIgnoringOptionalProblems(IJavaProject project) throws JavaModelException {
274 IPath projectPath= project.getPath();
275 IClasspathEntry[] rawClasspath= project.getRawClasspath();
276 for (IClasspathEntry entry : rawClasspath) {
277 if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE && projectPath.equals(entry.getPath()) && isIgnoringOptionalProblems(entry))
278 return true;
279 }
280 return false;
281 }
282
283 private int getErrorTicksFromMarkers(IResource res, int depth, ISourceReference sourceElement) throws CoreException {
284 if (res == null || !res.isAccessible()) {
285 return 0;
286 }
287 int severity= 0;
288 if (sourceElement == null) {
289 if (res instanceof IProject) {
290 severity= res.findMaxProblemSeverity(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
291 if (severity == IMarker.SEVERITY_ERROR) {
292 return ERRORTICK_BUILDPATH_ERROR;
293 }
294 severity= res.findMaxProblemSeverity(JavaRuntime.JRE_CONTAINER_MARKER, true, IResource.DEPTH_ZERO);
295 if (severity == IMarker.SEVERITY_ERROR) {
296 return ERRORTICK_BUILDPATH_ERROR;
297 }
298 }
299 severity= res.findMaxProblemSeverity(IMarker.PROBLEM, true, depth);
300 } else {
301 IMarker[] markers= res.findMarkers(IMarker.PROBLEM, true, depth);
302 if (markers != null && markers.length > 0) {
303 for (int i= 0; i < markers.length && (severity != IMarker.SEVERITY_ERROR); i++) {
304 IMarker curr= markers[i];
305 if (isMarkerInRange(curr, sourceElement)) {
306 int val= curr.getAttribute(IMarker.SEVERITY, -1);
307 if (val == IMarker.SEVERITY_WARNING || val == IMarker.SEVERITY_ERROR) {
308 severity= val;
309 }
310 }
311 }
312 }
313 }
314 if (severity == IMarker.SEVERITY_ERROR) {
315 return ERRORTICK_ERROR;
316 } else if (severity == IMarker.SEVERITY_WARNING) {
317 return ERRORTICK_WARNING;
318 }
319 return 0;
320 }
321
322 private int getPackageErrorTicksFromMarkers(IPackageFragment pack) throws CoreException {
323 // Packages are special: They must not consider markers on subpackages.
324
325 IResource res= pack.getResource();
326 if (res == null || !res.isAccessible()) {
327 return 0;
328 }
329
330 // markers on package itself (e.g. missing @NonNullByDefault)
331 int severity= res.findMaxProblemSeverity(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
332 if (severity == IMarker.SEVERITY_ERROR)
333 return ERRORTICK_ERROR;
334
335 // markers on CUs
336 for (ICompilationUnit cu : pack.getCompilationUnits()) {
337 severity= Math.max(severity, cu.getResource().findMaxProblemSeverity(IMarker.PROBLEM, true, IResource.DEPTH_ZERO));
338 if (severity == IMarker.SEVERITY_ERROR)
339 return ERRORTICK_ERROR;
340 }
341
342 // markers on files and folders
343 for (Object object : pack.getNonJavaResources()) {
344 if (object instanceof IResource) {
345 IResource resource= (IResource) object;
346 severity= Math.max(severity, resource.findMaxProblemSeverity(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE));
347 if (severity == IMarker.SEVERITY_ERROR)
348 return ERRORTICK_ERROR;
349 }
350 }
351
352 // SEVERITY_ERROR already handled above
353 if (severity == IMarker.SEVERITY_WARNING) {
354 return ERRORTICK_WARNING;
355 }
356 return 0;
357 }
358
359 private boolean isMarkerInRange(IMarker marker, ISourceReference sourceElement) throws CoreException {
360 if (marker.isSubtypeOf(IMarker.TEXT)) {
361 int pos= marker.getAttribute(IMarker.CHAR_START, -1);
362 return isInside(pos, sourceElement);
363 }
364 return false;
365 }
366
367 private IAnnotationModel isInJavaAnnotationModel(ICompilationUnit original) {
368 if (original.isWorkingCopy()) {
369 FileEditorInput editorInput= new FileEditorInput((IFile) original.getResource());
370 return JavaPlugin.getDefault().getCompilationUnitDocumentProvider().getAnnotationModel(editorInput);
371 }
372 return null;
373 }
374
375
376 private int getErrorTicksFromAnnotationModel(IAnnotationModel model, ISourceReference sourceElement) throws CoreException {
377 int info= 0;
378 Iterator<Annotation> iter= model.getAnnotationIterator();
379 while ((info != ERRORTICK_ERROR) && iter.hasNext()) {
380 Annotation annot= iter.next();
381 IMarker marker= isAnnotationInRange(model, annot, sourceElement);
382 if (marker != null) {
383 int priority= marker.getAttribute(IMarker.SEVERITY, -1);
384 if (priority == IMarker.SEVERITY_WARNING) {
385 info= ERRORTICK_WARNING;
386 } else if (priority == IMarker.SEVERITY_ERROR) {
387 info= ERRORTICK_ERROR;
388 }
389 }
390 }
391 return info;
392 }
393
394 private IMarker isAnnotationInRange(IAnnotationModel model, Annotation annot, ISourceReference sourceElement) throws CoreException {
395 if (annot instanceof MarkerAnnotation) {
396 if (sourceElement == null || isInside(model.getPosition(annot), sourceElement)) {
397 IMarker marker= ((MarkerAnnotation) annot).getMarker();
398 if (marker.exists() && marker.isSubtypeOf(IMarker.PROBLEM)) {
399 return marker;
400 }
401 }
402 }
403 return null;
404 }
405
406 private boolean isInside(Position pos, ISourceReference sourceElement) throws CoreException {
407 return pos != null && isInside(pos.getOffset(), sourceElement);
408 }
409
410 /**
411 * Tests if a position is inside the source range of an element.
412 * @param pos Position to be tested.
413 * @param sourceElement Source element (must be a IJavaElement)
414 * @return boolean Return <code>true</code> if position is located inside the source element.
415 * @throws CoreException Exception thrown if element range could not be accessed.
416 *
417 * @since 2.1
418 */
419 protected boolean isInside(int pos, ISourceReference sourceElement) throws CoreException {
420 if (fCachedRange == null) {
421 fCachedRange= sourceElement.getSourceRange();
422 }
423 ISourceRange range= fCachedRange;
424 if (range != null) {
425 int rangeOffset= range.getOffset();
426 return (rangeOffset <= pos && rangeOffset + range.getLength() > pos);
427 }
428 return false;
429 }
430
431 /* (non-Javadoc)
432 * @see IBaseLabelProvider#dispose()
433 */
434 public void dispose() {
435 if (fProblemChangedListener != null) {
436 JavaPlugin.getDefault().getProblemMarkerManager().removeListener(fProblemChangedListener);
437 fProblemChangedListener= null;
438 }
439 if (fRegistry != null && fUseNewRegistry) {
440 fRegistry.dispose();
441 }
442 }
443
444 /* (non-Javadoc)
445 * @see IBaseLabelProvider#isLabelProperty(Object, String)
446 */
447 public boolean isLabelProperty(Object element, String property) {
448 return true;
449 }
450
451 /* (non-Javadoc)
452 * @see IBaseLabelProvider#addListener(ILabelProviderListener)
453 */
454 public void addListener(ILabelProviderListener listener) {
455 if (fListeners == null) {
456 fListeners= new ListenerList();
457 }
458 fListeners.add(listener);
459 if (fProblemChangedListener == null) {
460 fProblemChangedListener= new IProblemChangedListener() {
461 public void problemsChanged(IResource[] changedResources, boolean isMarkerChange) {
462 fireProblemsChanged(changedResources, isMarkerChange);
463 }
464 };
465 JavaPlugin.getDefault().getProblemMarkerManager().addListener(fProblemChangedListener);
466 }
467 }
468
469 /* (non-Javadoc)
470 * @see IBaseLabelProvider#removeListener(ILabelProviderListener)
471 */
472 public void removeListener(ILabelProviderListener listener) {
473 if (fListeners != null) {
474 fListeners.remove(listener);
475 if (fListeners.isEmpty() && fProblemChangedListener != null) {
476 JavaPlugin.getDefault().getProblemMarkerManager().removeListener(fProblemChangedListener);
477 fProblemChangedListener= null;
478 }
479 }
480 }
481
482 private void fireProblemsChanged(IResource[] changedResources, boolean isMarkerChange) {
483 if (fListeners != null && !fListeners.isEmpty()) {
484 LabelProviderChangedEvent event= new ProblemsLabelChangedEvent(this, changedResources, isMarkerChange);
485 Object[] listeners= fListeners.getListeners();
486 for (int i= 0; i < listeners.length; i++) {
487 ((ILabelProviderListener) listeners[i]).labelProviderChanged(event);
488 }
489 }
490 }
491
492 /* (non-Javadoc)
493 * @see org.eclipse.jface.viewers.ILightweightLabelDecorator#decorate(java.lang.Object, org.eclipse.jface.viewers.IDecoration)
494 */
495 public void decorate(Object element, IDecoration decoration) {
496 int adornmentFlags= computeAdornmentFlags(element);
497 if (adornmentFlags == ERRORTICK_ERROR) {
498 decoration.addOverlay(JavaPluginImages.DESC_OVR_ERROR);
499 } else if (adornmentFlags == ERRORTICK_BUILDPATH_ERROR) {
500 decoration.addOverlay(JavaPluginImages.DESC_OVR_BUILDPATH_ERROR);
501 } else if (adornmentFlags == ERRORTICK_WARNING) {
502 decoration.addOverlay(JavaPluginImages.DESC_OVR_WARNING);
503 }
504 }
505
506}