package com.redhat.ceylon.eclipse.core.debug.presentation;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.internal.core.LaunchManager;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jdt.debug.core.IJavaReferenceType;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaType;
import org.eclipse.jdt.debug.core.IJavaValue;
import org.eclipse.jdt.debug.core.IJavaVariable;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import com.redhat.ceylon.compiler.java.metadata.Ceylon;
import com.redhat.ceylon.eclipse.core.debug.DebugUtils;
import com.redhat.ceylon.eclipse.core.debug.model.CeylonJDIDebugTarget;
class CeylonPresentationContext implements IPresentationContext {
private IPresentationContext delegate;
public CeylonPresentationContext(IPresentationContext delegate) {
this.delegate = delegate;
}
public String[] getColumns() {
return delegate.getColumns();
}
public void addPropertyChangeListener(IPropertyChangeListener listener) {
delegate.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(IPropertyChangeListener listener) {
delegate.removePropertyChangeListener(listener);
}
public String getId() {
return delegate.getId();
}
public void setProperty(String property, Object value) {
delegate.setProperty(property, value);
}
public Object getProperty(String property) {
return delegate.getProperty(property);
}
public void dispose() {
delegate.dispose();
}
public String[] getProperties() {
return delegate.getProperties();
}
public IWorkbenchPart getPart() {
return delegate.getPart();
}
public IWorkbenchWindow getWindow() {
return delegate.getWindow();
}
static IPresentationContext toCeylonContextIfNecessary(IPresentationContext context, IViewerUpdate viewerUpdate) {
if (context instanceof CeylonPresentationContext) {
return context;
}
if (isCeylonContext(viewerUpdate)) {
return new CeylonPresentationContext(context);
}
return context;
}
static boolean isCeylonContext(IPresentationContext context) {
return context instanceof CeylonPresentationContext;
}
static IJavaStackFrame getCeylonStackFrame(IViewerUpdate viewerUpdate) {
IJavaStackFrame frame = getStackFrame(viewerUpdate);
if (frame != null && DebugUtils.isCeylonFrame(frame)) {
return frame;
}
return null;
}
private static IJavaStackFrame getStackFrame(IViewerUpdate viewerUpdate) {
Object input = viewerUpdate.getViewerInput();
if (input instanceof IJavaStackFrame) {
return (IJavaStackFrame) input;
}
if (input instanceof LaunchManager) {
if (viewerUpdate.getElement() instanceof IJavaStackFrame) {
return (IJavaStackFrame) viewerUpdate.getElement();
}
}
IAdaptable context = DebugUITools.getDebugContext();
if (context != null) {
return (IJavaStackFrame) context.getAdapter(IJavaStackFrame.class);
}
return null;
}
static Boolean isInCeylonFile(IJavaReferenceType type) throws DebugException {
String sourceName = null;
sourceName = type.getSourceName();
if (sourceName != null
&& sourceName.endsWith(".ceylon")) {
return true;
}
return false;
}
static IJavaReferenceType getReferenceType(Object obj) throws DebugException {
IJavaReferenceType type = null;
if (obj instanceof IJavaReferenceType) {
type = (IJavaReferenceType) obj;
} else {
IJavaValue value = null;
if (obj instanceof IJavaValue) {
value = (IJavaValue) obj;
} else if (obj instanceof IJavaVariable) {
value = (IJavaValue) ((IJavaVariable)obj).getValue();
}
if (value != null) {
IJavaType valueType = value.getJavaType();
if (valueType instanceof IJavaReferenceType) {
type = (IJavaReferenceType) valueType;
}
}
}
return type;
}
static Boolean isKnownAsCeylon(String typeName) throws DebugException {
if (typeName.startsWith("ceylon.language.")) {
return true;
}
return false;
}
static Boolean isKnownAsJava(String typeName) throws DebugException {
if (typeName.startsWith("java.lang")) {
return true;
}
return false;
}
static boolean isCeylonContext(IJavaValue value, PresentationType presentationType) {
IAdaptable debugContext = DebugUITools.getDebugContext();
if (! (debugContext instanceof IJavaStackFrame)) {
return false;
}
return CeylonPresentationContext.isCeylonContext(
(IJavaStackFrame) debugContext,
value,
presentationType);
}
static boolean isCeylonContext(IJavaVariable var, PresentationType presentationType) {
IAdaptable debugContext = DebugUITools.getDebugContext();
if (! (debugContext instanceof IJavaStackFrame)) {
return false;
}
IJavaValue value = null;
try {
value = (IJavaValue) var.getValue();
} catch (DebugException e) {
return false;
}
if (value == null) {
return false;
}
return CeylonPresentationContext.isCeylonContext(
(IJavaStackFrame) debugContext,
value,
presentationType);
}
static boolean isCeylonContext(IViewerUpdate viewerUpdate) {
return isCeylonContext(
getStackFrame(viewerUpdate),
viewerUpdate.getElement(),
viewerUpdate instanceof ILabelUpdate ? PresentationType.LABEL : PresentationType.CHILDREN);
}
public static enum PresentationType {
LABEL,
CHILDREN
}
static boolean isCeylonContext(IJavaStackFrame stackFrame, Object element, PresentationType presentationType) {
if (stackFrame == null || ! DebugUtils.isCeylonFrame(stackFrame)) {
// We are suspended in a Java file => adopt the Java presentations
return false;
}
if (presentationType.equals(PresentationType.CHILDREN)) {
IJavaReferenceType type;
try {
type = getReferenceType(element);
if (type != null) {
// If the current model element has a Class (variable in the Variables View for example),
// Analyze the Class to know whether we use the Java or the Ceylon presentation
if (isInCeylonFile(type)) {
return true;
}
String typeName = type.getName();
if (typeName != null) {
if (isKnownAsCeylon(typeName)) {
return true;
}
if (isKnownAsJava(typeName)) {
return false;
}
}
// We are in a Ceylon stackframe, this class is defined in Java,
// and we don't know if it is a Ceylon class
// => look at the Ceylon annotation
IDebugTarget dt = type.getDebugTarget();
if (dt instanceof CeylonJDIDebugTarget) {
CeylonJDIDebugTarget target = (CeylonJDIDebugTarget) dt;
return target.isAnnotationPresent((IJavaReferenceType) type, Ceylon.class, 5000);
}
return false;
}
} catch (DebugException e) {
e.printStackTrace();
return false;
}
}
return true;
}
}