/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.sarl.lang.ui.labeling;
import java.lang.reflect.Method;
import javax.inject.Singleton;
import com.google.inject.Inject;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
import org.eclipse.jdt.ui.JavaElementImageDescriptor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.xtend.core.xtend.XtendMember;
import org.eclipse.xtext.diagnostics.AbstractDiagnostic;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.ui.IImageHelper;
import org.eclipse.xtext.ui.IImageHelper.IImageDescriptorHelper;
/**
* A decorator that add the diagnotic results on Ecore elements.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@Singleton
public class SARLDiagnosticLabelDecorator extends BaseLabelProvider implements ILabelDecorator {
private static final Method GET_NODE_METHOD;
static {
try {
GET_NODE_METHOD = AbstractDiagnostic.class.getDeclaredMethod("getNode"); //$NON-NLS-1$
GET_NODE_METHOD.setAccessible(true);
} catch (Exception e) {
throw new Error(e);
}
}
@Inject
private IImageHelper imageHelper;
@Inject
private IImageDescriptorHelper imageDescriptorHelper;
private static boolean inside(INode node, ICompositeNode parentCandidate) {
INode current = node;
while (current != null) {
if (current.equals(parentCandidate)) {
return true;
}
current = current.getParent();
}
return false;
}
/** Replies the image that corresponds to the given object.
*
* @param imageDescription
* a {@link String}, an {@link ImageDescriptor} or an {@link Image}
* @return the {@link Image} associated with the description or <code>null</code>
*/
protected Image convertToImage(Object imageDescription) {
if (imageDescription instanceof Image) {
return (Image) imageDescription;
} else if (imageDescription instanceof ImageDescriptor) {
return this.imageHelper.getImage((ImageDescriptor) imageDescription);
} else if (imageDescription instanceof String) {
return this.imageHelper.getImage((String) imageDescription);
}
return null;
}
private static boolean hasParserIssue(ICompositeNode node, Iterable<Resource.Diagnostic> issues) {
for (final Resource.Diagnostic resourceDiagnostic : issues) {
if (resourceDiagnostic instanceof AbstractDiagnostic) {
final AbstractDiagnostic diag = (AbstractDiagnostic) resourceDiagnostic;
final INode diagNode;
try {
diagNode = (INode) GET_NODE_METHOD.invoke(diag);
} catch (Exception e) {
throw new Error(e);
}
if (inside(diagNode, node)) {
return true;
}
}
}
return false;
}
/** Replies the diagnotic adornment for the given element.
*
* @param element the model element.
* @return the adornment.
*/
@SuppressWarnings("static-method")
protected int getIssueAdornment(XtendMember element) {
final ICompositeNode node = NodeModelUtils.getNode(element);
if (node == null) {
return 0;
}
// Error markers are more important than warning markers.
// Order of checks:
// - parser error (from the resource) or semantic error (from Diagnostician)
// - parser warning or semantic warning
final Resource resource = element.eResource();
if (hasParserIssue(node, resource.getErrors())) {
return JavaElementImageDescriptor.ERROR;
}
final Diagnostic diagnostic = Diagnostician.INSTANCE.validate(element);
switch (diagnostic.getSeverity()) {
case Diagnostic.ERROR:
return JavaElementImageDescriptor.ERROR;
case Diagnostic.WARNING:
return JavaElementImageDescriptor.WARNING;
default:
}
if (hasParserIssue(node, resource.getWarnings())) {
return JavaElementImageDescriptor.WARNING;
}
return 0;
}
/**Replies the size of the images.
*
* @return {@link JavaElementImageProvider#SMALL_SIZE} or {@link JavaElementImageProvider#BIG_SIZE}
*/
@SuppressWarnings("static-method")
protected Point imagesSize() {
return JavaElementImageProvider.BIG_SIZE;
}
@Override
public Image decorateImage(Image image, Object element) {
if (element instanceof XtendMember) {
final int adornment = getIssueAdornment((XtendMember) element);
if (adornment != 0) {
final ImageDescriptor descriptor = this.imageDescriptorHelper.getImageDescriptor(image);
final ImageDescriptor newDescriptor = new JavaElementImageDescriptor(descriptor, adornment, imagesSize());
return convertToImage(newDescriptor);
}
}
return image;
}
@Override
public String decorateText(String text, Object element) {
return text;
}
}