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 }