001: /*
002: * This is free software, licensed under the Gnu Public License (GPL)
003: * get a copy from <http://www.gnu.org/licenses/gpl.html>
004: * $Id: TableRenderer.java,v 1.7 2005/06/18 04:58:13 hzeller Exp $
005: * author: Henner Zeller <H.Zeller@acm.org>
006: */
007: package henplus.view;
008:
009: import henplus.OutputDevice;
010:
011: import java.util.ArrayList;
012: import java.util.List;
013: import java.util.Iterator;
014:
015: /**
016: * document me.
017: */
018: public class TableRenderer {
019:
020: private static final int MAX_CACHE_ELEMENTS = 500;
021:
022: private final List cacheRows;
023: private boolean alreadyFlushed;
024: private int writtenRows;
025: private int separatorWidth;
026:
027: private boolean enableHeader;
028: private boolean enableFooter;
029:
030: protected final ColumnMetaData meta[];
031: protected final OutputDevice out;
032: protected final String colSeparator;
033:
034: public TableRenderer(ColumnMetaData[] meta, OutputDevice out,
035: String separator, boolean enableHeader, boolean enableFooter) {
036: this .meta = meta;
037: this .out = out;
038: this .enableHeader = enableHeader;
039: this .enableFooter = enableFooter;
040:
041: /*
042: * we cache the rows in order to dynamically determine the
043: * output width of each column.
044: */
045: this .cacheRows = new ArrayList(MAX_CACHE_ELEMENTS);
046: this .alreadyFlushed = false;
047: this .writtenRows = 0;
048: this .colSeparator = " " + separator;
049: this .separatorWidth = separator.length();
050: }
051:
052: public TableRenderer(ColumnMetaData[] meta, OutputDevice out) {
053: this (meta, out, "|", true, true);
054: }
055:
056: public void addRow(Column[] row) {
057: updateColumnWidths(row);
058: addRowToCache(row);
059: }
060:
061: protected void addRowToCache(Column[] row) {
062: cacheRows.add(row);
063: if (cacheRows.size() >= MAX_CACHE_ELEMENTS) {
064: flush();
065: cacheRows.clear();
066: }
067: }
068:
069: /**
070: * return the meta data that is used to display this table.
071: */
072: public ColumnMetaData[] getMetaData() {
073: return meta;
074: }
075:
076: /**
077: * Overwrite this method if you need to handle customized columns.
078: * @param row
079: */
080: protected void updateColumnWidths(Column[] row) {
081: for (int i = 0; i < meta.length; ++i) {
082: row[i].setAutoWrap(meta[i].getAutoWrap());
083: meta[i].updateWidth(row[i].getWidth());
084: }
085: }
086:
087: public void closeTable() {
088: flush();
089: if (writtenRows > 0 && enableFooter) {
090: printHorizontalLine();
091: }
092: }
093:
094: /**
095: * flush the cached rows.
096: */
097: public void flush() {
098: if (!alreadyFlushed) {
099: if (enableHeader) {
100: printTableHeader();
101: }
102: alreadyFlushed = true;
103: }
104: Iterator rowIterator = cacheRows.iterator();
105: while (rowIterator.hasNext()) {
106: Column[] currentRow = (Column[]) rowIterator.next();
107: boolean hasMoreLines;
108: do {
109: hasMoreLines = false;
110: hasMoreLines = printColumns(currentRow, hasMoreLines);
111: out.println();
112: } while (hasMoreLines);
113: ++writtenRows;
114: }
115: }
116:
117: protected boolean printColumns(Column[] currentRow,
118: boolean hasMoreLines) {
119: for (int i = 0; i < meta.length; ++i) {
120: if (!meta[i].doDisplay())
121: continue;
122: hasMoreLines = printColumn(currentRow[i], hasMoreLines, i);
123: }
124: return hasMoreLines;
125: }
126:
127: protected boolean printColumn(Column col, boolean hasMoreLines,
128: int i) {
129: String txt;
130: out.print(" ");
131: txt = formatString(col.getNextLine(), ' ', meta[i].getWidth(),
132: meta[i].getAlignment());
133: hasMoreLines |= col.hasNextLine();
134: if (col.isNull())
135: out.attributeGrey();
136: out.print(txt);
137: if (col.isNull())
138: out.attributeReset();
139: out.print(colSeparator);
140: return hasMoreLines;
141: }
142:
143: private void printHorizontalLine() {
144: for (int i = 0; i < meta.length; ++i) {
145: if (!meta[i].doDisplay())
146: continue;
147: String txt;
148: txt = formatString("", '-', meta[i].getWidth()
149: + separatorWidth + 1, ColumnMetaData.ALIGN_LEFT);
150: out.print(txt);
151: out.print("+");
152: }
153: out.println();
154: }
155:
156: private void printTableHeader() {
157: printHorizontalLine();
158: for (int i = 0; i < meta.length; ++i) {
159: if (!meta[i].doDisplay())
160: continue;
161: String txt;
162: txt = formatString(meta[i].getLabel(), ' ', meta[i]
163: .getWidth() + 1, ColumnMetaData.ALIGN_CENTER);
164: out.attributeBold();
165: out.print(txt);
166: out.attributeReset();
167: out.print(colSeparator);
168: }
169: out.println();
170: printHorizontalLine();
171: }
172:
173: protected String formatString(String text, char fillchar, int len,
174: int alignment) {
175: // System.out.println("[formatString] len: " + len + ", text.length: " + text.length());
176: // text = "hi";
177: StringBuffer fillstr = new StringBuffer();
178:
179: if (len > 4000) {
180: len = 4000;
181: }
182:
183: if (text == null) {
184: text = "[NULL]";
185: }
186: int slen = text.length();
187:
188: if (alignment == ColumnMetaData.ALIGN_LEFT) {
189: fillstr.append(text);
190: }
191: int fillNumber = len - slen;
192: int boundary = 0;
193: if (alignment == ColumnMetaData.ALIGN_CENTER) {
194: boundary = fillNumber / 2;
195: }
196: while (fillNumber > boundary) {
197: fillstr.append(fillchar);
198: --fillNumber;
199: }
200: if (alignment != ColumnMetaData.ALIGN_LEFT) {
201: fillstr.append(text);
202: }
203: while (fillNumber > 0) {
204: fillstr.append(fillchar);
205: --fillNumber;
206: }
207: return fillstr.toString();
208: }
209: }
210:
211: /*
212: * Local variables:
213: * c-basic-offset: 4
214: * compile-command: "ant -emacs -find build.xml"
215: * End:
216: */
|