1e3f6868dac3b4c4714637d12b93d97823011a35cshowardpackage autotest.common.table;
2e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
3e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
48b0ea2285c1327a686ff0b6ab245915e7fd20094showardimport autotest.common.Utils;
5ef37eccb66c415fdb6a8fe63244fe8545463719fshowardimport autotest.common.ui.RightClickTable;
6ef37eccb66c415fdb6a8fe63244fe8545463719fshoward
74cd4763a855d8eb7d25fd4963babc432eb4d25e6showardimport com.google.gwt.event.dom.client.ClickEvent;
84cd4763a855d8eb7d25fd4963babc432eb4d25e6showardimport com.google.gwt.event.dom.client.ClickHandler;
94cd4763a855d8eb7d25fd4963babc432eb4d25e6showardimport com.google.gwt.event.dom.client.ContextMenuEvent;
104cd4763a855d8eb7d25fd4963babc432eb4d25e6showardimport com.google.gwt.event.dom.client.ContextMenuHandler;
114cd4763a855d8eb7d25fd4963babc432eb4d25e6showardimport com.google.gwt.event.dom.client.DomEvent;
12e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.json.client.JSONObject;
13e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.json.client.JSONValue;
14e8819cdf80ca0e0602d22551a50f970aa68e108dmblighimport com.google.gwt.user.client.ui.Composite;
154cd4763a855d8eb7d25fd4963babc432eb4d25e6showardimport com.google.gwt.user.client.ui.HTMLTable;
16d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luoimport com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
1794b698cacab819b42104ce0db68aa63b68f4d1d1showardimport com.google.gwt.user.client.ui.Widget;
181c8c2215e525de8813c375e796354f8ffb811a08showard
191c8c2215e525de8813c375e796354f8ffb811a08showardimport java.util.ArrayList;
208579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshowardimport java.util.Collections;
211c8c2215e525de8813c375e796354f8ffb811a08showardimport java.util.List;
22e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
23e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh/**
2426dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren * A table to display data from JSONObjects.  Each row displays data from one
25e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * JSONObject.  A header row with column titles is automatically generated, and
26e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * support is included for adding other arbitrary header rows.
27e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <br><br>
28e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * Styles:
29e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <ul>
30e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <li>.data-table - the entire table
31e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <li>.data-row-header - the column title row
32e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * <li>.data-row-one/.data-row-two - data row styles.  These two are alternated.
33e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh * </ul>
34e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh */
354cd4763a855d8eb7d25fd4963babc432eb4d25e6showardpublic class DataTable extends Composite implements ClickHandler, ContextMenuHandler {
36e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public static final String HEADER_STYLE = "data-row-header";
37e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public static final String CLICKABLE_STYLE = "data-row-clickable";
381c8c2215e525de8813c375e796354f8ffb811a08showard    public static final String HIGHLIGHTED_STYLE = "data-row-highlighted";
3994b698cacab819b42104ce0db68aa63b68f4d1d1showard    public static final String WIDGET_COLUMN = "_WIDGET_COLUMN_";
4035dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward    // use CLICKABLE_WIDGET_COLUMN for widget that expect to receive clicks.  The table will ignore
4135dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward    // click events coming from these columns.
4235dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward    public static final String CLICKABLE_WIDGET_COLUMN = "_CLICKABLE_WIDGET_COLUMN_";
431c8c2215e525de8813c375e796354f8ffb811a08showard    // for indexing into column subarrays (i.e. columns[1][COL_NAME])
441c8c2215e525de8813c375e796354f8ffb811a08showard    public static final int COL_NAME = 0, COL_TITLE = 1;
4526dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
468579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    public static interface DataTableListener {
474cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick);
488579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
4926dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
50ef37eccb66c415fdb6a8fe63244fe8545463719fshoward    protected RightClickTable table;
5126dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
52e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    protected String[][] columns;
53e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    protected int headerRow = 0;
54e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    protected boolean clickable = false;
5526dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
5694b698cacab819b42104ce0db68aa63b68f4d1d1showard    protected TableWidgetFactory widgetFactory = null;
578579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    private List<DataTableListener> listeners = new ArrayList<DataTableListener>();
5826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
591c8c2215e525de8813c375e796354f8ffb811a08showard    // keep a list of JSONObjects corresponding to rows in the table
606bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward    protected List<JSONObject> jsonObjects = new ArrayList<JSONObject>();
61e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
6226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
6394b698cacab819b42104ce0db68aa63b68f4d1d1showard    public static interface TableWidgetFactory {
649d821ab7d97c677a63589e6d71ee3c9da46f7077showard        public Widget createWidget(int row, int cell, JSONObject rowObject);
6594b698cacab819b42104ce0db68aa63b68f4d1d1showard    }
6626dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
67e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
68e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * @param columns An array specifying the name of each column and the field
69e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * to which it corresponds.  The array should have the form
7026dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren     * {{'field_name1', 'Column Title 1'},
71e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     *  {'field_name2', 'Column Title 2'}, ...}.
7226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren     */
73e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public DataTable(String[][] columns) {
746bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward        int rows = columns.length;
756bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward        this.columns = new String[rows][2];
766bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward        for (int i = 0; i < rows; i++) {
776bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward            System.arraycopy(columns[i], 0, this.columns[i], 0, 2);
786bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward        }
7926dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
80ef37eccb66c415fdb6a8fe63244fe8545463719fshoward        table = new RightClickTable();
81e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        initWidget(table);
8226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
83e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        table.setCellSpacing(0);
84e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        table.setCellPadding(0);
853adac3671a998be8421238d3a08a7ffd2c3cbe1cshoward        table.setStylePrimaryName("data-table");
863adac3671a998be8421238d3a08a7ffd2c3cbe1cshoward        table.addStyleDependentName("outlined");
87e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
88e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        for (int i = 0; i < columns.length; i++) {
89e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            table.setText(0, i, columns[i][1]);
90e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        }
91e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
92e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        table.getRowFormatter().setStylePrimaryName(0, HEADER_STYLE);
934cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        table.addClickHandler(this);
94e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
9526dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
963ed34fd6fa69b0d1faba7b67ab32225b63b64781showard    /**
973ed34fd6fa69b0d1faba7b67ab32225b63b64781showard     * Causes the last column of the data table to fill the remainder of the width left in the
983ed34fd6fa69b0d1faba7b67ab32225b63b64781showard     * parent widget.
993ed34fd6fa69b0d1faba7b67ab32225b63b64781showard     */
1003ed34fd6fa69b0d1faba7b67ab32225b63b64781showard    public void fillParent() {
1013ed34fd6fa69b0d1faba7b67ab32225b63b64781showard        table.getColumnFormatter().setWidth(table.getCellCount(0) - 1, "100%");
1023ed34fd6fa69b0d1faba7b67ab32225b63b64781showard    }
10326dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
10494b698cacab819b42104ce0db68aa63b68f4d1d1showard    public void setWidgetFactory(TableWidgetFactory widgetFactory) {
10594b698cacab819b42104ce0db68aa63b68f4d1d1showard        this.widgetFactory = widgetFactory;
10694b698cacab819b42104ce0db68aa63b68f4d1d1showard    }
107e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
108e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    protected void setRowStyle(int row) {
109e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        table.getRowFormatter().setStyleName(row, "data-row");
110e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        if ((row & 1) == 0) {
111e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            table.getRowFormatter().addStyleName(row, "data-row-alternate");
112e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        }
113e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        if (clickable) {
114e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            table.getRowFormatter().addStyleName(row, CLICKABLE_STYLE);
115e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        }
116e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
11726dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
118e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public void setClickable(boolean clickable) {
119e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        this.clickable = clickable;
120e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        for(int i = headerRow + 1; i < table.getRowCount(); i++)
121e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            setRowStyle(i);
122e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
123e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
124e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
125e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * Clear all data rows from the table.  Leaves the header rows intact.
126e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
127e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public void clear() {
1288579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        while (table.getRowCount() > 1) {
1298579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward            table.removeRow(1);
130e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        }
1311c8c2215e525de8813c375e796354f8ffb811a08showard        jsonObjects.clear();
132e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
13326dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
134e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
135e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * This gets called for every JSONObject that gets added to the table using
13626dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren     * addRow().  This allows subclasses to customize objects before they are
13726dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren     * added to the table, for example to reformat fields or generate new
138e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * fields from the existing data.
139e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * @param row The row object about to be added to the table.
140e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
141e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    protected void preprocessRow(JSONObject row) {}
14226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
143e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    protected String[] getRowText(JSONObject row) {
144e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        String[] rowText = new String[columns.length];
145e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        for (int i = 0; i < columns.length; i++) {
14694b698cacab819b42104ce0db68aa63b68f4d1d1showard            if (isWidgetColumn(i))
14794b698cacab819b42104ce0db68aa63b68f4d1d1showard                continue;
14826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
149e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            String columnKey = columns[i][0];
150e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            JSONValue columnValue = row.get(columnKey);
151669624aad9c77060f706fde7c8e717cb636f9be8showard            if (columnValue == null || columnValue.isNull() != null) {
152669624aad9c77060f706fde7c8e717cb636f9be8showard                rowText[i] = "";
153669624aad9c77060f706fde7c8e717cb636f9be8showard            } else {
154669624aad9c77060f706fde7c8e717cb636f9be8showard                rowText[i] = Utils.jsonToString(columnValue);
155669624aad9c77060f706fde7c8e717cb636f9be8showard            }
156e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        }
157e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        return rowText;
158e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
15926dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
160e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
161e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * Add a row from an array of Strings, one String for each column.
162e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * @param rowData Data for each column, in left-to-right column order.
163e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
1641c8c2215e525de8813c375e796354f8ffb811a08showard    protected void addRowFromData(String[] rowData) {
165e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        int row = table.getRowCount();
16694b698cacab819b42104ce0db68aa63b68f4d1d1showard        for(int i = 0; i < columns.length; i++) {
16794b698cacab819b42104ce0db68aa63b68f4d1d1showard            if(isWidgetColumn(i)) {
1688579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                table.setWidget(row, i, getWidgetForCell(row, i));
16994b698cacab819b42104ce0db68aa63b68f4d1d1showard            } else {
1708579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                table.setText(row, i, rowData[i]);
17194b698cacab819b42104ce0db68aa63b68f4d1d1showard            }
17294b698cacab819b42104ce0db68aa63b68f4d1d1showard        }
173e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        setRowStyle(row);
174e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
175e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
17635dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward    protected boolean isWidgetColumn(int column) {
17735dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward        return columns[column][COL_NAME].equals(WIDGET_COLUMN) || isClickableWidgetColumn(column);
17835dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward    }
17926dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
18035dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward    protected boolean isClickableWidgetColumn(int column) {
18135dbd8414c0e7022a6a4b54f7ef16b5ff51ae53bshoward        return columns[column][COL_NAME].equals(CLICKABLE_WIDGET_COLUMN);
18294b698cacab819b42104ce0db68aa63b68f4d1d1showard    }
18394b698cacab819b42104ce0db68aa63b68f4d1d1showard
184e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
185e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * Add a row from a JSONObject.  Columns will be populated by pulling fields
186e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * from the objects, as dictated by the columns information passed into the
187e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * DataTable constructor.
188e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
189e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public void addRow(JSONObject row) {
190e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        preprocessRow(row);
1911c8c2215e525de8813c375e796354f8ffb811a08showard        jsonObjects.add(row);
192e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        addRowFromData(getRowText(row));
193e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
19426dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
195e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
196e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * Add all objects in a JSONArray.
197e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * @param rows An array of JSONObjects
198e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * @throws IllegalArgumentException if any other type of JSONValue is in the
199e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * array.
200e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
2014879914c122f4ed97eae3b08c5af1930fd75b39dshoward    public void addRows(List<JSONObject> rows) {
2024879914c122f4ed97eae3b08c5af1930fd75b39dshoward        for (JSONObject row : rows) {
203e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            addRow(row);
204e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        }
205e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
206e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
207e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
208e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * Remove a data row from the table.
2091c8c2215e525de8813c375e796354f8ffb811a08showard     * @param rowIndex The index of the row, where the first data row is indexed 0.
210e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     * Header rows are ignored.
211e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
2121c8c2215e525de8813c375e796354f8ffb811a08showard    public void removeRow(int rowIndex) {
2131c8c2215e525de8813c375e796354f8ffb811a08showard        jsonObjects.remove(rowIndex);
2141c8c2215e525de8813c375e796354f8ffb811a08showard        int realRow = rowIndex + 1; // header row
215e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        table.removeRow(realRow);
216e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh        for(int i = realRow; i < table.getRowCount(); i++)
217e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh            setRowStyle(i);
218e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
21926dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
220e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
22126dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren     * Returns the number of data rows in the table.  The actual number of
2221c8c2215e525de8813c375e796354f8ffb811a08showard     * visible table rows is more than this, due to the header row.
223e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
224e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    public int getRowCount() {
2251c8c2215e525de8813c375e796354f8ffb811a08showard        return table.getRowCount() - 1;
226e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
22726dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
228e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    /**
2291c8c2215e525de8813c375e796354f8ffb811a08showard     * Get the JSONObject corresponding to the indexed row.
230e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh     */
2311c8c2215e525de8813c375e796354f8ffb811a08showard    public JSONObject getRow(int rowIndex) {
2326bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward        return jsonObjects.get(rowIndex);
233e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
23426dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2358579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    public List<JSONObject> getAllRows() {
2368579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        return Collections.unmodifiableList(jsonObjects);
2378579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
23826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2391c8c2215e525de8813c375e796354f8ffb811a08showard    public void highlightRow(int row) {
2401c8c2215e525de8813c375e796354f8ffb811a08showard        row++; // account for header row
2411c8c2215e525de8813c375e796354f8ffb811a08showard        table.getRowFormatter().addStyleName(row, HIGHLIGHTED_STYLE);
2421c8c2215e525de8813c375e796354f8ffb811a08showard    }
24326dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2441c8c2215e525de8813c375e796354f8ffb811a08showard    public void unhighlightRow(int row) {
2456bc47015cce0ebc2fc255d3950bfeaf4851f36fdshoward        row++; // account for header row
2461c8c2215e525de8813c375e796354f8ffb811a08showard        table.getRowFormatter().removeStyleName(row, HIGHLIGHTED_STYLE);
247e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh    }
24826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
249ef37eccb66c415fdb6a8fe63244fe8545463719fshoward    public void sinkRightClickEvents() {
2504cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        table.addContextMenuHandler(this);
251ef37eccb66c415fdb6a8fe63244fe8545463719fshoward    }
25226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2534cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    @Override
2544cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    public void onClick(ClickEvent event) {
2554cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        onCellClicked(event, false);
2564cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    }
25726dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2584cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    @Override
2594cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    public void onContextMenu(ContextMenuEvent event) {
2604cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        onCellClicked(event, true);
2614cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    }
26226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2634cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    private void onCellClicked(DomEvent<?> event, boolean isRightClick) {
2644cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        HTMLTable.Cell tableCell = table.getCellForDomEvent(event);
26526dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren        if (tableCell == null) {
26626dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren            return;
26726dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren        }
26826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2694cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        int row = tableCell.getRowIndex();
2704cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        int cell = tableCell.getCellIndex();
27126dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
272eb0fd4c76ee70e68d907e542423ae249489552c2showard        if (isClickableWidgetColumn(cell) && table.getWidget(row, cell) != null) {
2738579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward            return;
274eb0fd4c76ee70e68d907e542423ae249489552c2showard        }
27526dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2764cd4763a855d8eb7d25fd4963babc432eb4d25e6showard        onCellClicked(row, cell, isRightClick);
2774cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    }
27826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2794cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    protected void onCellClicked(int row, int cell, boolean isRightClick) {
2808579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        if (row != headerRow) {
2814cd4763a855d8eb7d25fd4963babc432eb4d25e6showard            notifyListenersClicked(row - headerRow - 1, isRightClick);
2828579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        }
2838579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
28426dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2858579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    public void addListener(DataTableListener listener) {
2868579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        listeners.add(listener);
2878579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
28826dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2898579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    public void removeListener(DataTableListener listener) {
2908579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        listeners.remove(listener);
2918579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
29226dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
2934cd4763a855d8eb7d25fd4963babc432eb4d25e6showard    protected void notifyListenersClicked(int rowIndex, boolean isRightClick) {
2948579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        JSONObject row = getRow(rowIndex);
2958579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        for (DataTableListener listener : listeners) {
2964cd4763a855d8eb7d25fd4963babc432eb4d25e6showard            listener.onRowClicked(rowIndex, row, isRightClick);
2978579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        }
2988579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
29926dd6aa23eb2771acefa611c029c06f6ee6f1b11jamesren
3008579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    public void refreshWidgets() {
3018579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        for (int row = 1; row < table.getRowCount(); row++) {
3028579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward            for (int column = 0; column < columns.length; column++) {
3038579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                if (!isWidgetColumn(column)) {
3048579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                    continue;
3058579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                }
3068579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                table.clearCell(row, column);
3078579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward                table.setWidget(row, column, getWidgetForCell(row, column));
3088579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward            }
3098579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        }
3108579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
3118579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward
3128579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    private Widget getWidgetForCell(int row, int column) {
3138579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward        return widgetFactory.createWidget(row - 1, column, jsonObjects.get(row - 1));
3148579ea343f8d4c74b44d5b5cb2df3ef7552b2f6eshoward    }
315d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo
316d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo    /**
317d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo     * Add a style name to a specific column by column name.
318d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo     */
319d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo    public void addStyleNameByColumnName(String columnName, String styleName) {
320d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo        CellFormatter cellFormatter = table.getCellFormatter();
321d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo        for (int column = 0; column < columns.length; column++) {
322d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo            if (columns[column][1].equals(columnName)) {
323d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo                for (int row = 1; row < table.getRowCount(); row++) {
324d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo                    cellFormatter.addStyleName(row, column, styleName);
325d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo                }
326d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo            }
327d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo        }
328d58f008bca8c2d70c3f36d93a9fc1f76f25b4d3fJiaxi Luo    }
329e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh}
330