package rocks.inspectit.ui.rcp.editor.tree.input;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import rocks.inspectit.shared.all.cmr.model.MethodIdent;
import rocks.inspectit.shared.all.cmr.service.ICachedDataService;
import rocks.inspectit.shared.all.communication.data.ExceptionSensorData;
import rocks.inspectit.ui.rcp.InspectIT;
import rocks.inspectit.ui.rcp.InspectITImages;
import rocks.inspectit.ui.rcp.editor.inputdefinition.InputDefinition;
import rocks.inspectit.ui.rcp.editor.viewers.StyledCellIndexLabelProvider;
import rocks.inspectit.ui.rcp.formatter.TextFormatter;
import rocks.inspectit.ui.rcp.model.ExceptionImageFactory;
import rocks.inspectit.ui.rcp.model.ModifiersImageFactory;
/**
* This input controller displays the detail contents of {@link ExceptionSensorData} objects.
*
* @author Eduard Tudenhoefner
*
*/
public class ExceptionTreeInputController extends AbstractTreeInputController {
/**
* The ID of this subview / controller.
*/
public static final String ID = "inspectit.subview.tree.exceptiontree";
/**
* The list of {@link ExceptionSensorData} objects which is displayed.
*/
private List<ExceptionSensorData> exceptionSensorData = new ArrayList<>();
/**
* The resource manager is used for the images etc.
*/
private LocalResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources());
/**
* The private inner enumeration used to define the used IDs which are mapped into the columns.
* The order in this enumeration represents the order of the columns. If it is reordered,
* nothing else has to be changed.
*
* @author Eduard Tudenhoefner
*
*/
private static enum Column {
/** The event type column. */
EVENT_TYPE("Event Type", 280, null),
/** The method column. */
METHOD_CONSTRUCTOR("Method / Constructor", 500, InspectITImages.IMG_METHOD),
/** The error message column. */
ERROR_MESSAGE("Error Message", 250, null),
/** The cause column. */
CAUSE("Cause", 120, null);
/** The name. */
private String name;
/** The width of the column. */
private int width;
/** The image descriptor. Can be <code>null</code> */
private Image image;
/**
* Default constructor which creates a column enumeration object.
*
* @param name
* The name of the column.
* @param width
* The width of the column.
* @param imageName
* The name of the image. Names are defined in {@link InspectITImages}.
*/
private Column(String name, int width, String imageName) {
this.name = name;
this.width = width;
this.image = InspectIT.getDefault().getImage(imageName);
}
/**
* Converts an ordinal into a column.
*
* @param i
* The ordinal.
* @return The appropriate column.
*/
public static Column fromOrd(int i) {
if ((i < 0) || (i >= Column.values().length)) {
throw new IndexOutOfBoundsException("Invalid ordinal");
}
return Column.values()[i];
}
}
/**
* The cached service is needed because of the ID mappings.
*/
private ICachedDataService cachedDataService;
/**
* {@inheritDoc}
*/
@Override
public void setInputDefinition(InputDefinition inputDefinition) {
super.setInputDefinition(inputDefinition);
cachedDataService = inputDefinition.getRepositoryDefinition().getCachedDataService();
}
/**
* {@inheritDoc}
*/
@Override
public int getExpandLevel() {
return AbstractTreeViewer.ALL_LEVELS;
}
/**
* {@inheritDoc}
*/
@Override
public void createColumns(TreeViewer treeViewer) {
for (Column column : Column.values()) {
TreeViewerColumn viewerColumn = new TreeViewerColumn(treeViewer, SWT.NONE);
viewerColumn.getColumn().setMoveable(true);
viewerColumn.getColumn().setResizable(true);
viewerColumn.getColumn().setText(column.name);
viewerColumn.getColumn().setWidth(column.width);
if (null != column.image) {
viewerColumn.getColumn().setImage(column.image);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Object getTreeInput() {
return exceptionSensorData;
}
/**
* {@inheritDoc}
*/
@Override
public IContentProvider getContentProvider() {
return new ExceptionTreeContentProvider();
}
/**
* {@inheritDoc}
*/
@Override
public IBaseLabelProvider getLabelProvider() {
return new ExceptionTreeLabelProvider();
}
/**
* {@inheritDoc}
*/
@Override
public boolean canOpenInput(List<? extends Object> data) {
if (null == data) {
return false;
}
if (data.isEmpty()) {
return true;
}
if (!(data.get(0) instanceof ExceptionSensorData)) {
return false;
}
return true;
}
/**
* The exception tree details label provider for this view.
*
* @author Eduard Tudenhoefner
*
*/
private final class ExceptionTreeLabelProvider extends StyledCellIndexLabelProvider {
/**
* Creates the styled text.
*
* @param element
* The element to create the styled text for.
* @param index
* The index in the column.
* @return The created styled string.
*/
@Override
public StyledString getStyledText(Object element, int index) {
ExceptionSensorData data = (ExceptionSensorData) element;
MethodIdent methodIdent = cachedDataService.getMethodIdentForId(data.getMethodIdent());
Column enumId = Column.fromOrd(index);
return getStyledTextForColumn(data, methodIdent, enumId);
}
/**
* Returns the column image for the given element at the given index.
*
* @param element
* The element.
* @param index
* The index.
* @return Returns the Image.
*/
@Override
public Image getColumnImage(Object element, int index) {
ExceptionSensorData data = (ExceptionSensorData) element;
MethodIdent methodIdent = cachedDataService.getMethodIdentForId(data.getMethodIdent());
Column enumId = Column.fromOrd(index);
switch (enumId) {
case METHOD_CONSTRUCTOR:
Image image = ModifiersImageFactory.getImage(methodIdent.getModifiers());
image = ExceptionImageFactory.decorateImageWithException(image, data, resourceManager);
return image;
case EVENT_TYPE:
return null;
case ERROR_MESSAGE:
return null;
case CAUSE:
return null;
default:
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
protected Color getBackground(Object element, int index) {
return null;
}
}
/**
* Returns the styled text for a specific column.
*
* @param data
* The data object to extract the information from.
* @param methodIdent
* The method ident object.
* @param enumId
* The enumeration ID.
* @return The styled string containing the information from the data object.
*/
private static StyledString getStyledTextForColumn(ExceptionSensorData data, MethodIdent methodIdent, Column enumId) {
StyledString styledString = null;
switch (enumId) {
case METHOD_CONSTRUCTOR:
return new StyledString(TextFormatter.getMethodWithParameters(methodIdent));
case EVENT_TYPE:
styledString = new StyledString(data.getExceptionEvent().toString());
return styledString;
case ERROR_MESSAGE:
styledString = new StyledString();
if (null != data.getErrorMessage()) {
styledString.append(data.getErrorMessage());
}
return styledString;
case CAUSE:
styledString = new StyledString();
if (null != data.getCause()) {
styledString.append(data.getCause().toString());
}
return styledString;
default:
return styledString;
}
}
/**
* The exception tree details content provider for this view.
*
* @author Eduard Tudenhoefner
*
*/
private static final class ExceptionTreeContentProvider implements ITreeContentProvider {
/**
* {@inheritDoc}
*/
@Override
public Object[] getChildren(Object parent) {
ExceptionSensorData exceptionSensorData = (ExceptionSensorData) parent;
List<ExceptionSensorData> exceptionSensorDataList = new ArrayList<>();
exceptionSensorDataList.add(exceptionSensorData.getChild());
return exceptionSensorDataList.toArray();
}
/**
* {@inheritDoc}
*/
@Override
public Object getParent(Object child) {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasChildren(Object parent) {
if (parent == null) {
return false;
}
if (parent instanceof ExceptionSensorData) {
ExceptionSensorData exceptionSensorData = (ExceptionSensorData) parent;
if (null != exceptionSensorData.getChild()) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public Object[] getElements(Object inputElement) {
List<ExceptionSensorData> exceptionSensorData = (List<ExceptionSensorData>) inputElement;
return exceptionSensorData.toArray();
}
/**
* {@inheritDoc}
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
}
}
/**
* {@inheritDoc}
*/
@Override
public String getReadableString(Object object) {
if (object instanceof ExceptionSensorData) {
ExceptionSensorData data = (ExceptionSensorData) object;
StringBuilder sb = new StringBuilder();
MethodIdent methodIdent = cachedDataService.getMethodIdentForId(data.getMethodIdent());
for (Column column : Column.values()) {
sb.append(getStyledTextForColumn(data, methodIdent, column).toString());
sb.append('\t');
}
return sb.toString();
}
throw new RuntimeException("Could not create the human readable string!");
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getColumnValues(Object object) {
if (object instanceof ExceptionSensorData) {
ExceptionSensorData data = (ExceptionSensorData) object;
MethodIdent methodIdent = cachedDataService.getMethodIdentForId(data.getMethodIdent());
List<String> values = new ArrayList<>();
for (Column column : Column.values()) {
values.add(getStyledTextForColumn(data, methodIdent, column).toString());
}
return values;
}
throw new RuntimeException("Could not create the column values!");
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public Object[] getObjectsToSearch(Object treeInput) {
List<ExceptionSensorData> allObjects = new ArrayList<>();
List<ExceptionSensorData> exceptionSensorDataList = (List<ExceptionSensorData>) treeInput;
for (ExceptionSensorData exData : exceptionSensorDataList) {
ExceptionSensorData objectToAdd = exData;
while (null != objectToAdd) {
allObjects.add(objectToAdd);
objectToAdd = objectToAdd.getChild();
}
}
return allObjects.toArray();
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
resourceManager.dispose();
}
/**
* {@inheritDoc}
*/
@Override
public SubViewClassification getSubViewClassification() {
return SubViewClassification.SLAVE;
}
}