DataTable.java revision e8819cdf80ca0e0602d22551a50f970aa68e108d
1package afeclient.client; 2 3 4 5import com.google.gwt.json.client.JSONArray; 6import com.google.gwt.json.client.JSONObject; 7import com.google.gwt.json.client.JSONValue; 8import com.google.gwt.user.client.ui.Composite; 9import com.google.gwt.user.client.ui.FlexTable; 10import com.google.gwt.user.client.ui.Widget; 11 12/** 13 * A table to display data from JSONObjects. Each row displays data from one 14 * JSONObject. A header row with column titles is automatically generated, and 15 * support is included for adding other arbitrary header rows. 16 * <br><br> 17 * Styles: 18 * <ul> 19 * <li>.data-table - the entire table 20 * <li>.data-row-header - the column title row 21 * <li>.data-row-one/.data-row-two - data row styles. These two are alternated. 22 * </ul> 23 */ 24public class DataTable extends Composite { 25 public static final String HEADER_STYLE = "data-row-header"; 26 public static final String CLICKABLE_STYLE = "data-row-clickable"; 27 28 protected FlexTable table; 29 30 protected String[][] columns; 31 protected int headerRow = 0; 32 protected boolean clickable = false; 33 34 /** 35 * @param columns An array specifying the name of each column and the field 36 * to which it corresponds. The array should have the form 37 * {{'field_name1', 'Column Title 1'}, 38 * {'field_name2', 'Column Title 2'}, ...}. 39 */ 40 public DataTable(String[][] columns) { 41 this.columns = columns; 42 table = new FlexTable(); 43 initWidget(table); 44 45 table.setCellSpacing(0); 46 table.setCellPadding(0); 47 table.setStyleName("data-table"); 48 49 for (int i = 0; i < columns.length; i++) { 50 table.setText(0, i, columns[i][1]); 51 } 52 53 table.getRowFormatter().setStylePrimaryName(0, HEADER_STYLE); 54 } 55 56 protected void setRowStyle(int row) { 57 table.getRowFormatter().setStyleName(row, "data-row"); 58 if ((row & 1) == 0) { 59 table.getRowFormatter().addStyleName(row, "data-row-alternate"); 60 } 61 if (clickable) { 62 table.getRowFormatter().addStyleName(row, CLICKABLE_STYLE); 63 } 64 } 65 66 public void setClickable(boolean clickable) { 67 this.clickable = clickable; 68 for(int i = headerRow + 1; i < table.getRowCount(); i++) 69 setRowStyle(i); 70 } 71 72 /** 73 * Clear all data rows from the table. Leaves the header rows intact. 74 */ 75 public void clear() { 76 while (getRowCount() > 0) { 77 removeRow(0); 78 } 79 } 80 81 /** 82 * This gets called for every JSONObject that gets added to the table using 83 * addRow(). This allows subclasses to customize objects before they are 84 * added to the table, for example to reformat fields or generate new 85 * fields from the existing data. 86 * @param row The row object about to be added to the table. 87 */ 88 protected void preprocessRow(JSONObject row) {} 89 90 protected String getTextForValue(JSONValue value) { 91 if (value.isNumber() != null) 92 return Integer.toString((int) value.isNumber().getValue()); 93 else if (value.isString() != null) 94 return value.isString().stringValue(); 95 else if (value.isNull() != null) 96 return ""; 97 else 98 throw new IllegalArgumentException(value.toString()); 99 } 100 101 protected String[] getRowText(JSONObject row) { 102 String[] rowText = new String[columns.length]; 103 for (int i = 0; i < columns.length; i++) { 104 String columnKey = columns[i][0]; 105 JSONValue columnValue = row.get(columnKey); 106 rowText[i] = getTextForValue(columnValue); 107 } 108 return rowText; 109 } 110 111 /** 112 * Add a row from an array of Strings, one String for each column. 113 * @param rowData Data for each column, in left-to-right column order. 114 */ 115 public void addRowFromData(String[] rowData) { 116 int row = table.getRowCount(); 117 for(int i = 0; i < columns.length; i++) 118 table.setHTML(row, i, rowData[i]); 119 setRowStyle(row); 120 } 121 122 /** 123 * Add a row from a JSONObject. Columns will be populated by pulling fields 124 * from the objects, as dictated by the columns information passed into the 125 * DataTable constructor. 126 */ 127 public void addRow(JSONObject row) { 128 preprocessRow(row); 129 addRowFromData(getRowText(row)); 130 } 131 132 /** 133 * Add all objects in a JSONArray. 134 * @param rows An array of JSONObjects 135 * @throws IllegalArgumentException if any other type of JSONValue is in the 136 * array. 137 */ 138 public void addRows(JSONArray rows) { 139 for (int i = 0; i < rows.size(); i++) { 140 JSONObject row = rows.get(i).isObject(); 141 if (row == null) 142 throw new IllegalArgumentException("rows must be JSONObjects"); 143 addRow(row); 144 } 145 } 146 147 /** 148 * Remove a data row from the table. 149 * @param row The index of the row, where the first data row is indexed 0. 150 * Header rows are ignored. 151 */ 152 public void removeRow(int row) { 153 int realRow = row + getHeaderRowCount(); 154 table.removeRow(realRow); 155 for(int i = realRow; i < table.getRowCount(); i++) 156 setRowStyle(i); 157 } 158 159 /** 160 * Returns the number of data rows in the table. The actual number of 161 * visible table rows is more than this, due to the header rows. 162 */ 163 public int getRowCount() { 164 return table.getRowCount() - getHeaderRowCount(); 165 } 166 167 /** 168 * Adds a header row to the table. This is an extra row that is added above 169 * the row of column titles and below any other header rows that have been 170 * added. The row consists of a single cell. 171 * @param widget A widget to add to the cell. 172 * @return The row index of the new header row. 173 */ 174 public int addHeaderRow(Widget widget) { 175 int row = table.insertRow(headerRow); 176 headerRow++; 177 table.getFlexCellFormatter().setColSpan(row, 0, columns.length); 178 table.setWidget(row, 0, widget); 179 return row; 180 } 181 182 /** 183 * Returns the number of header rows, including the column title row. 184 */ 185 public int getHeaderRowCount() { 186 return headerRow + 1; 187 } 188} 189