001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Emmanuel Cecchet.
020: * Contributor(s): ______________________.
021: */package org.continuent.sequoia.console.text.formatter;
022:
023: /**
024: * Utility class to format a table which can be pretty displayed in the text console.
025: *
026: * @author <a href="mailto:jeff.mesnil@emicnetworks.com">Jeff Mesnil</a>
027: */
028: public class TableFormatter {
029: /**
030: * Format as a table.
031: *
032: * @param headers the headers of the table
033: * @param cells the cells of the table
034: * @param headersAsRow <code>true</code> if the headers must be displayed on the same row,
035: * <code>false</code> if the headers must be displayed on the same column
036: *
037: * @return a String representing a pretty formatted table
038: */
039: public static String format(String[] headers, String[][] cells,
040: boolean headersAsRow) {
041: StringBuffer buf = new StringBuffer();
042: int[] longestLengths = findLongestDataLengths(headers, cells,
043: headersAsRow);
044: String horizontalRule = createHorizontalRule(longestLengths);
045: if (headersAsRow) {
046: buf.append(horizontalRule);
047: appendHeadersTo(headers, buf, longestLengths);
048: buf.append(horizontalRule);
049: appendCellsTo(cells, buf, longestLengths);
050: buf.append(horizontalRule);
051: } else {
052: appendHeaderAndCells(headers, cells, buf, longestLengths,
053: horizontalRule);
054: }
055: return buf.toString();
056:
057: }
058:
059: /**
060: * Create an horizontal rule following the format:
061: * <code>+-----+-------+-----+</code>
062: * where the size of each part is determinged based on the longest length
063: * for each column
064: *
065: * @param longestLengths an array of int corresponding to the longest length of cells for a given column
066: *
067: * @return a <code>String</code> to used as an horizontal rule
068: */
069: private static String createHorizontalRule(int[] longestLengths) {
070: StringBuffer buf = new StringBuffer("+");
071: for (int i = 0; i < longestLengths.length; i++) {
072: // we add 2 to the longest length for each column to put one
073: // space before and after any cell content
074: appendStringTo(buf, "-", longestLengths[i] + 2);
075: buf.append("+");
076: }
077: buf.append("\n");
078: return buf.toString();
079: }
080:
081: /**
082: * Append <code>n</code> times the <code>string</code> to <code>buf</code>.
083: *
084: * @param buf a <code>StringBuffer</code>
085: * @param string the <code>String</code> to append
086: * @param n the number of times the string should be appended
087: */
088: private static void appendStringTo(StringBuffer buf, String string,
089: int n) {
090: for (int i = 0; i < n; i++) {
091: buf.append(string);
092: }
093: }
094:
095: /**
096: * Find the longest lengths for the data.
097: * Used internally to create an horizontal rule and to
098: * append whitespaces in each cell so that everything
099: * is propertly formatted.
100: *
101: * @param headers headers of the table
102: * @param cells cells of the table
103: * @param headersAsRow <code>true</code> if the headers must be displayed on the same row,
104: * <code>false</code> if the headers must be displayed on the same column
105: *
106: * @return an array of <code>int</code> containing the longest length for each column
107: */
108: private static int[] findLongestDataLengths(String[] headers,
109: String[][] cells, boolean headersAsRow) {
110: if (headersAsRow) {
111: // there is has much columns as heafers.length
112: int[] longestLengths = new int[headers.length];
113: for (int j = 0; j < longestLengths.length; j++) {
114: int maxLength = 0;
115: maxLength = Math.max(maxLength, headers[j].length());
116: for (int i = 0; i < cells.length; i++) {
117: maxLength = Math.max(maxLength, cells[i][j]
118: .length());
119: }
120: longestLengths[j] = maxLength;
121: }
122: return longestLengths;
123: } else {
124: // there is only two columns:
125: // - the first for the header
126: // - the second for the cell
127: int[] longestLengths = new int[2];
128: longestLengths[0] = 0;
129: for (int i = 0; i < headers.length; i++) {
130: longestLengths[0] = Math.max(longestLengths[0],
131: headers[i].length());
132: }
133: longestLengths[1] = 0;
134: for (int i = 0; i < cells.length; i++) {
135: for (int j = 0; j < cells[i].length; j++) {
136: String cell = cells[i][j];
137: longestLengths[1] = Math.max(longestLengths[1],
138: cell.length());
139: }
140: }
141: return longestLengths;
142: }
143: }
144:
145: /**
146: * Append a table of cells to the buffer
147: *
148: * @param cells the table of cells to append
149: * @param buf the <code>StringBuffer</code> where to append
150: * @param longestLengths used to fill each cell with whitespaces so
151: * that everything is properly formatted
152: */
153: private static void appendCellsTo(String[][] cells,
154: StringBuffer buf, int[] longestLengths) {
155: for (int i = 0; i < cells.length; i++) {
156: buf.append("| ");
157: for (int j = 0; j < cells[i].length; j++) {
158: String cell = cells[i][j];
159: buf.append(cell);
160: appendStringTo(buf, " ", longestLengths[j]
161: - cell.length());
162: buf.append(" | ");
163: }
164: buf.append("\n");
165: }
166: }
167:
168: /**
169: * Append table's headers to the buffer
170: *
171: * @param headers the headers of the table
172: * @param buf the <code>StringBuffer</code> where to append
173: * @param longestLengths used to fill each cell with whitespaces so
174: * that everything is properly formatted
175: */
176: private static void appendHeadersTo(String[] headers,
177: StringBuffer buf, int[] longestLengths) {
178: buf.append("| ");
179: for (int i = 0; i < headers.length; i++) {
180: String header = headers[i];
181: buf.append(header);
182: appendStringTo(buf, " ", longestLengths[i]
183: - header.length());
184: buf.append(" | ");
185: }
186: buf.append("\n");
187: }
188:
189: /**
190: * Append table's headers and cells in one pass.
191: * used when the headers should be displayed on the same colum
192: * (i.e. <code>headersAsRow</code> was <code>false</code>).
193: *
194: * @param headers the headers of the table
195: * @param cells the cells of the table
196: * @param buf the <code>StringBuffer</code> where to append
197: * @param longestLengths used to fill each cell with whitespaces so
198: * that everything is properly formatted
199: * @param horizontalRule an horizontal rule
200: */
201: private static void appendHeaderAndCells(String[] headers,
202: String[][] cells, StringBuffer buf, int[] longestLengths,
203: String horizontalRule) {
204: buf.append(horizontalRule);
205: for (int i = 0; i < cells.length; i++) {
206: for (int j = 0; j < cells[i].length; j++) {
207: buf.append("| ");
208: buf.append(headers[j]);
209: appendStringTo(buf, " ", longestLengths[0]
210: - headers[j].length());
211: buf.append(" | ");
212: String cell = cells[i][j];
213: buf.append(cell);
214: appendStringTo(buf, " ", longestLengths[1]
215: - cell.length());
216: buf.append(" |\n");
217: }
218: buf.append(horizontalRule);
219: }
220: }
221: }
|