package edu.berkeley.nlp.ui; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; import edu.berkeley.nlp.util.Counter; import edu.berkeley.nlp.util.Pair; import edu.berkeley.nlp.util.StrUtils; public class Table { // row -> column -> entry private final Map<Pair<Integer, Integer>, String[]> entries = new HashMap<Pair<Integer, Integer>, String[]>(); private final Counter<Integer> maxHeights = new Counter<Integer>(), maxWidths = new Counter<Integer>(); private int nColumns, nRows; public Table(Populator populator) { populator.setTable(this); populator.populate(); } public static abstract class Populator { private void setTable(Table table) { this.table = table; } private Table table; private DecimalFormat fmt = EasyFormat.getStdFormat(); public Populator() { } public Populator(DecimalFormat fmt) { this.fmt = fmt; } public abstract void populate(); public final void set(int row, int column, double number) { set(row, column, fmt.format(number)); } public final void set(int row, int column, String text) { table.nColumns = Math.max(table.nColumns, column + 1); table.nRows = Math.max(table.nRows, row + 1); String[] lines = text.split("\\n"); table.maxHeights.setCount(row, Math.max(table.maxHeights.getCount(row), lines.length)); for (String line : lines) table.maxWidths.setCount(column, Math.max(table.maxWidths.getCount(column), line.length())); table.entries.put(new Pair<Integer, Integer>(row, column), lines); } /** append at the end of the last line */ public final void append(int row, int column, String text) { String[] entries = table.entries.get(new Pair<Integer, Integer>(row, column)); String lastEntry = (entries != null ? entries[entries.length - 1] : null); set(row, column, (lastEntry != null ? lastEntry : "") + text); } public final void addLines(int row, int column, String text) { Pair<Integer, Integer> key = new Pair<Integer, Integer>(row, column); String currentString = StrUtils.join(table.entries.get(key), "\n"); if (!currentString.equals("")) currentString = currentString + "\n"; currentString += text; set(row, column, currentString); } } private boolean borderDefault = true; public void setBorder(boolean value) { this.borderDefault = value; } @Override public String toString() { return toString(borderDefault); } public String toHTML() { return toHTML(borderDefault); } public String toHTML(boolean printBorders) { StringBuilder builder = new StringBuilder(); builder.append("<table class=\"" + (printBorders ? "with-borders" : "without-borders") + "\">"); for (int row = 0; row < nRows; row++) { builder.append("<tr>"); for (int col = 0; col < nColumns; col++) { builder.append("<td>"); Pair<Integer, Integer> key = new Pair<Integer, Integer>(row, col); String[] entry = entries.get(key); if (entry != null) for (int i = 0; i < entry.length; i++) builder.append(entry[i] + (i < entry.length - 1 ? "<br/>" : "") + ""); builder.append("</td>"); } builder.append("</tr>"); } builder.append("</table>\n"); return builder.toString(); } public static final String css = "table.with-borders {" + "border-width: 1px 1px 1px 1px;" + "border-spacing: 2px;" + "border-style: solid solid solid solid;" + "border-color: black black black black;" + "border-collapse: collapse;" + "background-color: white;" + "}" + "table.with-borders td {" + "border-width: 1px 1px 1px 1px;" + "padding: 1px 1px 1px 1px;" + "border-style: dotted dotted dotted dotted;" + "border-color: gray gray gray gray;" + "background-color: white;" + "-moz-border-radius: 0px 0px 0px 0px;" + "}" + "table.without-borders {" + "border-width: 1px 1px 1px 1px;" + "border-spacing: 2px;" + "border-style: none none none none;" + "border-collapse: collapse;" + "background-color: white;" + "}" + "table.without-borders td {" + "border-width: 1px 1px 1px 1px;" + "padding: 1px 1px 1px 1px;" + "border-style: none none none none;" + "background-color: white;" + "-moz-border-radius: 0px 0px 0px 0px;" + "}"; public String toString(boolean printBorders) { StringBuilder builder = new StringBuilder(); // top border if (printBorders) builder.append(horizontalSeparator() + "\n"); for (int row = 0; row < nRows; row++) { for (int rowLine = 0; rowLine < maxHeights.getCount(row); rowLine++) { // left border if (printBorders) builder.append("|"); for (int col = 0; col < nColumns; col++) { Pair<Integer, Integer> key = new Pair<Integer, Integer>(row, col); String text = (entries.get(key) == null || rowLine >= entries.get(key).length ? "" : entries.get(key)[rowLine]); builder.append(pad(text, (int) maxWidths.getCount(col), " ")); if (printBorders) builder.append("|"); } if (rowLine != maxHeights.getCount(row) - 1) builder.append("\n"); } if (printBorders) builder.append("\n" + horizontalSeparator()); builder.append("\n"); } return builder.toString(); } private StringBuilder horizontalSeparator() { StringBuilder builder = new StringBuilder(); builder.append("+"); for (int col = 0; col < nColumns; col++) builder.append(pad("", (int) maxWidths.getCount(col), "-") + "+"); return builder; } private String pad(String s, int finalLength, String pad) { if (s.length() > finalLength) throw new RuntimeException(); StringBuilder b = new StringBuilder(); b.append(s); while (b.length() < finalLength) b.append(pad); return b.toString(); } public static void main(String[] args) { Table table = new Table(new Populator() { @Override public void populate() { for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) if (i <= j) addLines(i, j, "Sum:" + (i + j)); for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) if (i <= j) addLines(i, j, "Prod:" + (i * j)); } }); System.out.println(table.toString()); //System.out.println(table.toHTML(false)); } }