/*
* #%~
* org.overture.ide.ui
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.ide.ui;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.resource.ImageDescriptor;
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.overture.ide.core.IVdmElement;
import org.overture.ide.ui.internal.viewsupport.IProblemChangedListener;
import org.overture.ide.ui.internal.viewsupport.ImageDescriptorRegistry;
import org.overture.ide.ui.internal.viewsupport.ImageImageDescriptor;
import org.overture.ide.ui.internal.viewsupport.VdmElementImageDescriptor;
/**
* 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 <code>IMarker.PROBLEM</code>.
* <p>
* <b>Important</b>: Although this decorator implements ILightweightLabelDecorator, do not contribute this
* class as a decorator to the <code>org.eclipse.ui.decorators</code> extension. Only use this class in your
* own views and label providers.
*
* @since 2.0
*/
public class VdmProblemsLabelDecorator implements ILabelDecorator,
ILightweightLabelDecorator
{
/**
* This is a special <code>LabelProviderChangedEvent</code> carrying additional information whether the
* event origins from a maker change.
* <p>
* <code>ProblemsLabelChangedEvent</code>s are only generated by <code>
* ProblemsLabelDecorator</code>s.
* </p>
*/
public static class ProblemsLabelChangedEvent extends
LabelProviderChangedEvent
{
private static final long serialVersionUID = 1L;
private boolean fMarkerChange;
/**
* @param eventSource
* the base label provider
* @param changedResource
* the changed resources
* @param isMarkerChange
* <code>true</code> if the change is a marker change; otherwise <code>false</code>
*/
public ProblemsLabelChangedEvent(IBaseLabelProvider eventSource,
IResource[] changedResource, boolean isMarkerChange) {
super(eventSource, changedResource);
fMarkerChange = isMarkerChange;
}
/**
* Returns whether this event origins from marker changes. If <code>false</code> 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 = VdmElementImageDescriptor.WARNING;
private static final int ERRORTICK_ERROR = VdmElementImageDescriptor.ERROR;
private ImageDescriptorRegistry fRegistry;
private boolean fUseNewRegistry = false;
private IProblemChangedListener fProblemChangedListener;
private ListenerList fListeners;
// private ISourceRange fCachedRange;
/**
* Creates a new <code>ProblemsLabelDecorator</code>.
*/
public VdmProblemsLabelDecorator() {
this(null);
fUseNewRegistry = true;
}
/**
* Note: This constructor is for internal use only. Clients should not call this constructor.
*
* @param registry
* The registry to use or <code>null</code> to use the Java plugin's image registry
* @noreference This constructor is not intended to be referenced by clients.
*/
public VdmProblemsLabelDecorator(ImageDescriptorRegistry registry) {
fRegistry = registry;
fProblemChangedListener = null;
}
private ImageDescriptorRegistry getRegistry()
{
if (fRegistry == null)
{
fRegistry = fUseNewRegistry ? new ImageDescriptorRegistry()
: VdmUIPlugin.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)
{
if (image == null)
return null;
int adornmentFlags = computeAdornmentFlags(obj);
if (adornmentFlags != 0)
{
ImageDescriptor baseImage = new ImageImageDescriptor(image);
Rectangle bounds = image.getBounds();
return getRegistry().get(new VdmElementImageDescriptor(baseImage,
0,
new Point(bounds.width, bounds.height)));
}
return image;
}
/**
* Computes the adornment flags for the given element.
*
* @param obj
* the element to compute the flags for
*
* @return the adornment flags
*/
protected int computeAdornmentFlags(Object obj)
{
// try
// {
if (obj instanceof IVdmElement)
{
IVdmElement element = (IVdmElement) obj;
int type = element.getElementType();
switch (type)
{
case IVdmElement.VDM_MODEL:
case IVdmElement.VDM_PROJECT:
// case IVdmElement.PACKAGE_FRAGMENT_ROOT:
// return getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_INFINITE, null);
// case IVdmElement.PACKAGE_FRAGMENT:
case IVdmElement.COMPILATION_UNIT:
// case IVdmElement.CLASS_FILE:
// return getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_ONE, null);
// case IVdmElement.PACKAGE_DECLARATION:
// case IVdmElement.IMPORT_DECLARATION:
// case IVdmElement.IMPORT_CONTAINER:
case IVdmElement.TYPE:
case IVdmElement.INITIALIZER:
case IVdmElement.METHOD:
case IVdmElement.FIELD:
// case IVdmElement.LOCAL_VARIABLE:
// ICompilationUnit cu= (ICompilationUnit)
// element.getAncestor(IVdmElement.COMPILATION_UNIT);
// if (cu != null) {
// ISourceReference ref= (type == IVdmElement.COMPILATION_UNIT) ? null :
// (ISourceReference) element;
// // The assumption is that only source elements in compilation unit can have markers
// IAnnotationModel model= isInJavaAnnotationModel(cu);
// int result= 0;
// if (model != null) {
// // open in Java editor: look at annotation model
// result= getErrorTicksFromAnnotationModel(model, ref);
// } else {
// result= getErrorTicksFromMarkers(cu.getResource(), IResource.DEPTH_ONE, ref);
// }
// fCachedRange= null;
// return result;
// }
break;
default:
}
}
// else if (obj instanceof IResource)
// {
// return getErrorTicksFromMarkers((IResource) obj,
// IResource.DEPTH_INFINITE,
// null);
// }
// } catch (CoreException e)
// {
// if (e instanceof VdmModelException)
// {
// if (((VdmModelException) e).isDoesNotExist())
// {
// return 0;
// }
// }
// if (e.getStatus().getCode() == IResourceStatus.MARKER_NOT_FOUND)
// {
// return 0;
// }
//
// VdmUIPlugin.log(e);
// }
return 0;
}
// private int getErrorTicksFromMarkers(IResource res, int depth,
// ISourceReference sourceElement) throws CoreException
// {
// if (res == null || !res.isAccessible())
// {
// return 0;
// }
// int severity = 0;
// if (sourceElement == null)
// {
// severity = res.findMaxProblemSeverity(IMarker.PROBLEM, true, depth);
// } else
// {
// IMarker[] markers = res.findMarkers(IMarker.PROBLEM, true, depth);
// if (markers != null && markers.length > 0)
// {
// for (int i = 0; i < markers.length
// && (severity != IMarker.SEVERITY_ERROR); i++)
// {
// IMarker curr = markers[i];
// if (isMarkerInRange(curr, sourceElement))
// {
// int val = curr.getAttribute(IMarker.SEVERITY, -1);
// if (val == IMarker.SEVERITY_WARNING
// || val == IMarker.SEVERITY_ERROR)
// {
// severity = val;
// }
// }
// }
// }
// }
// if (severity == IMarker.SEVERITY_ERROR)
// {
// return ERRORTICK_ERROR;
// } else if (severity == IMarker.SEVERITY_WARNING)
// {
// return ERRORTICK_WARNING;
// }
// return 0;
// }
//
// 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 IAnnotationModel isInJavaAnnotationModel(ICompilationUnit original) {
// if (original.isWorkingCopy()) {
// FileEditorInput editorInput= new FileEditorInput((IFile) original.getResource());
// //return JavaPlugin.getDefault().getCompilationUnitDocumentProvider().getAnnotationModel(editorInput);
// }
// return null;
// }
// private int getErrorTicksFromAnnotationModel(IAnnotationModel model,
// ISourceReference sourceElement) throws CoreException
// {
// int info = 0;
// Iterator iter = model.getAnnotationIterator();
// while ((info != ERRORTICK_ERROR) && iter.hasNext())
// {
// Annotation annot = (Annotation) iter.next();
// IMarker marker = isAnnotationInRange(model, annot, 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)
// {
// if (sourceElement == null
// || isInside(model.getPosition(annot), sourceElement))
// {
// IMarker marker = ((MarkerAnnotation) annot).getMarker();
// if (marker.exists() && marker.isSubtypeOf(IMarker.PROBLEM))
// {
// return marker;
// }
// }
// }
// return null;
// }
//
// private boolean isInside(Position pos, ISourceReference sourceElement)
// throws CoreException
// {
// return pos != null && isInside(pos.getOffset(), sourceElement);
// }
//
// /**
// * 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 IVdmElement)
// * @return boolean Return <code>true</code> 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
// {
// if (fCachedRange == null)
// {
// fCachedRange = sourceElement.getSourceRange();
// }
// ISourceRange range = fCachedRange;
// 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)
{
VdmUIPlugin.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);
}
};
VdmUIPlugin.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)
{
VdmUIPlugin.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(VdmPluginImages.DESC_OVR_ERROR);
} else if (adornmentFlags == ERRORTICK_WARNING)
{
decoration.addOverlay(VdmPluginImages.DESC_OVR_WARNING);
}
}
}