package org.basex.gui.view.info;
import static org.basex.core.Text.*;
import static org.basex.gui.GUIConstants.*;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import org.basex.core.Command;
import org.basex.core.Prop;
import org.basex.core.cmd.XQuery;
import org.basex.gui.GUIProp;
import org.basex.gui.GUIConstants.Fill;
import org.basex.gui.layout.BaseXBack;
import org.basex.gui.layout.BaseXLabel;
import org.basex.gui.layout.BaseXEditor;
import org.basex.gui.view.View;
import org.basex.gui.view.ViewNotifier;
import org.basex.util.Performance;
import org.basex.util.TokenBuilder;
import org.basex.util.list.IntList;
import org.basex.util.list.StringList;
/**
* This view displays query information.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class InfoView extends View {
/** Old text. */
private final TokenBuilder text = new TokenBuilder();
/** Header label. */
private final BaseXLabel header;
/** Timer label. */
private final BaseXLabel timer;
/** North label. */
private final BaseXBack north;
/** Text Area. */
private final BaseXEditor area;
/** Query statistics. */
private IntList stat = new IntList();
/** Query statistics strings. */
private StringList strings;
/** Focused bar. */
private int focus = -1;
/** Panel Width. */
private int w;
/** Panel Height. */
private int h;
/** Bar widths. */
private int bw;
/** Bar size. */
private int bs;
/**
* Default constructor.
* @param man view manager
*/
public InfoView(final ViewNotifier man) {
super(INFOVIEW, man);
border(6, 6, 6, 6).layout(new BorderLayout());
north = new BaseXBack(Fill.NONE).layout(new BorderLayout());
header = new BaseXLabel(QUERY_INFO);
north.add(header, BorderLayout.NORTH);
north.add(header, BorderLayout.NORTH);
timer = new BaseXLabel(" ", true, false);
north.add(timer, BorderLayout.SOUTH);
add(north, BorderLayout.NORTH);
area = new BaseXEditor(false, gui);
add(area, BorderLayout.CENTER);
refreshLayout();
}
@Override
public void refreshInit() { }
@Override
public void refreshFocus() { }
@Override
public void refreshMark() { }
@Override
public void refreshContext(final boolean more, final boolean quick) { }
@Override
public void refreshUpdate() { }
@Override
public void refreshLayout() {
header.setFont(lfont);
timer.setFont(font);
area.setFont(font);
}
@Override
public boolean visible() {
return gui.gprop.is(GUIProp.SHOWINFO);
}
@Override
public void visible(final boolean v) {
gui.gprop.set(GUIProp.SHOWINFO, v);
}
@Override
protected boolean db() {
return false;
}
/**
* Displays the specified information.
* @param info info string
* @param cmd command string
* @param time time needed
* @param ok flag indicating if command execution was successful
*/
public void setInfo(final String info, final Command cmd,
final String time, final boolean ok) {
final StringList eval = new StringList();
final StringList comp = new StringList();
final StringList plan = new StringList();
final StringList sl = new StringList();
final StringList stats = new StringList();
final IntList il = new IntList();
String err = "";
String qu = "";
String res = "";
final String[] split = info.split(NL);
for(int i = 0; i < split.length; ++i) {
final String line = split[i];
final int s = line.indexOf(':');
if(line.startsWith(PARSING_CC) || line.startsWith(COMPILING_CC) ||
line.startsWith(EVALUATING_CC) || line.startsWith(PRINTING_CC) ||
line.startsWith(TOTAL_TIME_CC)) {
final int t = line.indexOf(" ms");
sl.add(line.substring(0, s).trim());
il.add((int) (Double.parseDouble(line.substring(s + 1, t)) * 100));
} else if(line.startsWith(QUERY_C)) {
qu = line.substring(s + 1).trim();
} else if(line.startsWith(QUERY_PLAN_C)) {
while(++i < split.length && !split[i].isEmpty()) plan.add(split[i]);
--i;
} else if(line.startsWith(COMPILING_C)) {
while(++i < split.length && !split[i].isEmpty()) comp.add(split[i]);
} else if(line.startsWith(RESULT_C)) {
res = line.substring(s + 1).trim();
} else if(line.startsWith(EVALUATING_C)) {
while(split[++i].startsWith(QUERYSEP)) eval.add(split[i]);
--i;
} else if(!ok) {
err += line + NL;
} else if(line.startsWith(HITS_X_CC) || line.startsWith(UPDATED_CC)
|| line.startsWith(PRINTED_CC)) {
stats.add("- " + line);
}
}
stat = il;
strings = sl;
String total = time;
final boolean q = cmd instanceof XQuery;
if(!ok || !q) {
text.bold();
if(q) {
add(QUERY_C + ' ', cmd.toString().replaceAll("^.*? ", "").trim());
} else if(cmd != null) {
text.bold().add(COMMAND + COLS).norm().addExt(cmd).nline();
}
if(ok) {
text.add(info).nline();
} else {
add(COMPILING_C, comp);
add(QUERY_PLAN_C, plan);
add(ERROR_C, err.replaceAll(STOPPED_AT + ".*\\r?\\n", ""));
}
} else if(sl.size() != 0) {
text.reset();
add(EVALUATING_C, eval);
add(QUERY_C + ' ', qu);
add(COMPILING_C, comp);
if(comp.size() != 0) add(RESULT_C, res);
add(TIMING_C, sl);
add(RESULT_C, stats);
add(QUERY_PLAN_C, plan);
final int runs = Math.max(1, gui.context.prop.num(Prop.RUNS));
total = Performance.getTimer(il.get(il.size() - 1) * 10000L * runs, runs);
}
area.setText(text.finish());
if(total != null) timer.setText(TOTAL_TIME_CC + total);
repaint();
}
/**
* Resets the info string without repainting the view.
*/
public void reset() {
text.reset();
}
/**
* Adds the specified strings.
* @param head string header
* @param list list reference
*/
private void add(final String head, final StringList list) {
final int runs = Math.max(1, gui.context.prop.num(Prop.RUNS));
if(list.size() == 0) return;
text.bold().add(head).norm().nline();
final int is = list.size();
for(int i = 0; i < is; ++i) {
String line = list.get(i);
if(list == strings) line = ' ' + QUERYSEP + line + ": " +
Performance.getTimer(stat.get(i) * 10000L * runs, runs);
text.add(line).nline();
}
text.hline();
}
/**
* Adds a string.
* @param head string header
* @param txt text
*/
private void add(final String head, final String txt) {
if(txt.isEmpty()) return;
text.bold().add(head).norm().add(txt).nline().hline();
}
@Override
public void mouseMoved(final MouseEvent e) {
final int l = stat.size();
if(l == 0) return;
focus = -1;
if(e.getY() < h) {
for(int i = 0; i < l; ++i) {
final int bx = w - bw + bs * i;
if(e.getX() >= bx && e.getX() < bx + bs) focus = i;
}
}
final int runs = Math.max(1, gui.context.prop.num(Prop.RUNS));
final int f = focus == -1 ? l - 1 : focus;
timer.setText(strings.get(f) + COLS +
Performance.getTimer(stat.get(f) * 10000L * runs, runs));
repaint();
}
@Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
final int l = stat.size();
if(l == 0) return;
h = north.getHeight();
w = getWidth() - 8;
bw = gui.gprop.num(GUIProp.FONTSIZE) * 2 + w / 10;
bs = bw / (l - 1);
// find maximum value
int m = 0;
for(int i = 0; i < l - 1; ++i) m = Math.max(m, stat.get(i));
// draw focused bar
final int by = 10;
final int bh = h - by;
for(int i = 0; i < l - 1; ++i) {
if(i != focus) continue;
final int bx = w - bw + bs * i;
g.setColor(color3);
g.fillRect(bx, by, bs + 1, bh);
}
// draw all bars
for(int i = 0; i < l - 1; ++i) {
final int bx = w - bw + bs * i;
g.setColor(color((i == focus ? 3 : 2) + i * 2));
final int p = Math.max(1, stat.get(i) * bh / m);
g.fillRect(bx, by + bh - p, bs, p);
g.setColor(color(8));
g.drawRect(bx, by + bh - p, bs, p - 1);
}
}
}