1 /**
2 * Copyright (c) 2012, University of Konstanz, Distributed Systems Group
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of Konstanz nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 package org.perfidix.ouput.asciitable;
28
29 import java.util.ArrayList;
30 import java.util.List;
31
32 import org.perfidix.ouput.asciitable.AbstractTabularComponent.Alignment;
33
34 /**
35 * This class represents a table which allows formatting of data as an ascii
36 * table. it takes care of automatically adjusting widths of the tables. A word
37 * on the orientations: at the current point of development, the orientation
38 * works on COLUMNS and NOT on ROWs. so you can set the orientation of a full
39 * ROW, but you cannot set the orientation for each field[x][y] in the table.
40 *
41 * @author Alexander Onea, neue Couch
42 * @author Sebastian Graf, University of Konstanz
43 */
44 public final class NiceTable {
45
46 /**
47 * Container for all rows.
48 */
49 private transient final List<AbstractTabularComponent> rows;
50
51 /**
52 * Storing the length of chars in the different columns.
53 */
54 private transient final int[] columnLengths;
55
56 /**
57 * An array holding the orientations of columns.
58 */
59 private transient final Alignment[] orientations;
60
61 /**
62 * Constructor. needs the number of columns to show.
63 *
64 * @param numberOfColumns
65 * the number of columns to display.
66 */
67 public NiceTable(final int numberOfColumns) {
68
69 columnLengths = new int[numberOfColumns];
70 orientations = new Alignment[numberOfColumns];
71 rows = new ArrayList<AbstractTabularComponent>();
72 }
73
74 /**
75 * Adds a header.
76 *
77 * @param title
78 * the text to display within the header
79 */
80 public void addHeader(final String title) {
81 addHeader(title, '=', Alignment.Left);
82 }
83
84 /**
85 * Adds a header row to the table. can be used to give a table some title.
86 *
87 * <pre>
88 * addHeader("hello",'.',NiceTable.LEFT)
89 * would produce a row like
90 * ... hello ..........................
91 * {rows in here.}
92 * </pre>
93 *
94 * @param title
95 * the string to display as a header
96 * @param mark
97 * the mark to use for the rest of the column
98 * @param orientation
99 * the orientation of the header column.
100 */
101 public void addHeader(final String title, final char mark, final Alignment orientation) {
102 final Header header = new Header(title, mark, orientation, this);
103 rows.add(header);
104 }
105
106 /**
107 * Adds a string row. checks that the strings added do not contain newlines,
108 * because if so, it has to split them in order to make them fit the row.
109 *
110 * @param data
111 * the array of data.
112 */
113 public void addRow(final String[] data) {
114 if (anyStringContainsNewLine(data)) {
115 final String[][] theMatrix = Util.createMatrix(data);
116 for (int i = 0; i < theMatrix.length; i++) {
117 addRow(theMatrix[i]);
118 }
119 } else {
120 final Row myRow = new Row(this, data);
121 rows.add(myRow);
122 }
123
124 }
125
126 /**
127 * allows the addition of lines. think of it as a horizontal rule in a
128 * table.
129 *
130 * @param fill
131 * any character with which to draw the line.
132 */
133 public void addLine(final char fill) {
134 rows.add(new DynamicLine(fill, this));
135 }
136
137 /**
138 * the main method doing the work. draws everyting.
139 *
140 * @return the formatted table.
141 */
142 @Override
143 public String toString() {
144
145 final StringBuilder builder = new StringBuilder();
146
147 for (int i = 0; i < rows.size(); i++) {
148 final AbstractTabularComponent myObj = rows.get(i);
149 builder.append(myObj.draw());
150 }
151 return builder.toString();
152 }
153
154 /**
155 * Returns the global column width at index columnIndex.
156 *
157 * @param columnIndex
158 * the index of the column for which to fetch the width.
159 * @return the width (in number of chars) for the column index.
160 */
161 protected int getColumnWidth(final int columnIndex) {
162
163 return columnLengths[columnIndex];
164 }
165
166 /**
167 * Performs an update on the column lengths.
168 *
169 * @param index
170 * the index of the column
171 * @param newSize
172 * the new size of the column
173 */
174 protected void updateColumnWidth(final int index, final int newSize) {
175 columnLengths[index] = Math.max(columnLengths[index], newSize);
176 }
177
178 /**
179 * Returns the actual number of columns this table has got.
180 *
181 * @return the number of columns the table may contain.
182 */
183 private int numColumns() {
184 return this.columnLengths.length;
185 }
186
187 /**
188 * Returns the orientation of a column.
189 *
190 * @param columnIndex
191 * integer
192 * @return Alignment for the column
193 */
194 protected Alignment getOrientation(final int columnIndex) {
195
196 return orientations[columnIndex];
197 }
198
199 /**
200 * Returns the row width.
201 *
202 * @return int the width of the row
203 */
204 private int getRowWidth() {
205 int returnVal = 1;
206 if (rows.size() < 1) {
207 returnVal = 0;
208 }
209 for (int i = 0; i < rows.size(); i++) {
210 if (rows.get(i) instanceof Row) {
211 returnVal = ((Row)rows.get(i)).getRowWidth();
212 }
213 }
214 return returnVal;
215 }
216
217 /**
218 * Returns the total width of the table.
219 *
220 * @return int the width of the table
221 */
222 protected int getTotalWidth() {
223 return this.getRowWidth() + 3 * numColumns() + 1;
224 }
225
226 /**
227 * Tests whether any string contains a newline symbol.
228 *
229 * @param data
230 * the array to check.
231 * @return whether any of the strings contains a newline symbol.
232 */
233 private boolean anyStringContainsNewLine(final String[] data) {
234 boolean returnVal = false;
235 for (int i = 0; i < data.length; i++) {
236 if (Util.containsNewlines(data[i])) {
237 returnVal = true;
238 }
239 }
240 return returnVal;
241 }
242
243 }