1) Added missing strings for italic, underline and strike through.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / ui / ProblemsLabelDecorator.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.ui;
12
13 import java.util.Iterator;
14
15 import net.sourceforge.phpdt.core.ICompilationUnit;
16 import net.sourceforge.phpdt.core.IJavaElement;
17 import net.sourceforge.phpdt.core.ISourceRange;
18 import net.sourceforge.phpdt.core.ISourceReference;
19 import net.sourceforge.phpdt.core.JavaModelException;
20 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
21 import net.sourceforge.phpdt.internal.ui.viewsupport.IProblemChangedListener;
22 import net.sourceforge.phpdt.internal.ui.viewsupport.ImageDescriptorRegistry;
23 import net.sourceforge.phpdt.internal.ui.viewsupport.ImageImageDescriptor;
24 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
25
26 import org.eclipse.core.resources.IFile;
27 import org.eclipse.core.resources.IMarker;
28 import org.eclipse.core.resources.IResource;
29 import org.eclipse.core.runtime.CoreException;
30 import org.eclipse.jface.resource.ImageDescriptor;
31 import org.eclipse.jface.text.Position;
32 import org.eclipse.jface.text.source.Annotation;
33 import org.eclipse.jface.text.source.IAnnotationModel;
34 //incastrix
35 //import org.eclipse.jface.util.ListenerList;
36 import org.eclipse.core.runtime.ListenerList;
37 import org.eclipse.jface.viewers.IBaseLabelProvider;
38 import org.eclipse.jface.viewers.IDecoration;
39 import org.eclipse.jface.viewers.ILabelDecorator;
40 import org.eclipse.jface.viewers.ILabelProviderListener;
41 import org.eclipse.jface.viewers.ILightweightLabelDecorator;
42 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
43 import org.eclipse.swt.graphics.Image;
44 import org.eclipse.swt.graphics.Point;
45 import org.eclipse.swt.graphics.Rectangle;
46 import org.eclipse.ui.part.FileEditorInput;
47 import org.eclipse.ui.texteditor.MarkerAnnotation;
48
49 /**
50  * LabelDecorator that decorates an element's image with error and warning
51  * overlays that represent the severity of markers attached to the element's
52  * underlying resource. To see a problem decoration for a marker, the marker
53  * needs to be a subtype of <code>IMarker.PROBLEM</code>.
54  * <p>
55  * Note: Only images for elements in Java projects are currently updated on
56  * marker changes.
57  * </p>
58  * 
59  * @since 2.0
60  */
61 public class ProblemsLabelDecorator implements ILabelDecorator,
62                 ILightweightLabelDecorator {
63
64         /**
65          * This is a special <code>LabelProviderChangedEvent</code> carring
66          * additional information whether the event orgins from a maker change.
67          * <p>
68          * <code>ProblemsLabelChangedEvent</code>s are only generated by <code>
69          * ProblemsLabelDecorator</code>s.
70          * </p>
71          */
72         public static class ProblemsLabelChangedEvent extends
73                         LabelProviderChangedEvent {
74
75                 /**
76                  * 
77                  */
78                 private static final long serialVersionUID = -7557704732816971319L;
79                 private boolean fMarkerChange;
80
81                 /**
82                  * Note: This constructor is for internal use only. Clients should not
83                  * call this constructor.
84                  */
85                 public ProblemsLabelChangedEvent(IBaseLabelProvider source,
86                                 IResource[] changedResource, boolean isMarkerChange) {
87                         super(source, changedResource);
88                         fMarkerChange = isMarkerChange;
89                 }
90
91                 /**
92                  * Returns whether this event origins from marker changes. If
93                  * <code>false</code> an annotation model change is the origin. In
94                  * this case viewers not displaying working copies can ignore these
95                  * events.
96                  * 
97                  * @return if this event origins from a marker change.
98                  */
99                 public boolean isMarkerChange() {
100                         return fMarkerChange;
101                 }
102
103         }
104
105         private static final int ERRORTICK_WARNING = JavaElementImageDescriptor.WARNING;
106
107         private static final int ERRORTICK_ERROR = JavaElementImageDescriptor.ERROR;
108
109         private ImageDescriptorRegistry fRegistry;
110
111         private boolean fUseNewRegistry = false;
112
113         private IProblemChangedListener fProblemChangedListener;
114
115         private ListenerList fListeners;
116
117         /**
118          * Creates a new <code>ProblemsLabelDecorator</code>.
119          */
120 //      public ProblemsLabelDecorator() {
121 //              this(null);
122 //              fUseNewRegistry = true;
123 //      }
124
125         /*
126          * Creates decorator with a shared image registry.
127          * 
128          * @param registry The registry to use or <code>null</code> to use the
129          * Java plugin's image registry.
130          */
131         /**
132          * Note: This constructor is for internal use only. Clients should not call
133          * this constructor.
134          */
135         public ProblemsLabelDecorator(ImageDescriptorRegistry registry) {
136                 fRegistry = registry;
137                 fProblemChangedListener = null;
138         }
139
140         private ImageDescriptorRegistry getRegistry() {
141                 if (fRegistry == null) {
142                         fRegistry = fUseNewRegistry ? new ImageDescriptorRegistry()
143                                         : PHPeclipsePlugin.getImageDescriptorRegistry();
144                 }
145                 return fRegistry;
146         }
147
148         /*
149          * (non-Javadoc)
150          * 
151          * @see ILabelDecorator#decorateText(String, Object)
152          */
153         public String decorateText(String text, Object element) {
154                 return text;
155         }
156
157         /*
158          * (non-Javadoc)
159          * 
160          * @see ILabelDecorator#decorateImage(Image, Object)
161          */
162         public Image decorateImage(Image image, Object obj) {
163                 int adornmentFlags = computeAdornmentFlags(obj);
164                 if (adornmentFlags != 0) {
165                         ImageDescriptor baseImage = new ImageImageDescriptor(image);
166                         Rectangle bounds = image.getBounds();
167                         return getRegistry().get(
168                                         new JavaElementImageDescriptor(baseImage, adornmentFlags,
169                                                         new Point(bounds.width, bounds.height)));
170                 }
171                 return image;
172         }
173
174         /**
175          * Note: This method is for internal use only. Clients should not call this
176          * method.
177          */
178         protected int computeAdornmentFlags(Object obj) {
179                 try {
180                         if (obj instanceof IJavaElement) {
181                                 IJavaElement element = (IJavaElement) obj;
182                                 int type = element.getElementType();
183                                 switch (type) {
184                                 case IJavaElement.JAVA_PROJECT:
185                                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
186                                         return getErrorTicksFromMarkers(element.getResource(),
187                                                         IResource.DEPTH_INFINITE, null);
188                                 case IJavaElement.PACKAGE_FRAGMENT:
189                                 case IJavaElement.CLASS_FILE:
190                                         return getErrorTicksFromMarkers(element.getResource(),
191                                                         IResource.DEPTH_ONE, null);
192                                 case IJavaElement.COMPILATION_UNIT:
193                                 case IJavaElement.PACKAGE_DECLARATION:
194                                 case IJavaElement.IMPORT_DECLARATION:
195                                 case IJavaElement.IMPORT_CONTAINER:
196                                 case IJavaElement.TYPE:
197                                 case IJavaElement.INITIALIZER:
198                                 case IJavaElement.METHOD:
199                                 case IJavaElement.FIELD:
200                                         ICompilationUnit cu = (ICompilationUnit) element
201                                                         .getAncestor(IJavaElement.COMPILATION_UNIT);
202                                         if (cu != null) {
203                                                 ISourceReference ref = (type == IJavaElement.COMPILATION_UNIT) ? null
204                                                                 : (ISourceReference) element;
205                                                 // The assumption is that only source elements in
206                                                 // compilation unit can have markers
207                                                 if (cu.isWorkingCopy()) {
208                                                         // working copy: look at annotation model
209                                                         return getErrorTicksFromWorkingCopy(
210                                                                         (ICompilationUnit) cu.getOriginalElement(),
211                                                                         ref);
212                                                 }
213                                                 return getErrorTicksFromMarkers(cu.getResource(),
214                                                                 IResource.DEPTH_ONE, ref);
215                                         }
216                                         break;
217                                 default:
218                                 }
219                         } else if (obj instanceof IResource) {
220                                 return getErrorTicksFromMarkers((IResource) obj,
221                                                 IResource.DEPTH_INFINITE, null);
222                         }
223                 } catch (CoreException e) {
224                         if (e instanceof JavaModelException) {
225                                 if (((JavaModelException) e).isDoesNotExist()) {
226                                         return 0;
227                                 }
228                         }
229                         PHPeclipsePlugin.log(e);
230                 }
231                 return 0;
232         }
233
234         private int getErrorTicksFromMarkers(IResource res, int depth,
235                         ISourceReference sourceElement) throws CoreException {
236                 if (res == null || !res.isAccessible()) {
237                         return 0;
238                 }
239                 int info = 0;
240
241                 IMarker[] markers = res.findMarkers(IMarker.PROBLEM, true, depth);
242                 if (markers != null) {
243                         for (int i = 0; i < markers.length && (info != ERRORTICK_ERROR); i++) {
244                                 IMarker curr = markers[i];
245                                 if (sourceElement == null
246                                                 || isMarkerInRange(curr, sourceElement)) {
247                                         int priority = curr.getAttribute(IMarker.SEVERITY, -1);
248                                         if (priority == IMarker.SEVERITY_WARNING) {
249                                                 info = ERRORTICK_WARNING;
250                                         } else if (priority == IMarker.SEVERITY_ERROR) {
251                                                 info = ERRORTICK_ERROR;
252                                         }
253                                 }
254                         }
255                 }
256                 return info;
257         }
258
259         private boolean isMarkerInRange(IMarker marker,
260                         ISourceReference sourceElement) throws CoreException {
261                 if (marker.isSubtypeOf(IMarker.TEXT)) {
262                         int pos = marker.getAttribute(IMarker.CHAR_START, -1);
263                         return isInside(pos, sourceElement);
264                 }
265                 return false;
266         }
267
268         private int getErrorTicksFromWorkingCopy(ICompilationUnit original,
269                         ISourceReference sourceElement) throws CoreException {
270                 int info = 0;
271                 FileEditorInput editorInput = new FileEditorInput((IFile) original
272                                 .getResource());
273                 IAnnotationModel model = PHPeclipsePlugin.getDefault()
274                                 .getCompilationUnitDocumentProvider().getAnnotationModel(
275                                                 editorInput);
276                 if (model != null) {
277                         Iterator iter = model.getAnnotationIterator();
278                         while ((info != ERRORTICK_ERROR) && iter.hasNext()) {
279                                 Annotation curr = (Annotation) iter.next();
280                                 IMarker marker = isAnnotationInRange(model, curr, sourceElement);
281                                 if (marker != null) {
282                                         int priority = marker.getAttribute(IMarker.SEVERITY, -1);
283                                         if (priority == IMarker.SEVERITY_WARNING) {
284                                                 info = ERRORTICK_WARNING;
285                                         } else if (priority == IMarker.SEVERITY_ERROR) {
286                                                 info = ERRORTICK_ERROR;
287                                         }
288                                 }
289                         }
290                 }
291                 return info;
292         }
293
294         private IMarker isAnnotationInRange(IAnnotationModel model,
295                         Annotation annot, ISourceReference sourceElement)
296                         throws CoreException {
297                 if (annot instanceof MarkerAnnotation) {
298                         IMarker marker = ((MarkerAnnotation) annot).getMarker();
299                         if (marker.exists() && marker.isSubtypeOf(IMarker.PROBLEM)) {
300                                 Position pos = model.getPosition(annot);
301                                 if (sourceElement == null
302                                                 || isInside(pos.getOffset(), sourceElement)) {
303                                         return marker;
304                                 }
305                         }
306                 }
307                 return null;
308         }
309
310         /**
311          * Tests if a position is inside the source range of an element.
312          * 
313          * @param pos
314          *            Position to be tested.
315          * @param sourceElement
316          *            Source element (must be a IJavaElement)
317          * @return boolean Return <code>true</code> if position is located inside
318          *         the source element.
319          * @throws CoreException
320          *             Exception thrown if element range could not be accessed.
321          * 
322          * @since 2.1
323          */
324         protected boolean isInside(int pos, ISourceReference sourceElement)
325                         throws CoreException {
326                 ISourceRange range = sourceElement.getSourceRange();
327                 if (range != null) {
328                         int rangeOffset = range.getOffset();
329                         return (rangeOffset <= pos && rangeOffset + range.getLength() > pos);
330                 }
331                 return false;
332         }
333
334         /*
335          * (non-Javadoc)
336          * 
337          * @see IBaseLabelProvider#dispose()
338          */
339         public void dispose() {
340                 if (fProblemChangedListener != null) {
341                         PHPeclipsePlugin.getDefault().getProblemMarkerManager()
342                                         .removeListener(fProblemChangedListener);
343                         fProblemChangedListener = null;
344                 }
345                 if (fRegistry != null && fUseNewRegistry) {
346                         fRegistry.dispose();
347                 }
348         }
349
350         /*
351          * (non-Javadoc)
352          * 
353          * @see IBaseLabelProvider#isLabelProperty(Object, String)
354          */
355         public boolean isLabelProperty(Object element, String property) {
356                 return true;
357         }
358
359         /*
360          * (non-Javadoc)
361          * 
362          * @see IBaseLabelProvider#addListener(ILabelProviderListener)
363          */
364         public void addListener(ILabelProviderListener listener) {
365                 if (fListeners == null) {
366                         fListeners = new ListenerList();
367                 }
368                 fListeners.add(listener);
369                 if (fProblemChangedListener == null) {
370                         fProblemChangedListener = new IProblemChangedListener() {
371                                 public void problemsChanged(IResource[] changedResources,
372                                                 boolean isMarkerChange) {
373                                         fireProblemsChanged(changedResources, isMarkerChange);
374                                 }
375                         };
376                         PHPeclipsePlugin.getDefault().getProblemMarkerManager()
377                                         .addListener(fProblemChangedListener);
378                 }
379         }
380
381         /*
382          * (non-Javadoc)
383          * 
384          * @see IBaseLabelProvider#removeListener(ILabelProviderListener)
385          */
386         public void removeListener(ILabelProviderListener listener) {
387                 if (fListeners != null) {
388                         fListeners.remove(listener);
389                         if (fListeners.isEmpty() && fProblemChangedListener != null) {
390                                 PHPeclipsePlugin.getDefault().getProblemMarkerManager()
391                                                 .removeListener(fProblemChangedListener);
392                                 fProblemChangedListener = null;
393                         }
394                 }
395         }
396
397         private void fireProblemsChanged(IResource[] changedResources,
398                         boolean isMarkerChange) {
399                 if (fListeners != null && !fListeners.isEmpty()) {
400                         LabelProviderChangedEvent event = new ProblemsLabelChangedEvent(
401                                         this, changedResources, isMarkerChange);
402                         Object[] listeners = fListeners.getListeners();
403                         for (int i = 0; i < listeners.length; i++) {
404                                 ((ILabelProviderListener) listeners[i])
405                                                 .labelProviderChanged(event);
406                         }
407                 }
408         }
409
410         /*
411          * (non-Javadoc)
412          * 
413          * @see org.eclipse.jface.viewers.ILightweightLabelDecorator#decorate(java.lang.Object,
414          *      org.eclipse.jface.viewers.IDecoration)
415          */
416         public void decorate(Object element, IDecoration decoration) {
417                 int adornmentFlags = computeAdornmentFlags(element);
418                 if (adornmentFlags == ERRORTICK_ERROR) {
419                         decoration.addOverlay(PHPUiImages.DESC_OVR_ERROR);
420                 } else if (adornmentFlags == ERRORTICK_WARNING) {
421                         decoration.addOverlay(PHPUiImages.DESC_OVR_WARNING);
422                 }
423         }
424
425 }