package com.onpositive.gae.profiler.ui;
import java.text.DecimalFormatSymbols;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import com.onpositive.commons.ui.viewers.DataColumn;
import com.onpositive.commons.ui.viewers.FilterMode;
import com.onpositive.commons.ui.viewers.ViewerConfiguration;
import com.onpositive.gae.profiler.IProfilerSnaphotModel;
import com.onpositive.gae.profiler.ITrace;
import com.onpositive.gae.profiler.SnapshotFilter;
import com.onpositive.gae.profiler.core.Snapshot;
public class ViewerConfigurationFactories {
private static TextLayout layout = new TextLayout(Display.getDefault());
private int fontSize;
protected static Color percentHotColor = new Color(Display.getDefault(),
190, 150, 150);
protected static Color hotColor = new Color(Display.getDefault(), 255, 0, 0);
protected static Color percentColor = new Color(Display.getDefault(), 160,
160, 160);
protected static Color ordinaryColor = new Color(Display.getDefault(), 0,
0, 0);
boolean isHot(double bl) {
return bl > 0.05;
}
private IProfilerSnaphotModel snapshot;
{
layout.setText(" 100,00%");
fontSize = layout.getBounds().width;
}
public ViewerConfigurationFactories(IProfilerSnaphotModel snapshot) {
this.snapshot = snapshot;
}
private static final char DECIMAL_SEPARATOR = new DecimalFormatSymbols()
.getDecimalSeparator();
public static String getNumberString(long number) {
StringBuffer buf = new StringBuffer();
getNumberString(number, buf);
return buf.toString();
}
public static void getNumberString(long number, StringBuffer buf) {
long currentNumber = number;
while (currentNumber >= 1000) {
long per = currentNumber % 1000;
StringBuffer pref = new StringBuffer();
if (per < 10)
pref.append(" 00");
else if (per < 100)
pref.append(" 0");
else
pref.append(" ");
pref.append(per);
buf.insert(0, pref);
currentNumber /= 1000;
}
buf.insert(0, currentNumber);
}
public static String getNumberString(double number) {
long num = (long) (number * 100);
long rest = num % 100;
if (rest < 0)
rest *= -1;
long high = num / 100;
StringBuffer buf = new StringBuffer();
getNumberString(high, buf);
buf.append(DECIMAL_SEPARATOR);
if (rest < 10)
buf.append("0");
buf.append(rest);
return buf.toString();
}
public static String getPercentNumberString(double number) {
long num = (long) (number * 100);
long rest = num % 100;
if (rest < 0)
rest *= -1;
long high = num / 100;
StringBuffer buf = new StringBuffer();
getNumberString(high, buf);
int km = buf.length();
StringBuffer less = new StringBuffer();
less.append(DECIMAL_SEPARATOR);
if (rest < 10)
less.append("0");
less.append(rest);
if (km <= 2) {
buf.append(less);
} else {
int d = km - 2;
if (less.length() - d > 1) {
buf.append(less.substring(0, less.length() - d));
}
}
buf.append('%');
return buf.toString();
}
private abstract class PercentColumn extends DataColumn {
private PercentColumn(int minSizeChar, String name, String tooltip,
int weight, boolean isInt) {
super(minSizeChar, name, tooltip, weight);
this.isInt = isInt;
}
boolean isInt;
abstract double getValue(ITrace tr);
abstract double getTotalValue();
protected void paint(Event event) {
ITrace tr = (ITrace) event.item.getData();
if (tr == null) {
return;
}
double selfTime2 = getValue(tr);
if (selfTime2 == Double.MIN_VALUE) {
return;
}
double selfTime = !isInt ? (selfTime2) : selfTime2;
String text = !isInt ? (getNumberString(selfTime))
: (getNumberString((int) (selfTime)));
Rectangle r = event.gc.getClipping();
boolean isHot = false;
if (snapshot != null) {
double totalExecutionTime = getTotalValue();
double pc = selfTime2 / totalExecutionTime;
isHot = isHot(pc);
String percentNumberString = getPercentNumberString(pc * 100);
int we = 4;
for (int a = 0; a < percentNumberString.length(); a++) {
we += event.gc.getCharWidth(percentNumberString.charAt(a));
}
int position = r.x + r.width - we;
event.gc.setForeground(isHot ? percentHotColor : percentColor);
event.gc.drawText(percentNumberString, position, event.y);
}
layout.setText(text);
Rectangle cm = layout.getBounds();
event.gc.setForeground(isHot ? hotColor : ordinaryColor);
layout.draw(event.gc, r.x + r.width - fontSize - cm.width - 4,
event.y);
}
protected int compare(Object obj1, Object obj2) {
ITrace tr1 = (ITrace) obj1;
ITrace tr2 = (ITrace) obj2;
double d = getValue(tr1) - getValue(tr2);
int d2 = d > 0 ? 1 : -1;
if (d == 0) {
d2 = 0;
}
return -(d2 != 0 ? d2 : tr1.getName().compareTo(tr2.getName()));
}
}
private abstract class UsualColumn extends DataColumn {
private UsualColumn(int minSizeChar, String name, String tooltip,
int weight, boolean isInt) {
super(minSizeChar, name, tooltip, weight);
this.isInt = isInt;
}
abstract double getValue(ITrace tr);
boolean isInt;
protected void paint(Event event) {
ITrace tr = (ITrace) event.item.getData();
if (tr == null) {
return;
}
double selfTime2 = getValue(tr);
double selfTime = selfTime2;
String text = !isInt ? (getNumberString(selfTime))
: getNumberString((int) selfTime);
Rectangle r = event.gc.getClipping();
boolean isHot = false;
isHot = isHot(tr);
layout.setText(text);
Rectangle cm = layout.getBounds();
event.gc.setForeground(isHot ? hotColor : ordinaryColor);
layout.draw(event.gc, r.x + r.width - cm.width - 4, event.y);
}
public abstract boolean isHot(ITrace tr);
protected int compare(Object obj1, Object obj2) {
ITrace tr1 = (ITrace) obj1;
ITrace tr2 = (ITrace) obj2;
double d = getValue(tr1) - getValue(tr2);
int d2 = d > 0 ? 1 : -1;
if (d == 0) {
d2 = 0;
}
return -(d2 != 0 ? d2 : tr1.getName().compareTo(tr2.getName()));
}
}
DataColumn countColumn = new UsualColumn(30, "Call Count", "Call Count", 1,
true) {
public double getValue(ITrace tr) {
return tr.getCount();
}
public boolean isHot(ITrace tr) {
return false;
}
};
DataColumn totalTime = new PercentColumn(15, "Total time",
"Total time performed in method and its callees", 1, false) {
protected void paint(Event event) {
super.paint(event);
}
public double getTotalValue() {
return snapshot.getTotalValue();
}
public double getValue(ITrace tr) {
return tr.getTotalTime();
}
};
DataColumn selfTime = new PercentColumn(
15,
"Self time",
"Self time performed in method without time performed in its callees",
1, false) {
public double getTotalValue() {
return snapshot.getTotalValue();
}
public double getValue(ITrace tr) {
return tr.getSelfTime();
}
};
DataColumn cpuTime = new PercentColumn(
15,
"API Time",
"Total API time in this method and in its callees",
1, false) {
public double getTotalValue() {
return ((Snapshot)snapshot).getApiTotal();
}
public double getValue(ITrace tr) {
return tr.getApiTotalTime()/1.2;
}
};
FilterMode[] defaultMode = new FilterMode[] {
new FilterMode("Invocation count", "at least",
SnapshotFilter.KIND_INVOCATION_COUNT),
new FilterMode("Self time", "at least (ms)",
SnapshotFilter.KIND_SELF_TIME),
new FilterMode("Total time", "at least (ms)",
SnapshotFilter.KIND_CUMMULATIVE_TIME) };
public ViewerConfiguration getMethodListConfiguration() {
return new ViewerConfiguration("Method List", "",
new MethodListContentProvider(), defaultMode, false, false,
new DataColumn[] { countColumn, totalTime, selfTime ,cpuTime});
}
public ViewerConfiguration getCallGraphConfiguration() {
return new ViewerConfiguration("Call tree", "",
new CallTreeContentProvider(), defaultMode, true, false,
new DataColumn[] { countColumn, totalTime, cpuTime });
}
public ViewerConfiguration getPackageTreeConfiguration() {
return new ViewerConfiguration("Package Tree", "",
new HierarchyContentProvider(), defaultMode, true, false,
new DataColumn[] { countColumn, totalTime, selfTime });
}
public void setActiveConfig(ViewerConfiguration config) {
}
}