package com.jetbrains.actionscript.profiler.livetable;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.pom.Navigatable;
import com.intellij.ui.treeStructure.treetable.TreeTableModel;
import com.intellij.util.Function;
import com.intellij.util.ui.ColumnInfo;
import com.jetbrains.actionscript.profiler.base.ColoredSortableTreeTable;
import com.jetbrains.actionscript.profiler.sampler.FrameInfo;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.text.NumberFormat;
import java.util.Comparator;
/**
* @author: Fedor.Korotkov
*/
public class LiveObjectsTreeTable extends ColoredSortableTreeTable implements DataProvider {
private Function<FrameInfo, Navigatable> frameLocationResolveFunction;
private Function<String, Navigatable> classNameLocationResolveFunction;
public LiveObjectsTreeTable(@Nullable Project project) {
super(getColumns(), project);
}
@Override
@Nullable
public Object getData(@NonNls String dataId) {
if (CommonDataKeys.NAVIGATABLE.is(dataId)) {
return navigatableSelectedItem();
}
return null;
}
@Nullable
private Navigatable navigatableSelectedItem() {
final TreePath path = getTree().getSelectionPath();
if (path == null) {
return null;
}
final Object component = path.getLastPathComponent();
if (component instanceof SizeInfoNode) {
return resolveNavigatable((SizeInfoNode)component);
}
return null;
}
@Nullable
private Navigatable resolveNavigatable(SizeInfoNode node) {
if (node.isMethod() && frameLocationResolveFunction != null) {
return frameLocationResolveFunction.fun(node.getFrameInfo());
}
else if (classNameLocationResolveFunction != null) {
return classNameLocationResolveFunction.fun(node.getQName());
}
return null;
}
public void setFrameLocationResolveFunction(Function<FrameInfo, Navigatable> function) {
frameLocationResolveFunction = function;
}
public void setClassNameLocationResolveFunction(Function<String, Navigatable> function) {
classNameLocationResolveFunction = function;
}
private static ColumnInfo[] getColumns() {
final ColumnInfo qnameColumn = new ColumnInfo("Class") {
@Override
public Class getColumnClass() {
return TreeTableModel.class;
}
@Override
public Object valueOf(final Object o) {
return o;
}
@Override
public Comparator<DefaultMutableTreeNode> getComparator() {
return new AbstractSizeNodeComparator() {
@Override
protected int compareInfo(SizeInfoNode si1, SizeInfoNode si2) {
if (si1.isMethod() && si2.isMethod()) {
return si1.getFrameInfo().compareTo(si2.getFrameInfo());
}
int result = si1.getClassName().compareTo(si2.getClassName());
if (result != 0 || si1.getPackageName() == null || si2.getPackageName() == null) {
return result;
}
return si1.getPackageName().compareTo(si2.getPackageName());
}
};
}
};
final ColumnInfo countColumn = new AbstractSizeColumnInfo("Count") {
@Override
protected String extractValueFromSizeInfoNode(SizeInfoNode value) {
return Integer.toString(value.getCount());
}
@Override
public Comparator<DefaultMutableTreeNode> getComparator() {
return new AbstractSizeNodeComparator() {
@Override
protected int compareInfo(SizeInfoNode si1, SizeInfoNode si2) {
return (int)Math.signum(si2.getCount() - si1.getCount());
}
};
}
};
final ColumnInfo sizeColumn = new AbstractSizeColumnInfo("Size, bytes") {
@Override
protected String extractValueFromSizeInfoNode(SizeInfoNode value) {
return NumberFormat.getInstance().format(value.getSize());
}
@Override
public Comparator<DefaultMutableTreeNode> getComparator() {
return new AbstractSizeNodeComparator() {
@Override
protected int compareInfo(SizeInfoNode si1, SizeInfoNode si2) {
return (int)Math.signum(si2.getSize() - si1.getSize());
}
};
}
};
return new ColumnInfo[]{qnameColumn, countColumn, sizeColumn};
}
private static abstract class AbstractSizeNodeComparator implements Comparator<DefaultMutableTreeNode> {
@Override
public int compare(DefaultMutableTreeNode o1, DefaultMutableTreeNode o2) {
SizeInfoNode si1 = o1 instanceof SizeInfoNode ? (SizeInfoNode)o1 : null;
SizeInfoNode si2 = o2 instanceof SizeInfoNode ? (SizeInfoNode)o2 : null;
return compareInfo(si1, si2);
}
protected abstract int compareInfo(SizeInfoNode ci1, SizeInfoNode ci2);
}
private static abstract class AbstractSizeColumnInfo extends ColumnInfo<DefaultMutableTreeNode, String> {
public AbstractSizeColumnInfo(String name) {
super(name);
}
@Override
public String valueOf(DefaultMutableTreeNode node) {
SizeInfoNode infoNode = node instanceof SizeInfoNode ? (SizeInfoNode)node : null;
return infoNode != null ? extractValueFromSizeInfoNode(infoNode) : "";
}
protected abstract String extractValueFromSizeInfoNode(SizeInfoNode value);
}
}