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