/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package net.sourceforge.phpdt.ui;
import java.util.Iterator;
import net.sourceforge.phpdt.core.ICompilationUnit;
import net.sourceforge.phpdt.core.IJavaElement;
import net.sourceforge.phpdt.core.ISourceRange;
import net.sourceforge.phpdt.core.ISourceReference;
import net.sourceforge.phpdt.core.JavaModelException;
import net.sourceforge.phpdt.internal.ui.PHPUiImages;
import net.sourceforge.phpdt.internal.ui.viewsupport.IProblemChangedListener;
import net.sourceforge.phpdt.internal.ui.viewsupport.ImageDescriptorRegistry;
import net.sourceforge.phpdt.internal.ui.viewsupport.ImageImageDescriptor;
import net.sourceforge.phpeclipse.PHPeclipsePlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
//incastrix
//import org.eclipse.jface.util.ListenerList;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ILightweightLabelDecorator;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.MarkerAnnotation;
/**
* LabelDecorator that decorates an element's image with error and warning
* overlays that represent the severity of markers attached to the element's
* underlying resource. To see a problem decoration for a marker, the marker
* needs to be a subtype of IMarker.PROBLEM
.
*
* Note: Only images for elements in Java projects are currently updated on * marker changes. *
* * @since 2.0 */ public class ProblemsLabelDecorator implements ILabelDecorator, ILightweightLabelDecorator { /** * This is a specialLabelProviderChangedEvent
carring
* additional information whether the event orgins from a maker change.
*
* ProblemsLabelChangedEvent
s are only generated by
* ProblemsLabelDecorator
s.
*
false
an annotation model change is the origin. In
* this case viewers not displaying working copies can ignore these
* events.
*
* @return if this event origins from a marker change.
*/
public boolean isMarkerChange() {
return fMarkerChange;
}
}
private static final int ERRORTICK_WARNING = JavaElementImageDescriptor.WARNING;
private static final int ERRORTICK_ERROR = JavaElementImageDescriptor.ERROR;
private ImageDescriptorRegistry fRegistry;
private boolean fUseNewRegistry = false;
private IProblemChangedListener fProblemChangedListener;
private ListenerList fListeners;
/**
* Creates a new ProblemsLabelDecorator
.
*/
// public ProblemsLabelDecorator() {
// this(null);
// fUseNewRegistry = true;
// }
/*
* Creates decorator with a shared image registry.
*
* @param registry The registry to use or null
to use the
* Java plugin's image registry.
*/
/**
* Note: This constructor is for internal use only. Clients should not call
* this constructor.
*/
public ProblemsLabelDecorator(ImageDescriptorRegistry registry) {
fRegistry = registry;
fProblemChangedListener = null;
}
private ImageDescriptorRegistry getRegistry() {
if (fRegistry == null) {
fRegistry = fUseNewRegistry ? new ImageDescriptorRegistry()
: PHPeclipsePlugin.getImageDescriptorRegistry();
}
return fRegistry;
}
/*
* (non-Javadoc)
*
* @see ILabelDecorator#decorateText(String, Object)
*/
public String decorateText(String text, Object element) {
return text;
}
/*
* (non-Javadoc)
*
* @see ILabelDecorator#decorateImage(Image, Object)
*/
public Image decorateImage(Image image, Object obj) {
int adornmentFlags = computeAdornmentFlags(obj);
if (adornmentFlags != 0) {
ImageDescriptor baseImage = new ImageImageDescriptor(image);
Rectangle bounds = image.getBounds();
return getRegistry().get(
new JavaElementImageDescriptor(baseImage, adornmentFlags,
new Point(bounds.width, bounds.height)));
}
return image;
}
/**
* Note: This method is for internal use only. Clients should not call this
* method.
*/
protected int computeAdornmentFlags(Object obj) {
try {
if (obj instanceof IJavaElement) {
IJavaElement element = (IJavaElement) obj;
int type = element.getElementType();
switch (type) {
case IJavaElement.JAVA_PROJECT:
case IJavaElement.PACKAGE_FRAGMENT_ROOT:
return getErrorTicksFromMarkers(element.getResource(),
IResource.DEPTH_INFINITE, null);
case IJavaElement.PACKAGE_FRAGMENT:
case IJavaElement.CLASS_FILE:
return getErrorTicksFromMarkers(element.getResource(),
IResource.DEPTH_ONE, null);
case IJavaElement.COMPILATION_UNIT:
case IJavaElement.PACKAGE_DECLARATION:
case IJavaElement.IMPORT_DECLARATION:
case IJavaElement.IMPORT_CONTAINER:
case IJavaElement.TYPE:
case IJavaElement.INITIALIZER:
case IJavaElement.METHOD:
case IJavaElement.FIELD:
ICompilationUnit cu = (ICompilationUnit) element
.getAncestor(IJavaElement.COMPILATION_UNIT);
if (cu != null) {
ISourceReference ref = (type == IJavaElement.COMPILATION_UNIT) ? null
: (ISourceReference) element;
// The assumption is that only source elements in
// compilation unit can have markers
if (cu.isWorkingCopy()) {
// working copy: look at annotation model
return getErrorTicksFromWorkingCopy(
(ICompilationUnit) cu.getOriginalElement(),
ref);
}
return getErrorTicksFromMarkers(cu.getResource(),
IResource.DEPTH_ONE, ref);
}
break;
default:
}
} else if (obj instanceof IResource) {
return getErrorTicksFromMarkers((IResource) obj,
IResource.DEPTH_INFINITE, null);
}
} catch (CoreException e) {
if (e instanceof JavaModelException) {
if (((JavaModelException) e).isDoesNotExist()) {
return 0;
}
}
PHPeclipsePlugin.log(e);
}
return 0;
}
private int getErrorTicksFromMarkers(IResource res, int depth,
ISourceReference sourceElement) throws CoreException {
if (res == null || !res.isAccessible()) {
return 0;
}
int info = 0;
IMarker[] markers = res.findMarkers(IMarker.PROBLEM, true, depth);
if (markers != null) {
for (int i = 0; i < markers.length && (info != ERRORTICK_ERROR); i++) {
IMarker curr = markers[i];
if (sourceElement == null
|| isMarkerInRange(curr, sourceElement)) {
int priority = curr.getAttribute(IMarker.SEVERITY, -1);
if (priority == IMarker.SEVERITY_WARNING) {
info = ERRORTICK_WARNING;
} else if (priority == IMarker.SEVERITY_ERROR) {
info = ERRORTICK_ERROR;
}
}
}
}
return info;
}
private boolean isMarkerInRange(IMarker marker,
ISourceReference sourceElement) throws CoreException {
if (marker.isSubtypeOf(IMarker.TEXT)) {
int pos = marker.getAttribute(IMarker.CHAR_START, -1);
return isInside(pos, sourceElement);
}
return false;
}
private int getErrorTicksFromWorkingCopy(ICompilationUnit original,
ISourceReference sourceElement) throws CoreException {
int info = 0;
FileEditorInput editorInput = new FileEditorInput((IFile) original
.getResource());
IAnnotationModel model = PHPeclipsePlugin.getDefault()
.getCompilationUnitDocumentProvider().getAnnotationModel(
editorInput);
if (model != null) {
Iterator iter = model.getAnnotationIterator();
while ((info != ERRORTICK_ERROR) && iter.hasNext()) {
Annotation curr = (Annotation) iter.next();
IMarker marker = isAnnotationInRange(model, curr, sourceElement);
if (marker != null) {
int priority = marker.getAttribute(IMarker.SEVERITY, -1);
if (priority == IMarker.SEVERITY_WARNING) {
info = ERRORTICK_WARNING;
} else if (priority == IMarker.SEVERITY_ERROR) {
info = ERRORTICK_ERROR;
}
}
}
}
return info;
}
private IMarker isAnnotationInRange(IAnnotationModel model,
Annotation annot, ISourceReference sourceElement)
throws CoreException {
if (annot instanceof MarkerAnnotation) {
IMarker marker = ((MarkerAnnotation) annot).getMarker();
if (marker.exists() && marker.isSubtypeOf(IMarker.PROBLEM)) {
Position pos = model.getPosition(annot);
if (sourceElement == null
|| isInside(pos.getOffset(), sourceElement)) {
return marker;
}
}
}
return null;
}
/**
* Tests if a position is inside the source range of an element.
*
* @param pos
* Position to be tested.
* @param sourceElement
* Source element (must be a IJavaElement)
* @return boolean Return true
if position is located inside
* the source element.
* @throws CoreException
* Exception thrown if element range could not be accessed.
*
* @since 2.1
*/
protected boolean isInside(int pos, ISourceReference sourceElement)
throws CoreException {
ISourceRange range = sourceElement.getSourceRange();
if (range != null) {
int rangeOffset = range.getOffset();
return (rangeOffset <= pos && rangeOffset + range.getLength() > pos);
}
return false;
}
/*
* (non-Javadoc)
*
* @see IBaseLabelProvider#dispose()
*/
public void dispose() {
if (fProblemChangedListener != null) {
PHPeclipsePlugin.getDefault().getProblemMarkerManager()
.removeListener(fProblemChangedListener);
fProblemChangedListener = null;
}
if (fRegistry != null && fUseNewRegistry) {
fRegistry.dispose();
}
}
/*
* (non-Javadoc)
*
* @see IBaseLabelProvider#isLabelProperty(Object, String)
*/
public boolean isLabelProperty(Object element, String property) {
return true;
}
/*
* (non-Javadoc)
*
* @see IBaseLabelProvider#addListener(ILabelProviderListener)
*/
public void addListener(ILabelProviderListener listener) {
if (fListeners == null) {
fListeners = new ListenerList();
}
fListeners.add(listener);
if (fProblemChangedListener == null) {
fProblemChangedListener = new IProblemChangedListener() {
public void problemsChanged(IResource[] changedResources,
boolean isMarkerChange) {
fireProblemsChanged(changedResources, isMarkerChange);
}
};
PHPeclipsePlugin.getDefault().getProblemMarkerManager()
.addListener(fProblemChangedListener);
}
}
/*
* (non-Javadoc)
*
* @see IBaseLabelProvider#removeListener(ILabelProviderListener)
*/
public void removeListener(ILabelProviderListener listener) {
if (fListeners != null) {
fListeners.remove(listener);
if (fListeners.isEmpty() && fProblemChangedListener != null) {
PHPeclipsePlugin.getDefault().getProblemMarkerManager()
.removeListener(fProblemChangedListener);
fProblemChangedListener = null;
}
}
}
private void fireProblemsChanged(IResource[] changedResources,
boolean isMarkerChange) {
if (fListeners != null && !fListeners.isEmpty()) {
LabelProviderChangedEvent event = new ProblemsLabelChangedEvent(
this, changedResources, isMarkerChange);
Object[] listeners = fListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
((ILabelProviderListener) listeners[i])
.labelProviderChanged(event);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ILightweightLabelDecorator#decorate(java.lang.Object,
* org.eclipse.jface.viewers.IDecoration)
*/
public void decorate(Object element, IDecoration decoration) {
int adornmentFlags = computeAdornmentFlags(element);
if (adornmentFlags == ERRORTICK_ERROR) {
decoration.addOverlay(PHPUiImages.DESC_OVR_ERROR);
} else if (adornmentFlags == ERRORTICK_WARNING) {
decoration.addOverlay(PHPUiImages.DESC_OVR_WARNING);
}
}
}