DataTable.java revision 35dbd8414c0e7022a6a4b54f7ef16b5ff51ae53b
1e3f6868dac3b4c4714637d12b93d97823011a35cshowardpackage autotest.common.table; 2e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 3e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 4e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.json.client.JSONArray; 5e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.json.client.JSONObject; 6e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.json.client.JSONValue; 7e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.user.client.ui.Composite; 8e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.user.client.ui.FlexTable; 994b698cacab819b42104ce0db68aa63b68f4d1d1showardimport com.google.gwt.user.client.ui.Widget; 101c8c2215e525de8813c375e796354f8ffb811a08showard 111c8c2215e525de8813c375e796354f8ffb811a08showardimport java.util.ArrayList; 121c8c2215e525de8813c375e796354f8ffb811a08showardimport java.util.List; 13e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 14e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh/** 15e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * A table to display data from JSONObjects. Each row displays data from one 16e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * JSONObject. A header row with column titles is automatically generated, and 17e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * support is included for adding other arbitrary header rows. 18e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <br><br> 19e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Styles: 20e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <ul> 21e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <li>.data-table - the entire table 22e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <li>.data-row-header - the column title row 23e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <li>.data-row-one/.data-row-two - data row styles. These two are alternated. 24e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * </ul> 25e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 26e8819cdf80ca0e0602d22551a50f970aa68e108dmblighpublic class DataTable extends Composite { 27e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public static final String HEADER_STYLE = "data-row-header"; 28e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public static final String CLICKABLE_STYLE = "data-row-clickable"; 291c8c2215e525de8813c375e796354f8ffb811a08showard public static final String HIGHLIGHTED_STYLE = "data-row-highlighted"; 3094b698cacab819b42104ce0db68aa63b68f4d1d1showard public static final String WIDGET_COLUMN = "_WIDGET_COLUMN_"; 3135dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward // use CLICKABLE_WIDGET_COLUMN for widget that expect to receive clicks. The table will ignore 3235dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward // click events coming from these columns. 3335dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward public static final String CLICKABLE_WIDGET_COLUMN = "_CLICKABLE_WIDGET_COLUMN_"; 341c8c2215e525de8813c375e796354f8ffb811a08showard // for indexing into column subarrays (i.e. columns[1][COL_NAME]) 351c8c2215e525de8813c375e796354f8ffb811a08showard public static final int COL_NAME = 0, COL_TITLE = 1; 36e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 37e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected FlexTable table; 38e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 39e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected String[][] columns; 40e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected int headerRow = 0; 41e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected boolean clickable = false; 421c8c2215e525de8813c375e796354f8ffb811a08showard 4394b698cacab819b42104ce0db68aa63b68f4d1d1showard protected TableWidgetFactory widgetFactory = null; 4494b698cacab819b42104ce0db68aa63b68f4d1d1showard 451c8c2215e525de8813c375e796354f8ffb811a08showard // keep a list of JSONObjects corresponding to rows in the table 466bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward protected List<JSONObject> jsonObjects = new ArrayList<JSONObject>(); 47e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 4894b698cacab819b42104ce0db68aa63b68f4d1d1showard 4994b698cacab819b42104ce0db68aa63b68f4d1d1showard public static interface TableWidgetFactory { 509d821ab7d97c677a63589e6d71ee3c9da46f7077showard public Widget createWidget(int row, int cell, JSONObject rowObject); 5194b698cacab819b42104ce0db68aa63b68f4d1d1showard } 5294b698cacab819b42104ce0db68aa63b68f4d1d1showard 53e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 54e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * @param columns An array specifying the name of each column and the field 55e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * to which it corresponds. The array should have the form 56e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * {{'field_name1', 'Column Title 1'}, 57e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * {'field_name2', 'Column Title 2'}, ...}. 58e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 59e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public DataTable(String[][] columns) { 606bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward int rows = columns.length; 616bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward this.columns = new String[rows][2]; 626bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward for (int i = 0; i < rows; i++) { 636bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward System.arraycopy(columns[i], 0, this.columns[i], 0, 2); 646bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward } 656bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward 66e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table = new FlexTable(); 67e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh initWidget(table); 68e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 69e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.setCellSpacing(0); 70e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.setCellPadding(0); 71e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.setStyleName("data-table"); 72e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 73e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh for (int i = 0; i < columns.length; i++) { 74e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.setText(0, i, columns[i][1]); 75e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 76e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 77e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.getRowFormatter().setStylePrimaryName(0, HEADER_STYLE); 78e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 7994b698cacab819b42104ce0db68aa63b68f4d1d1showard 8094b698cacab819b42104ce0db68aa63b68f4d1d1showard public void setWidgetFactory(TableWidgetFactory widgetFactory) { 8194b698cacab819b42104ce0db68aa63b68f4d1d1showard this.widgetFactory = widgetFactory; 8294b698cacab819b42104ce0db68aa63b68f4d1d1showard } 83e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 84e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected void setRowStyle(int row) { 85e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.getRowFormatter().setStyleName(row, "data-row"); 86e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh if ((row & 1) == 0) { 87e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.getRowFormatter().addStyleName(row, "data-row-alternate"); 88e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 89e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh if (clickable) { 90e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.getRowFormatter().addStyleName(row, CLICKABLE_STYLE); 91e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 92e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 93e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 94e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public void setClickable(boolean clickable) { 95e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh this.clickable = clickable; 96e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh for(int i = headerRow + 1; i < table.getRowCount(); i++) 97e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh setRowStyle(i); 98e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 99e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 100e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 101e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Clear all data rows from the table. Leaves the header rows intact. 102e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 103e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public void clear() { 104e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh while (getRowCount() > 0) { 105e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh removeRow(0); 106e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 1071c8c2215e525de8813c375e796354f8ffb811a08showard jsonObjects.clear(); 108e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 109e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 110e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 111e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * This gets called for every JSONObject that gets added to the table using 112e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * addRow(). This allows subclasses to customize objects before they are 113e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * added to the table, for example to reformat fields or generate new 114e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * fields from the existing data. 115e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * @param row The row object about to be added to the table. 116e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 117e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected void preprocessRow(JSONObject row) {} 118e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 119e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected String getTextForValue(JSONValue value) { 120b8d3424d02cfdc6c3eeda788e3527c5ec50ad8f9showard if (value == null || value.isNull() != null) 121b8d3424d02cfdc6c3eeda788e3527c5ec50ad8f9showard return ""; 122b8d3424d02cfdc6c3eeda788e3527c5ec50ad8f9showard else if (value.isNumber() != null) 1236bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward return Integer.toString((int) value.isNumber().doubleValue()); 124e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh else if (value.isString() != null) 125e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh return value.isString().stringValue(); 126e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh else 127e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh throw new IllegalArgumentException(value.toString()); 128e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 129e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 130e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh protected String[] getRowText(JSONObject row) { 131e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh String[] rowText = new String[columns.length]; 132e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh for (int i = 0; i < columns.length; i++) { 13394b698cacab819b42104ce0db68aa63b68f4d1d1showard if (isWidgetColumn(i)) 13494b698cacab819b42104ce0db68aa63b68f4d1d1showard continue; 13594b698cacab819b42104ce0db68aa63b68f4d1d1showard 136e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh String columnKey = columns[i][0]; 137e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh JSONValue columnValue = row.get(columnKey); 138e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh rowText[i] = getTextForValue(columnValue); 139e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 140e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh return rowText; 141e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 142e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 143e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 144e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Add a row from an array of Strings, one String for each column. 145e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * @param rowData Data for each column, in left-to-right column order. 146e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 1471c8c2215e525de8813c375e796354f8ffb811a08showard protected void addRowFromData(String[] rowData) { 148e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh int row = table.getRowCount(); 14994b698cacab819b42104ce0db68aa63b68f4d1d1showard for(int i = 0; i < columns.length; i++) { 15094b698cacab819b42104ce0db68aa63b68f4d1d1showard if(isWidgetColumn(i)) { 1519d821ab7d97c677a63589e6d71ee3c9da46f7077showard table.setWidget(row, i, widgetFactory.createWidget(row - 1, i, 1529d821ab7d97c677a63589e6d71ee3c9da46f7077showard jsonObjects.get(row - 1))); 15394b698cacab819b42104ce0db68aa63b68f4d1d1showard } else { 15494b698cacab819b42104ce0db68aa63b68f4d1d1showard table.setHTML(row, i, rowData[i]); 15594b698cacab819b42104ce0db68aa63b68f4d1d1showard } 15694b698cacab819b42104ce0db68aa63b68f4d1d1showard } 157e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh setRowStyle(row); 158e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 159e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 16035dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward protected boolean isWidgetColumn(int column) { 16135dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward return columns[column][COL_NAME].equals(WIDGET_COLUMN) || isClickableWidgetColumn(column); 16235dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward } 16335dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward 16435dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward protected boolean isClickableWidgetColumn(int column) { 16535dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward return columns[column][COL_NAME].equals(CLICKABLE_WIDGET_COLUMN); 16694b698cacab819b42104ce0db68aa63b68f4d1d1showard } 16794b698cacab819b42104ce0db68aa63b68f4d1d1showard 168e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 169e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Add a row from a JSONObject. Columns will be populated by pulling fields 170e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * from the objects, as dictated by the columns information passed into the 171e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * DataTable constructor. 172e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 173e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public void addRow(JSONObject row) { 174e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh preprocessRow(row); 1751c8c2215e525de8813c375e796354f8ffb811a08showard jsonObjects.add(row); 176e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh addRowFromData(getRowText(row)); 177e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 178e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 179e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 180e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Add all objects in a JSONArray. 181e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * @param rows An array of JSONObjects 182e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * @throws IllegalArgumentException if any other type of JSONValue is in the 183e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * array. 184e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 185e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public void addRows(JSONArray rows) { 186e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh for (int i = 0; i < rows.size(); i++) { 187e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh JSONObject row = rows.get(i).isObject(); 188e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh if (row == null) 189e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh throw new IllegalArgumentException("rows must be JSONObjects"); 190e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh addRow(row); 191e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 192e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 193e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 194e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 195e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Remove a data row from the table. 1961c8c2215e525de8813c375e796354f8ffb811a08showard * @param rowIndex The index of the row, where the first data row is indexed 0. 197e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Header rows are ignored. 198e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 1991c8c2215e525de8813c375e796354f8ffb811a08showard public void removeRow(int rowIndex) { 2001c8c2215e525de8813c375e796354f8ffb811a08showard jsonObjects.remove(rowIndex); 2011c8c2215e525de8813c375e796354f8ffb811a08showard int realRow = rowIndex + 1; // header row 202e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh table.removeRow(realRow); 203e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh for(int i = realRow; i < table.getRowCount(); i++) 204e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh setRowStyle(i); 205e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 206e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 207e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 208e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Returns the number of data rows in the table. The actual number of 2091c8c2215e525de8813c375e796354f8ffb811a08showard * visible table rows is more than this, due to the header row. 210e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 211e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh public int getRowCount() { 2121c8c2215e525de8813c375e796354f8ffb811a08showard return table.getRowCount() - 1; 213e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 2141c8c2215e525de8813c375e796354f8ffb811a08showard 215e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh /** 2161c8c2215e525de8813c375e796354f8ffb811a08showard * Get the JSONObject corresponding to the indexed row. 217e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */ 2181c8c2215e525de8813c375e796354f8ffb811a08showard public JSONObject getRow(int rowIndex) { 2196bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward return jsonObjects.get(rowIndex); 220e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 221e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh 2221c8c2215e525de8813c375e796354f8ffb811a08showard public void highlightRow(int row) { 2231c8c2215e525de8813c375e796354f8ffb811a08showard row++; // account for header row 2241c8c2215e525de8813c375e796354f8ffb811a08showard table.getRowFormatter().addStyleName(row, HIGHLIGHTED_STYLE); 2251c8c2215e525de8813c375e796354f8ffb811a08showard } 2261c8c2215e525de8813c375e796354f8ffb811a08showard 2271c8c2215e525de8813c375e796354f8ffb811a08showard public void unhighlightRow(int row) { 2286bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward row++; // account for header row 2291c8c2215e525de8813c375e796354f8ffb811a08showard table.getRowFormatter().removeStyleName(row, HIGHLIGHTED_STYLE); 230e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh } 231e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh} 232