blob: 22d4a4c87b0156e91ff7afa95b44cb29deb29433 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 OPCoach.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* OPCoach - initial API and implementation
*******************************************************************************/
package org.eclipse.e4.internal.tools.context.spy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.eclipse.e4.core.internal.contexts.Computation;
import org.eclipse.e4.core.internal.contexts.EclipseContext;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
/**
* The column Label and content Provider used to display information in context
* data TreeViewer. Two instances for label provider are created : one for key,
* one for values
*
* @see ContextDataPart
*/
public class ContextDataProvider extends ColumnLabelProvider implements ITreeContentProvider
{
private static final String NO_VALUE_COULD_BE_COMPUTED = "No value could be yet computed";
private static final Color COLOR_IF_FOUND = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
private static final Color COLOR_IF_NOT_COMPUTED = Display.getCurrent().getSystemColor(SWT.COLOR_MAGENTA);
private static final Object[] EMPTY_RESULT = new Object[0];
static final String LOCAL_VALUE_NODE = "Local values managed by this context";
static final String INHERITED_INJECTED_VALUE_NODE = "Inherited values injected or updated using this context";
private static final String NO_VALUES_FOUND = "No values found";
private static final String UPDATED_IN_CLASS = "Updated in class :";
private static final String INJECTED_IN_FIELD = "Injected in field :";
private static final String INJECTED_IN_METHOD = "Injected in method :";
// Image keys constants
private static final String PUBLIC_METHOD_IMG_KEY = "icons/methpub_obj.gif";
private static final String PUBLIC_FIELD_IMG_KEY = "icons/field_public_obj.gif";
private static final String VALUE_IN_CONTEXT_IMG_KEY = "icons/valueincontext.gif";
private static final String INHERITED_VARIABLE_IMG_KEY = "icons/inher_co.gif";
private static final String LOCAL_VARIABLE_IMG_KEY = "icons/letter-l-icon.png";
private static final String CONTEXT_FUNCTION_IMG_KEY = "icons/contextfunction.gif";
private static final String INJECT_IMG_KEY = "icons/annotation_obj.gif";
private ImageRegistry imgReg;
@Inject
private ContextDataFilter contextFilter;
/** Store the selected context (initialized in inputChanged) */
@SuppressWarnings("restriction")
private static EclipseContext selectedContext;
private Font boldFont;
private boolean displayKey = false;
@Inject
public ContextDataProvider()
{
super();
initFonts();
initializeImageRegistry();
}
@Override
public void dispose()
{
selectedContext = null;
imgReg = null;
}
@SuppressWarnings("restriction")
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
selectedContext = (newInput instanceof EclipseContext) ? (EclipseContext) newInput : null;
}
public Object[] getElements(Object inputElement)
{
return new String[] { LOCAL_VALUE_NODE, INHERITED_INJECTED_VALUE_NODE };
}
@SuppressWarnings("restriction")
public Object[] getChildren(Object inputElement)
{
if (selectedContext == null)
return EMPTY_RESULT;
if (inputElement == LOCAL_VALUE_NODE)
{
Collection<Object> result = new ArrayList<Object>();
result.addAll(selectedContext.localData().entrySet());
// For context function, we have to compute the value (if possible),
// and display it as a standard value
Map<String, Object> cfValues = new HashMap<String, Object>();
for (String key : selectedContext.localContextFunction().keySet())
try
{
cfValues.put(key, selectedContext.get(key));
} catch (Exception e)
{
cfValues.put(key, NO_VALUE_COULD_BE_COMPUTED + " (Exception : " + e.getClass().getName() + ")");
}
result.addAll(cfValues.entrySet());
return result.toArray();
} else if (inputElement == INHERITED_INJECTED_VALUE_NODE)
{
// Search for all values injected using this context but defined in
// parent
Collection<Object> result = new ArrayList<Object>();
// Keep only the names that are not already displayed in local
// values
Collection<String> localKeys = selectedContext.localData().keySet();
Collection<String> localContextFunctionsKeys = selectedContext.localContextFunction().keySet();
if (selectedContext.getRawListenerNames() != null)
{
for (String name : selectedContext.getRawListenerNames())
{
if (!localKeys.contains(name) && !localContextFunctionsKeys.contains(name))
result.add(name);
}
}
return result.size() == 0 ? new String[] { NO_VALUES_FOUND } : result.toArray();
} else if (inputElement instanceof Map.Entry)
{
Set<Computation> listeners = getListeners(inputElement);
return (listeners == null) ? null : listeners.toArray();
} else if (inputElement instanceof String)
{
// This is the name of a raw listener in the inherited injected
// value part
return selectedContext.getListeners((String) inputElement).toArray();
}
return EMPTY_RESULT;
}
public void setDisplayKey(boolean k)
{
displayKey = k;
}
@Override
@SuppressWarnings({ "unchecked", "restriction" })
public String getText(Object element)
{
if (selectedContext == null)
return null;
if (element instanceof Map.Entry)
{
Map.Entry<String, Object> mapEntry = (Map.Entry<String, Object>) element;
Object o = displayKey ? mapEntry.getKey() : mapEntry.getValue();
return (o == null) ? "null" : o.toString();
} else if (element instanceof Computation)
{
// For a computation : display field or method in key column and the
// value in value
String txt = super.getText(element);
if (displayKey)
{
if (txt.contains("#"))
return INJECTED_IN_METHOD;
else if (txt.contains("@"))
return UPDATED_IN_CLASS;
else
return INJECTED_IN_FIELD;
} else
return txt;
}
return displayKey ? super.getText(element) : null;
}
@Override
public Color getForeground(Object element)
{
// Return magenta color if the value could not be yet computed (for context functions)
String s = getText(element);
if ((s != null) && s.startsWith(NO_VALUE_COULD_BE_COMPUTED))
return COLOR_IF_NOT_COMPUTED;
// Return blue color if the string matches the search
return (contextFilter.matchText(s)) ? COLOR_IF_FOUND : null;
}
/** Get the bold font for keys that are computed with ContextFunction */
public Font getFont(Object element)
{
return (element == LOCAL_VALUE_NODE || element == INHERITED_INJECTED_VALUE_NODE) ? boldFont : null;
}
@SuppressWarnings("restriction")
@Override
public Image getImage(Object element)
{
if (!displayKey) // No image in value column, only in key column
return null;
if (element == LOCAL_VALUE_NODE)
{
return selectedContext == null ? null : imgReg.get(LOCAL_VARIABLE_IMG_KEY);
} else if (element == INHERITED_INJECTED_VALUE_NODE)
{
return selectedContext == null ? null : imgReg.get(INHERITED_VARIABLE_IMG_KEY);
} else if (element instanceof Computation)
{
// For a computation : display field, method or class in key column and
// value in value column
String txt = super.getText(element);
if (txt.contains("#"))
return imgReg.get(PUBLIC_METHOD_IMG_KEY);
else if (txt.contains("@"))
return imgReg.get(CONTEXT_FUNCTION_IMG_KEY);
else
return imgReg.get(PUBLIC_FIELD_IMG_KEY);
} else if (element instanceof Map.Entry)
{
if (isAContextKeyFunction(element))
return imgReg.get(CONTEXT_FUNCTION_IMG_KEY);
else
{
// It is a value. If it is injected somewhere, display the
// inject image
return hasChildren(element) ? imgReg.get(INJECT_IMG_KEY) : imgReg.get(VALUE_IN_CONTEXT_IMG_KEY);
}
}
return imgReg.get(INJECT_IMG_KEY);
}
@SuppressWarnings("restriction")
@Override
public String getToolTipText(Object element)
{
if (element == LOCAL_VALUE_NODE)
{
return "This part contains values set in this context and then injected here or in children\n\n"
+ "If the value is injected using this context, you can expand the node to see where\n\n"
+ "If the value is injected using a child context you can find it in the second part for this child ";
} else if (element == INHERITED_INJECTED_VALUE_NODE)
{
return "This part contains the values injected or updated using this context, but initialized in a parent context\n\n"
+ "Expand nodes to see where values are injected or updated";
} else if (isAContextKeyFunction(element))
{
String key = (String) ((Map.Entry<?, ?>) element).getKey();
String fname = (String) selectedContext.localContextFunction().get(key).getClass().getCanonicalName();
return "This value is created by the Context Function : " + fname;
} else
{
if (hasChildren(element))
return "Expand this node to see where this value is injected or updated";
else
{
if (element instanceof Map.Entry)
return "This value is set here but not injected using this context (look in children context)";
}
}
return super.getToolTipText(element);
}
@Override
public Image getToolTipImage(Object object)
{
return getImage(object);
}
@Override
public int getToolTipStyle(Object object)
{
return SWT.SHADOW_OUT;
}
/**
* Compute it the current entry in context is a context function
*
* @param element
* @return true if element is a context function
*/
@SuppressWarnings({ "restriction", "unchecked" })
boolean isAContextKeyFunction(Object element)
{
if (selectedContext != null && element instanceof Map.Entry)
{
// Just check if key in element is a key in the map of context
// functions.
Map.Entry<String, Object> mapEntry = (Map.Entry<String, Object>) element;
return (selectedContext.localContextFunction().containsKey(mapEntry.getKey()));
}
return false;
}
@Override
public Object getParent(Object element)
{
if (element == LOCAL_VALUE_NODE || element == INHERITED_INJECTED_VALUE_NODE)
return null;
// Not computed
return null;
}
@SuppressWarnings("restriction")
@Override
public boolean hasChildren(Object element)
{
if ((element == INHERITED_INJECTED_VALUE_NODE) || (element == LOCAL_VALUE_NODE))
{
return true; // Intermediate nodes returns true
}
Set<Computation> listeners = getListeners(element);
return (listeners != null) && (listeners.size() > 0);
}
@SuppressWarnings({ "restriction", "unchecked" })
Set<Computation> getListeners(Object element)
{
if (selectedContext != null)
{
if (element instanceof Map.Entry)
{
// Ask the context to know if there are listeners for this value
Map.Entry<String, Object> mapEntry = (Map.Entry<String, Object>) element;
String key = mapEntry.getKey();
return selectedContext.getListeners(key);
} else if (element instanceof String)
{
// Ask the context to know if there are listeners for this raw
// listener name
return selectedContext.getListeners((String) element);
}
}
return null;
}
private void initializeImageRegistry()
{
Bundle b = FrameworkUtil.getBundle(this.getClass());
imgReg = new ImageRegistry();
imgReg.put(CONTEXT_FUNCTION_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(CONTEXT_FUNCTION_IMG_KEY)));
imgReg.put(INJECT_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(INJECT_IMG_KEY)));
imgReg.put(PUBLIC_METHOD_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(PUBLIC_METHOD_IMG_KEY)));
imgReg.put(PUBLIC_FIELD_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(PUBLIC_FIELD_IMG_KEY)));
imgReg.put(PUBLIC_FIELD_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(PUBLIC_FIELD_IMG_KEY)));
imgReg.put(LOCAL_VARIABLE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(LOCAL_VARIABLE_IMG_KEY)));
imgReg.put(VALUE_IN_CONTEXT_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(VALUE_IN_CONTEXT_IMG_KEY)));
imgReg.put(INHERITED_VARIABLE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(INHERITED_VARIABLE_IMG_KEY)));
}
private void initFonts()
{
FontData[] fontData = Display.getCurrent().getSystemFont().getFontData();
String fontName = fontData[0].getName();
FontRegistry registry = JFaceResources.getFontRegistry();
boldFont = registry.getBold(fontName);
}
}