• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package autotest.common.table;
2 
3 import autotest.common.SimpleCallback;
4 import autotest.common.table.DataSource.DataCallback;
5 import autotest.common.table.DataSource.Query;
6 import autotest.common.table.DataSource.SortDirection;
7 import autotest.common.table.DataSource.SortSpec;
8 import autotest.common.ui.Paginator;
9 
10 import com.google.gwt.json.client.JSONObject;
11 import com.google.gwt.user.client.ui.Composite;
12 import com.google.gwt.user.client.ui.HTMLPanel;
13 import com.google.gwt.user.client.ui.Image;
14 
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Iterator;
18 import java.util.List;
19 
20 /**
21  * Extended DataTable supporting sorting, filtering and pagination.
22  */
23 public class DynamicTable extends DataTable implements DataCallback {
24     public static final int NO_COLUMN = -1;
25     public static final String SORT_UP_IMAGE = "arrow_up.png",
26                                SORT_DOWN_IMAGE = "arrow_down.png";
27 
28     public static interface DynamicTableListener extends DataTableListener {
onTableRefreshed()29         public void onTableRefreshed();
30     }
31 
32     static class SortIndicator extends Composite {
33         public int column;
34         private Image image = new Image();
35 
SortIndicator(int column)36         public SortIndicator(int column) {
37             this.column = column;
38             initWidget(image);
39             setVisible(false);
40         }
41 
sortOn(SortDirection direction)42         public void sortOn(SortDirection direction) {
43             image.setUrl(direction == SortDirection.ASCENDING ? SORT_UP_IMAGE : SORT_DOWN_IMAGE);
44             setVisible(true);
45         }
46 
sortOff()47         public void sortOff() {
48             setVisible(false);
49         }
50     }
51 
52     protected DataSource dataSource;
53     private Query currentQuery;
54 
55     private boolean clientSortable = false;
56     private SortIndicator[] sortIndicators;
57     private List<SortSpec> sortColumns = new ArrayList<SortSpec>();
58 
59     protected List<Filter> filters = new ArrayList<Filter>();
60     protected List<Paginator> paginators = new ArrayList<Paginator>();
61     protected Integer rowsPerPage;
62 
63     protected List<DynamicTableListener> dynamicTableListeners =
64         new ArrayList<DynamicTableListener>();
65 
DynamicTable(String[][] columns, DataSource dataSource)66     public DynamicTable(String[][] columns, DataSource dataSource) {
67         super(columns);
68         setDataSource(dataSource);
69     }
70 
71     // SORTING
72 
73     /**
74      * Makes the table client sortable, that is, sortable by the user by
75      * clicking on column headers.
76      */
makeClientSortable()77     public void makeClientSortable() {
78         this.clientSortable = true;
79         table.getRowFormatter().addStyleName(0,
80                                          DataTable.HEADER_STYLE + "-sortable");
81 
82         sortIndicators = new SortIndicator[columns.length];
83         for(int i = 0; i < columns.length; i++) {
84             sortIndicators[i] = new SortIndicator(i);
85 
86             // we have to use an HTMLPanel here to preserve styles correctly and
87             // not break hover
88             // we add a <span> with a unique ID to hold the sort indicator
89             String name = columns[i][COL_TITLE];
90             String id = HTMLPanel.createUniqueId();
91             HTMLPanel panel = new HTMLPanel(name +
92                                             " <span id=\"" + id + "\"></span>");
93             panel.add(sortIndicators[i], id);
94             table.setWidget(0, i, panel);
95         }
96     }
97 
updateSortIndicators()98     private void updateSortIndicators() {
99         if (!clientSortable) {
100             return;
101         }
102 
103         SortSpec firstSpec = getFirstSortSpec();
104         for (SortIndicator indicator : sortIndicators) {
105             if (columns[indicator.column][COL_NAME].equals(firstSpec.getField())) {
106                 indicator.sortOn(firstSpec.getDirection());
107             } else {
108                 indicator.sortOff();
109             }
110         }
111     }
112 
getFirstSortSpec()113     private SortSpec getFirstSortSpec() {
114         if (sortColumns.isEmpty()) {
115             return null;
116         }
117         return sortColumns.get(0);
118     }
119 
120     /**
121      * Set column on which data is sorted.  You must call <code>refresh()</code>
122      * after this to display the results.
123      * @param columnField field of the column to sort on
124      * @param sortDirection DynamicTable.ASCENDING or DynamicTable.DESCENDING
125      */
sortOnColumn(String columnField, SortDirection sortDirection)126     public void sortOnColumn(String columnField, SortDirection sortDirection) {
127         // remove any existing sort on this column
128         for (Iterator<SortSpec> i = sortColumns.iterator(); i.hasNext(); ) {
129             if (i.next().getField().equals(columnField)) {
130                 i.remove();
131                 break;
132             }
133         }
134 
135         sortColumns.add(0, new SortSpec(columnField, sortDirection));
136         updateSortIndicators();
137     }
138 
139     /**
140      * Defaults to ascending order.
141      */
sortOnColumn(String columnField)142     public void sortOnColumn(String columnField) {
143         sortOnColumn(columnField, SortDirection.ASCENDING);
144     }
145 
clearSorts()146     public void clearSorts() {
147         sortColumns.clear();
148         updateSortIndicators();
149     }
150 
151     // PAGINATION
152 
153     /**
154      * Attach a new paginator to this table.
155      */
attachPaginator(Paginator paginator)156     public void attachPaginator(Paginator paginator) {
157         assert rowsPerPage != null;
158         paginators.add(paginator);
159         paginator.addCallback(new SimpleCallback() {
160             public void doCallback(Object source) {
161                 setPaginatorStart(((Paginator) source).getStart());
162                 fetchPage();
163             }
164         });
165         paginator.setResultsPerPage(rowsPerPage.intValue());
166     }
167 
168     /**
169      * Set the page size of this table (only useful if you attach paginators).
170      */
setRowsPerPage(int rowsPerPage)171     public void setRowsPerPage(int rowsPerPage) {
172         assert rowsPerPage > 0;
173         this.rowsPerPage = Integer.valueOf(rowsPerPage);
174         for (Paginator paginator : paginators) {
175             paginator.setResultsPerPage(rowsPerPage);
176         }
177     }
178 
179     /**
180      * Set start row for pagination.  You must call
181      * <code>refresh()</code> after this to display the results.
182      */
setPaginatorStart(int start)183     public void setPaginatorStart(int start) {
184         for (Paginator paginator : paginators) {
185             paginator.setStart(start);
186         }
187     }
188 
refreshPaginators()189     protected void refreshPaginators() {
190         for (Paginator paginator : paginators) {
191             paginator.update();
192         }
193     }
194 
updatePaginatorTotalResults(int totalResults)195     protected void updatePaginatorTotalResults(int totalResults) {
196         for (Paginator paginator : paginators) {
197             paginator.setNumTotalResults(totalResults);
198         }
199     }
200 
201 
202     // FILTERING
203 
addFilter(Filter filter)204     public void addFilter(Filter filter) {
205         filters.add(filter);
206         filter.addCallback(new SimpleCallback() {
207             public void doCallback(Object source) {
208                 setPaginatorStart(0);
209                 refresh();
210             }
211         });
212     }
213 
addFilterParams(JSONObject params)214     protected void addFilterParams(JSONObject params) {
215         for (Filter filter : filters) {
216             if (filter.isActive()) {
217                 filter.addParams(params);
218             }
219         }
220     }
221 
isAnyUserFilterActive()222     public boolean isAnyUserFilterActive() {
223         for (Filter filter : filters) {
224             if (filter.isUserControlled() && filter.isActive()) {
225                 return true;
226             }
227         }
228 
229         return false;
230     }
231 
232 
233     // DATA MANAGEMENT
234 
refresh()235     public void refresh() {
236         JSONObject params = new JSONObject();
237         addFilterParams(params);
238         dataSource.query(params, this);
239     }
240 
241     @Override
onQueryReady(Query query)242     public void onQueryReady(Query query) {
243         currentQuery = query;
244         if (!paginators.isEmpty()) {
245             query.getTotalResultCount(this);
246         }
247         fetchPage();
248     }
249 
fetchPage()250     private void fetchPage() {
251         Integer start = null, limit = null;
252         SortSpec[] sortOn = null;
253         if (!paginators.isEmpty()) {
254             Paginator p = paginators.get(0);
255             start = Integer.valueOf(p.getStart());
256             limit = Integer.valueOf(p.getResultsPerPage());
257         }
258 
259         if (!sortColumns.isEmpty()) {
260             sortOn = new SortSpec[sortColumns.size()];
261             sortColumns.toArray(sortOn);
262         }
263         currentQuery.getPage(start, limit, sortOn, this);
264     }
265 
266     @Override
handleTotalResultCount(int totalCount)267     public void handleTotalResultCount(int totalCount) {
268         updatePaginatorTotalResults(totalCount);
269         refreshPaginators();
270         notifyListenersRefreshed();
271     }
272 
handlePage(List<JSONObject> data)273     public void handlePage(List<JSONObject> data) {
274         clear();
275         addRows(data);
276         refreshPaginators();
277         notifyListenersRefreshed();
278     }
279 
getRowData(int row)280     public String[] getRowData(int row) {
281         String[] data = new String[columns.length];
282         for (int i = 0; i < columns.length; i++) {
283             if(isWidgetColumn(i)) {
284                 continue;
285             }
286             data[i] = table.getHTML(row, i);
287         }
288         return data;
289     }
290 
getDataSource()291     public DataSource getDataSource() {
292         return dataSource;
293     }
294 
setDataSource(DataSource dataSource)295     public void setDataSource(DataSource dataSource) {
296         this.dataSource = dataSource;
297     }
298 
getCurrentQuery()299     public Query getCurrentQuery() {
300         return currentQuery;
301     }
302 
303 
304     // INPUT
305 
306     @Override
onCellClicked(int row, int cell, boolean isRightClick)307     protected void onCellClicked(int row, int cell, boolean isRightClick) {
308         if (row == headerRow) {
309             if (isWidgetColumn(cell)) {
310                 // ignore sorting on widget columns
311                 return;
312             }
313             String columnName = columns[cell][COL_NAME];
314             SortDirection newSortDirection = SortDirection.ASCENDING;
315             SortSpec firstSortSpec = getFirstSortSpec();
316             // when clicking on the last sorted field, invert the sort
317             if (firstSortSpec != null && columnName.equals(firstSortSpec.getField())) {
318                 newSortDirection = invertSortDirection(firstSortSpec.getDirection());
319             }
320 
321             sortOnColumn(columnName, newSortDirection);
322             refresh();
323             return;
324         }
325 
326         super.onCellClicked(row, cell, isRightClick);
327     }
328 
invertSortDirection(SortDirection direction)329     private SortDirection invertSortDirection(SortDirection direction) {
330         return direction == SortDirection.ASCENDING ?
331                                         SortDirection.DESCENDING : SortDirection.ASCENDING;
332     }
333 
addListener(DynamicTableListener listener)334     public void addListener(DynamicTableListener listener) {
335         super.addListener(listener);
336         dynamicTableListeners.add(listener);
337     }
338 
removeListener(DynamicTableListener listener)339     public void removeListener(DynamicTableListener listener) {
340         super.removeListener(listener);
341         dynamicTableListeners.remove(listener);
342     }
343 
notifyListenersRefreshed()344     protected void notifyListenersRefreshed() {
345         for (DynamicTableListener listener : dynamicTableListeners) {
346             listener.onTableRefreshed();
347         }
348     }
349 
getSortSpecs()350     public List<SortSpec> getSortSpecs() {
351         return Collections.unmodifiableList(sortColumns);
352     }
353 
onError(JSONObject errorObject)354     public void onError(JSONObject errorObject) {
355         // nothing to do
356     }
357 }
358