package org.basex.gui.view.table;
import static org.basex.core.Text.*;
import static org.basex.util.Token.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import org.basex.core.Context;
import org.basex.data.Data;
import org.basex.data.Nodes;
import org.basex.gui.GUI;
import org.basex.gui.GUIConstants;
import org.basex.gui.GUIConstants.Fill;
import org.basex.gui.GUIProp;
import org.basex.gui.layout.BaseXBack;
import org.basex.gui.layout.BaseXBar;
import org.basex.gui.layout.BaseXLayout;
import org.basex.util.TokenBuilder;
/**
* This is the content area of the table view.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
final class TableContent extends BaseXBack {
/** Scrollbar reference. */
private final BaseXBar scroll;
/** View reference. */
private final TableData tdata;
/** GUI reference. */
private final GUI gui;
/** Currently focused string. */
String focusedString;
/**
* Default constructor.
* @param d table data
* @param scr scrollbar reference
*/
TableContent(final TableData d, final BaseXBar scr) {
scroll = scr;
tdata = d;
gui = scr.gui;
layout(new BorderLayout());
mode(gui.gprop.is(GUIProp.GRADIENT) ? Fill.GRADIENT : Fill.NONE);
add(scroll, BorderLayout.EAST);
}
@Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
// skip if view is unavailable
if(tdata.rows == null) return;
gui.painting = true;
g.setFont(GUIConstants.font);
final int w = getWidth() - scroll.getWidth();
final int h = getHeight();
final int fsz = gui.gprop.num(GUIProp.FONTSIZE);
final Context context = tdata.context;
final Data data = context.data();
final int focus = gui.context.focused;
final int rfocus = tdata.getRoot(data, focus);
int mpos = 0;
final int nCols = tdata.cols.length;
final int nRows = tdata.rows.size();
final int rowH = tdata.rowH;
final TableIterator ti = new TableIterator(data, tdata);
final TokenBuilder[] tb = new TokenBuilder[nCols];
for(int i = 0; i < nCols; ++i) tb[i] = new TokenBuilder();
focusedString = null;
final Nodes marked = context.marked;
int l = scroll.pos() / rowH - 1;
int posY = -scroll.pos() + l * rowH;
while(++l < nRows && marked != null) {
// skip when all visible rows have been painted or if data has changed
if(posY > h || l >= tdata.rows.size()) break;
posY += rowH;
final int pre = tdata.rows.get(l);
while(mpos < marked.size() && marked.list[mpos] < pre) ++mpos;
// draw line
g.setColor(GUIConstants.color2);
g.drawLine(0, posY + rowH - 1, w, posY + rowH - 1);
g.setColor(Color.white);
g.drawLine(0, posY + rowH, w, posY + rowH);
// verify if current node is marked or focused
final boolean rm = mpos < marked.size() && marked.list[mpos] == pre;
final boolean rf = pre == rfocus;
final int col = rm ? rf ? 5 : 4 : 3;
if(rm || rf) {
g.setColor(GUIConstants.color(col));
g.fillRect(0, posY - 1, w, rowH);
g.setColor(GUIConstants.color(col + 4));
g.drawLine(0, posY - 1, w, posY - 1);
}
g.setColor(Color.black);
// skip drawing of text during animation
if(rowH < fsz) continue;
// find all row contents
ti.init(pre);
int fcol = -1;
while(ti.more()) {
final int c = ti.col;
if(ti.pre == focus || data.parent(ti.pre, data.kind(ti.pre)) == focus)
fcol = c;
// add content to column (skip too long contents)...
if(tb[c].size() < 100) {
if(tb[c].size() != 0) tb[c].add("; ");
tb[c].add(data.text(ti.pre, ti.text));
}
}
// add dots if content is too long
for(final TokenBuilder t : tb) if(t.size() > 100) t.add(DOTS);
// draw row contents
byte[] focusStr = null;
int fx = -1;
double x = 1;
for(int c = 0; c < nCols; ++c) {
// draw single column
final double cw = w * tdata.cols[c].width;
final double ce = x + cw;
if(ce != 0) {
final byte[] str = tb[c].size() != 0 ? tb[c].finish() : null;
if(str != null) {
if(tdata.mouseX > x && tdata.mouseX < ce || fcol == c) {
fx = (int) x;
focusStr = str;
}
BaseXLayout.chopString(g, str, (int) x + 1, posY + 2,
(int) cw - 4, fsz);
tb[c].reset();
}
}
x = ce;
}
// highlight focused entry
if(rf || fcol != -1) {
if(focusStr != null) {
final int sw = BaseXLayout.width(g, focusStr) + 8;
if(fx > w - sw - 2) fx = w - sw - 2;
g.setColor(GUIConstants.color(col + 2));
g.fillRect(fx - 2, posY, sw, rowH - 1);
g.setColor(Color.black);
BaseXLayout.chopString(g, focusStr, fx + 1, posY + 2, sw, fsz);
// cache focused string
focusedString = string(focusStr);
final int i = focusedString.indexOf("; ");
if(i != -1) focusedString = focusedString.substring(0, i);
}
}
}
gui.painting = false;
}
}