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