package com.jetbrains.actionscript.profiler.calltreetable; 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.ui.ColumnInfo; import com.jetbrains.actionscript.profiler.ProfilerBundle; import com.jetbrains.actionscript.profiler.base.ColoredSortableTreeTable; import com.jetbrains.actionscript.profiler.base.NavigatableDataProducer; import com.jetbrains.actionscript.profiler.vo.CallInfo; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import javax.swing.tree.DefaultMutableTreeNode; import java.util.Comparator; public class CallTreeTable extends ColoredSortableTreeTable implements DataProvider { public CallTreeTable(@Nullable Project project) { super(getHotSpotsColumns(), project); } @Override @Nullable public Object getData(@NonNls String dataId) { if (CommonDataKeys.NAVIGATABLE.is(dataId)) { return getSelectedNavigableItem(); } return null; } @Nullable private Navigatable getSelectedNavigableItem() { Object value = getSelectedValue(); if (value instanceof NavigatableDataProducer) { return ((NavigatableDataProducer)value).getNavigatable(); } return null; } @Nullable public Object getSelectedValue() { int row = getSelectedRow(); if (row < 0 || row >= getRowCount()) { return null; } int column = Math.max(0, getSelectedColumn()); return getValueAt(row, column); } private static ColumnInfo[] getHotSpotsColumns() { final ColumnInfo methodsColumn = new ColumnInfo("Methods") { @Override public Class getColumnClass() { return TreeTableModel.class; } @Override public Object valueOf(final Object o) { return o; } @Override public Comparator getComparator() { return new FrameNameComparator(); } }; final ColumnInfo countColumn = new AbstractCallColumnInfo("Cumulative time, ms") { @Override public Comparator<DefaultMutableTreeNode> getComparator() { return new CumulativeTimeComparator(); } @Override protected long extractValueFromCallInfo(CallInfo value) { return value.getCumulativeTime(); } }; final ColumnInfo selfColumn = new AbstractCallColumnInfo("Self time, ms") { @Override public Comparator<DefaultMutableTreeNode> getComparator() { return new SelfTimeComparator(); } @Override protected long extractValueFromCallInfo(CallInfo value) { return value.getSelfTime(); } }; return new ColumnInfo[]{methodsColumn, countColumn, selfColumn}; } private static class FrameNameComparator extends AbstractTreeNodeComparator { @Override public int compareInfo(CallInfo a, CallInfo b) { return a.getFrameInfo().compareTo(b.getFrameInfo()); } } private static class CumulativeTimeComparator extends AbstractTreeNodeComparator { @Override public int compareInfo(CallInfo a, CallInfo b) { return (int)Math.signum(b.getCumulativeTime() - a.getCumulativeTime()); } } private static class SelfTimeComparator extends AbstractTreeNodeComparator { @Override public int compareInfo(CallInfo a, CallInfo b) { return (int)Math.signum(b.getSelfTime() - a.getSelfTime()); } } private static abstract class AbstractTreeNodeComparator implements Comparator<DefaultMutableTreeNode> { @Override public int compare(DefaultMutableTreeNode o1, DefaultMutableTreeNode o2) { CallInfo ci1 = o1.getUserObject() instanceof CallInfo ? (CallInfo)o1.getUserObject() : null; CallInfo ci2 = o2.getUserObject() instanceof CallInfo ? (CallInfo)o2.getUserObject() : null; return compareInfo(ci1, ci2); } protected abstract int compareInfo(CallInfo ci1, CallInfo ci2); } private static abstract class AbstractCallColumnInfo extends ColumnInfo<DefaultMutableTreeNode, String> { private static final long MS_IN_MICROSECOND = 1000; public AbstractCallColumnInfo(String name) { super(name); } @Override public String valueOf(DefaultMutableTreeNode o) { final MergedCallNode node = o instanceof MergedCallNode ? (MergedCallNode)o : null; final CallInfo info = node != null ? node.getCallInfo() : null; return info != null ? getDisplayValue(extractValueFromCallInfo(info)) : ""; } protected abstract long extractValueFromCallInfo(CallInfo value); private static String getDisplayValue(long value) { if (value > 1000) { return Long.toString(value / MS_IN_MICROSECOND); } return ProfilerBundle.message("less.one.ms"); } } }