|
@@ -15,1426 +15,1587 @@ |
15 |
15 |
|
*/ |
16 |
16 |
|
package com.google.gwt.gen2.table.client; |
17 |
17 |
|
|
18 |
|
- |
import com.google.gwt.core.client.GWT; |
19 |
|
- |
import com.google.gwt.event.dom.client.ClickEvent; |
20 |
|
- |
import com.google.gwt.event.dom.client.ClickHandler; |
21 |
|
- |
import com.google.gwt.gen2.event.shared.HandlerRegistration; |
22 |
|
- |
import com.google.gwt.gen2.table.client.CellEditor.CellEditInfo; |
23 |
|
- |
import com.google.gwt.gen2.table.client.SelectionGrid.SelectionPolicy; |
24 |
|
- |
import com.google.gwt.gen2.table.client.SortableGrid.ColumnSorter; |
25 |
|
- |
import com.google.gwt.gen2.table.client.SortableGrid.ColumnSorterCallback; |
26 |
|
- |
import com.google.gwt.gen2.table.client.TableDefinition.AbstractCellView; |
27 |
|
- |
import com.google.gwt.gen2.table.client.TableDefinition.AbstractRowView; |
|
18 |
+ |
import java.util.*; |
|
19 |
+ |
|
|
20 |
+ |
import com.google.gwt.core.client.*; |
|
21 |
+ |
import com.google.gwt.event.dom.client.*; |
|
22 |
+ |
import com.google.gwt.gen2.event.shared.*; |
|
23 |
+ |
import com.google.gwt.gen2.table.client.CellEditor.*; |
|
24 |
+ |
import com.google.gwt.gen2.table.client.FlexTable.*; |
|
25 |
+ |
import com.google.gwt.gen2.table.client.SelectionGrid.*; |
|
26 |
+ |
import com.google.gwt.gen2.table.client.SortableGrid.*; |
|
27 |
+ |
import com.google.gwt.gen2.table.client.TableDefinition.*; |
28 |
28 |
|
import com.google.gwt.gen2.table.client.TableModel.Callback; |
29 |
|
- |
import com.google.gwt.gen2.table.client.TableModelHelper.ColumnSortList; |
30 |
|
- |
import com.google.gwt.gen2.table.client.TableModelHelper.Request; |
31 |
|
- |
import com.google.gwt.gen2.table.client.TableModelHelper.Response; |
32 |
|
- |
import com.google.gwt.gen2.table.client.property.FooterProperty; |
33 |
|
- |
import com.google.gwt.gen2.table.client.property.HeaderProperty; |
34 |
|
- |
import com.google.gwt.gen2.table.client.property.MaximumWidthProperty; |
35 |
|
- |
import com.google.gwt.gen2.table.client.property.MinimumWidthProperty; |
36 |
|
- |
import com.google.gwt.gen2.table.client.property.PreferredWidthProperty; |
37 |
|
- |
import com.google.gwt.gen2.table.client.property.SortableProperty; |
38 |
|
- |
import com.google.gwt.gen2.table.client.property.TruncationProperty; |
39 |
|
- |
import com.google.gwt.gen2.table.event.client.HasPageChangeHandlers; |
40 |
|
- |
import com.google.gwt.gen2.table.event.client.HasPageCountChangeHandlers; |
41 |
|
- |
import com.google.gwt.gen2.table.event.client.HasPageLoadHandlers; |
42 |
|
- |
import com.google.gwt.gen2.table.event.client.HasPagingFailureHandlers; |
43 |
|
- |
import com.google.gwt.gen2.table.event.client.HasRowInsertionHandlers; |
44 |
|
- |
import com.google.gwt.gen2.table.event.client.HasRowRemovalHandlers; |
45 |
|
- |
import com.google.gwt.gen2.table.event.client.HasRowValueChangeHandlers; |
46 |
|
- |
import com.google.gwt.gen2.table.event.client.PageChangeEvent; |
47 |
|
- |
import com.google.gwt.gen2.table.event.client.PageChangeHandler; |
48 |
|
- |
import com.google.gwt.gen2.table.event.client.PageCountChangeEvent; |
49 |
|
- |
import com.google.gwt.gen2.table.event.client.PageCountChangeHandler; |
50 |
|
- |
import com.google.gwt.gen2.table.event.client.PageLoadEvent; |
51 |
|
- |
import com.google.gwt.gen2.table.event.client.PageLoadHandler; |
52 |
|
- |
import com.google.gwt.gen2.table.event.client.PagingFailureEvent; |
53 |
|
- |
import com.google.gwt.gen2.table.event.client.PagingFailureHandler; |
54 |
|
- |
import com.google.gwt.gen2.table.event.client.RowCountChangeEvent; |
55 |
|
- |
import com.google.gwt.gen2.table.event.client.RowCountChangeHandler; |
56 |
|
- |
import com.google.gwt.gen2.table.event.client.RowInsertionEvent; |
57 |
|
- |
import com.google.gwt.gen2.table.event.client.RowInsertionHandler; |
58 |
|
- |
import com.google.gwt.gen2.table.event.client.RowRemovalEvent; |
59 |
|
- |
import com.google.gwt.gen2.table.event.client.RowRemovalHandler; |
60 |
|
- |
import com.google.gwt.gen2.table.event.client.RowSelectionEvent; |
61 |
|
- |
import com.google.gwt.gen2.table.event.client.RowSelectionHandler; |
62 |
|
- |
import com.google.gwt.gen2.table.event.client.RowValueChangeEvent; |
63 |
|
- |
import com.google.gwt.gen2.table.event.client.RowValueChangeHandler; |
64 |
|
- |
import com.google.gwt.gen2.table.event.client.TableEvent.Row; |
65 |
|
- |
import com.google.gwt.gen2.table.client.FlexTable.FlexCellFormatter; |
66 |
|
- |
import com.google.gwt.user.client.ui.CheckBox; |
67 |
|
- |
import com.google.gwt.user.client.ui.HasHorizontalAlignment; |
68 |
|
- |
import com.google.gwt.user.client.ui.SimplePanel; |
69 |
|
- |
import com.google.gwt.user.client.ui.SourcesTableEvents; |
70 |
|
- |
import com.google.gwt.user.client.ui.TableListener; |
71 |
|
- |
import com.google.gwt.user.client.ui.Widget; |
72 |
|
- |
import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant; |
73 |
|
- |
import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant; |
74 |
|
- |
|
75 |
|
- |
import java.util.ArrayList; |
76 |
|
- |
import java.util.HashSet; |
77 |
|
- |
import java.util.Iterator; |
78 |
|
- |
import java.util.List; |
79 |
|
- |
import java.util.NoSuchElementException; |
80 |
|
- |
import java.util.Set; |
|
29 |
+ |
import com.google.gwt.gen2.table.client.TableModelHelper.*; |
|
30 |
+ |
import com.google.gwt.gen2.table.client.property.*; |
|
31 |
+ |
import com.google.gwt.gen2.table.event.client.*; |
|
32 |
+ |
import com.google.gwt.gen2.table.event.client.TableEvent.*; |
|
33 |
+ |
import com.google.gwt.user.client.ui.*; |
|
34 |
+ |
import com.google.gwt.user.client.ui.HasHorizontalAlignment.*; |
|
35 |
+ |
import com.google.gwt.user.client.ui.HasVerticalAlignment.*; |
81 |
36 |
|
|
82 |
37 |
|
/** |
83 |
38 |
|
* An {@link AbstractScrollTable} that acts as a view for an underlying |
84 |
39 |
|
* {@link MutableTableModel}. |
85 |
|
- |
* |
|
40 |
+ |
* |
86 |
41 |
|
* @param <RowType> the data type of the row values |
87 |
42 |
|
*/ |
88 |
|
- |
public class PagingScrollTable<RowType> extends AbstractScrollTable implements |
89 |
|
- |
HasTableDefinition<RowType>, HasPageCountChangeHandlers, |
90 |
|
- |
HasPageLoadHandlers, HasPageChangeHandlers, HasPagingFailureHandlers { |
91 |
|
- |
/** |
92 |
|
- |
* A custom {@link AbstractCellView} used by the {@link PagingScrollTable}. |
93 |
|
- |
* |
94 |
|
- |
* @param <RowType> the type of the row values |
95 |
|
- |
*/ |
96 |
|
- |
protected static class PagingScrollTableCellView<RowType> extends |
97 |
|
- |
AbstractCellView<RowType> { |
98 |
|
- |
private PagingScrollTable<RowType> table; |
99 |
|
- |
|
100 |
|
- |
public PagingScrollTableCellView(PagingScrollTable<RowType> table) { |
101 |
|
- |
super(table); |
102 |
|
- |
this.table = table; |
|
43 |
+ |
public class PagingScrollTable<RowType> extends AbstractScrollTable implements HasTableDefinition<RowType>, |
|
44 |
+ |
HasPageCountChangeHandlers, |
|
45 |
+ |
HasPageLoadHandlers, |
|
46 |
+ |
HasPageChangeHandlers, |
|
47 |
+ |
HasPagingFailureHandlers |
|
48 |
+ |
{ |
|
49 |
+ |
/** |
|
50 |
+ |
* A custom {@link AbstractCellView} used by the {@link PagingScrollTable}. |
|
51 |
+ |
* |
|
52 |
+ |
* @param <RowType> the type of the row values |
|
53 |
+ |
*/ |
|
54 |
+ |
protected static class PagingScrollTableCellView<RowType> extends AbstractCellView<RowType> |
|
55 |
+ |
{ |
|
56 |
+ |
private PagingScrollTable<RowType> table; |
|
57 |
+ |
|
|
58 |
+ |
public PagingScrollTableCellView( PagingScrollTable<RowType> table ) |
|
59 |
+ |
{ |
|
60 |
+ |
super( table ); |
|
61 |
+ |
this.table = table; |
|
62 |
+ |
} |
|
63 |
+ |
|
|
64 |
+ |
@Override |
|
65 |
+ |
public void setHorizontalAlignment( HorizontalAlignmentConstant align ) |
|
66 |
+ |
{ |
|
67 |
+ |
table.getDataTable().getCellFormatter().setHorizontalAlignment( getRowIndex(), getCellIndex(), align ); |
|
68 |
+ |
} |
|
69 |
+ |
|
|
70 |
+ |
@Override |
|
71 |
+ |
public void setHTML( String html ) |
|
72 |
+ |
{ |
|
73 |
+ |
table.getDataTable().setHTML( getRowIndex(), getCellIndex(), html ); |
|
74 |
+ |
} |
|
75 |
+ |
|
|
76 |
+ |
@Override |
|
77 |
+ |
public void setStyleAttribute( String attr, String value ) |
|
78 |
+ |
{ |
|
79 |
+ |
table.getDataTable().getFixedWidthGridCellFormatter().getRawElement( getRowIndex(), getCellIndex() ).getStyle().setProperty( attr, value ); |
|
80 |
+ |
} |
|
81 |
+ |
|
|
82 |
+ |
@Override |
|
83 |
+ |
public void setStyleName( String stylename ) |
|
84 |
+ |
{ |
|
85 |
+ |
table.getDataTable().getCellFormatter().setStyleName( getRowIndex(), getCellIndex(), stylename ); |
|
86 |
+ |
} |
|
87 |
+ |
|
|
88 |
+ |
@Override |
|
89 |
+ |
public void setText( String text ) |
|
90 |
+ |
{ |
|
91 |
+ |
table.getDataTable().setText( getRowIndex(), getCellIndex(), text ); |
|
92 |
+ |
} |
|
93 |
+ |
|
|
94 |
+ |
@Override |
|
95 |
+ |
public void setVerticalAlignment( VerticalAlignmentConstant align ) |
|
96 |
+ |
{ |
|
97 |
+ |
table.getDataTable().getCellFormatter().setVerticalAlignment( getRowIndex(), getCellIndex(), align ); |
|
98 |
+ |
} |
|
99 |
+ |
|
|
100 |
+ |
@Override |
|
101 |
+ |
public void setWidget( Widget widget ) |
|
102 |
+ |
{ |
|
103 |
+ |
table.getDataTable().setWidget( getRowIndex(), getCellIndex(), widget ); |
|
104 |
+ |
} |
103 |
105 |
|
} |
104 |
106 |
|
|
105 |
|
- |
@Override |
106 |
|
- |
public void setHorizontalAlignment(HorizontalAlignmentConstant align) { |
107 |
|
- |
table.getDataTable().getCellFormatter().setHorizontalAlignment( |
108 |
|
- |
getRowIndex(), getCellIndex(), align); |
|
107 |
+ |
/** |
|
108 |
+ |
* A custom {@link AbstractRowView} used by the {@link PagingScrollTable}. |
|
109 |
+ |
* |
|
110 |
+ |
* @param <RowType> the type of the row values |
|
111 |
+ |
*/ |
|
112 |
+ |
protected static class PagingScrollTableRowView<RowType> extends AbstractRowView<RowType> |
|
113 |
+ |
{ |
|
114 |
+ |
private PagingScrollTable<RowType> table; |
|
115 |
+ |
|
|
116 |
+ |
public PagingScrollTableRowView( PagingScrollTable<RowType> table ) |
|
117 |
+ |
{ |
|
118 |
+ |
super( new PagingScrollTableCellView<RowType>( table ) ); |
|
119 |
+ |
this.table = table; |
|
120 |
+ |
} |
|
121 |
+ |
|
|
122 |
+ |
@Override |
|
123 |
+ |
public void setStyleAttribute( String attr, String value ) |
|
124 |
+ |
{ |
|
125 |
+ |
table.getDataTable().getFixedWidthGridRowFormatter().getRawElement( getRowIndex() ).getStyle().setProperty( attr, value ); |
|
126 |
+ |
} |
|
127 |
+ |
|
|
128 |
+ |
@Override |
|
129 |
+ |
public void setStyleName( String stylename ) |
|
130 |
+ |
{ |
|
131 |
+ |
// If the row is selected, add the selected style name back |
|
132 |
+ |
if ( table.getDataTable().isRowSelected( getRowIndex() ) ) |
|
133 |
+ |
{ |
|
134 |
+ |
stylename += " selected"; |
|
135 |
+ |
} |
|
136 |
+ |
table.getDataTable().getRowFormatter().setStyleName( getRowIndex(), stylename ); |
|
137 |
+ |
} |
109 |
138 |
|
} |
110 |
139 |
|
|
111 |
|
- |
@Override |
112 |
|
- |
public void setHTML(String html) { |
113 |
|
- |
table.getDataTable().setHTML(getRowIndex(), getCellIndex(), html); |
|
140 |
+ |
/** |
|
141 |
+ |
* Information about a column header. |
|
142 |
+ |
*/ |
|
143 |
+ |
private static class ColumnHeaderInfo |
|
144 |
+ |
{ |
|
145 |
+ |
private int rowSpan = 1; |
|
146 |
+ |
private Object header; |
|
147 |
+ |
|
|
148 |
+ |
public ColumnHeaderInfo( Object header ) |
|
149 |
+ |
{ |
|
150 |
+ |
this.header = (header == null) ? "" : header; |
|
151 |
+ |
} |
|
152 |
+ |
|
|
153 |
+ |
public ColumnHeaderInfo( Object header, int rowSpan ) |
|
154 |
+ |
{ |
|
155 |
+ |
this.header = (header == null) ? " " : header; |
|
156 |
+ |
this.rowSpan = rowSpan; |
|
157 |
+ |
} |
|
158 |
+ |
|
|
159 |
+ |
@Override |
|
160 |
+ |
public boolean equals( Object o ) |
|
161 |
+ |
{ |
|
162 |
+ |
if ( o == null ) |
|
163 |
+ |
{ |
|
164 |
+ |
return false; |
|
165 |
+ |
} |
|
166 |
+ |
if ( o instanceof ColumnHeaderInfo ) |
|
167 |
+ |
{ |
|
168 |
+ |
ColumnHeaderInfo info = (ColumnHeaderInfo) o; |
|
169 |
+ |
return (rowSpan == info.rowSpan) && header.equals( info.header ); |
|
170 |
+ |
} |
|
171 |
+ |
return false; |
|
172 |
+ |
} |
|
173 |
+ |
|
|
174 |
+ |
public Object getHeader() |
|
175 |
+ |
{ |
|
176 |
+ |
return header; |
|
177 |
+ |
} |
|
178 |
+ |
|
|
179 |
+ |
public int getRowSpan() |
|
180 |
+ |
{ |
|
181 |
+ |
return rowSpan; |
|
182 |
+ |
} |
|
183 |
+ |
|
|
184 |
+ |
public void incrementRowSpan() |
|
185 |
+ |
{ |
|
186 |
+ |
rowSpan++; |
|
187 |
+ |
} |
|
188 |
+ |
} |
|
189 |
+ |
|
|
190 |
+ |
/** |
|
191 |
+ |
* An iterator over the visible rows in an iterator over many rows. |
|
192 |
+ |
*/ |
|
193 |
+ |
private class VisibleRowsIterator implements Iterator<RowType> |
|
194 |
+ |
{ |
|
195 |
+ |
/** |
|
196 |
+ |
* The iterator of row data. |
|
197 |
+ |
*/ |
|
198 |
+ |
private Iterator<RowType> rows; |
|
199 |
+ |
|
|
200 |
+ |
/** |
|
201 |
+ |
* The current row of the rows iterator. |
|
202 |
+ |
*/ |
|
203 |
+ |
private int curRow; |
|
204 |
+ |
|
|
205 |
+ |
/** |
|
206 |
+ |
* The last visible row in the grid. |
|
207 |
+ |
*/ |
|
208 |
+ |
private int lastVisibleRow; |
|
209 |
+ |
|
|
210 |
+ |
/** |
|
211 |
+ |
* Constructor. |
|
212 |
+ |
* |
|
213 |
+ |
* @param rows the iterator over row data |
|
214 |
+ |
* @param firstRow the first absolute row of the rows iterator |
|
215 |
+ |
* @param firstVisibleRow the first visible row in this grid |
|
216 |
+ |
* @param lastVisibleRow the last visible row in this grid |
|
217 |
+ |
*/ |
|
218 |
+ |
public VisibleRowsIterator( Iterator<RowType> rows, int firstRow, int firstVisibleRow, int lastVisibleRow ) |
|
219 |
+ |
{ |
|
220 |
+ |
this.curRow = firstRow; |
|
221 |
+ |
this.lastVisibleRow = lastVisibleRow; |
|
222 |
+ |
|
|
223 |
+ |
// Iterate up to the first row |
|
224 |
+ |
while ( curRow < firstVisibleRow && rows.hasNext() ) |
|
225 |
+ |
{ |
|
226 |
+ |
rows.next(); |
|
227 |
+ |
curRow++; |
|
228 |
+ |
} |
|
229 |
+ |
this.rows = rows; |
|
230 |
+ |
} |
|
231 |
+ |
|
|
232 |
+ |
public boolean hasNext() |
|
233 |
+ |
{ |
|
234 |
+ |
return (curRow <= lastVisibleRow && rows.hasNext()); |
|
235 |
+ |
} |
|
236 |
+ |
|
|
237 |
+ |
public RowType next() |
|
238 |
+ |
{ |
|
239 |
+ |
// Check that the next row exists |
|
240 |
+ |
if ( !hasNext() ) |
|
241 |
+ |
{ |
|
242 |
+ |
throw new NoSuchElementException(); |
|
243 |
+ |
} |
|
244 |
+ |
return rows.next(); |
|
245 |
+ |
} |
|
246 |
+ |
|
|
247 |
+ |
public void remove() |
|
248 |
+ |
{ |
|
249 |
+ |
throw new UnsupportedOperationException( "Remove not supported" ); |
|
250 |
+ |
} |
|
251 |
+ |
} |
|
252 |
+ |
|
|
253 |
+ |
/** |
|
254 |
+ |
* The bulk render used to render the contents of this table. |
|
255 |
+ |
*/ |
|
256 |
+ |
private FixedWidthGridBulkRenderer<RowType> bulkRenderer = null; |
|
257 |
+ |
|
|
258 |
+ |
/** |
|
259 |
+ |
* The wrapper around the empty table widget. |
|
260 |
+ |
*/ |
|
261 |
+ |
private SimplePanel emptyTableWidgetWrapper = new SimplePanel(); |
|
262 |
+ |
|
|
263 |
+ |
/** |
|
264 |
+ |
* The definition of the columns in the table. |
|
265 |
+ |
*/ |
|
266 |
+ |
private TableDefinition<RowType> tableDefinition = null; |
|
267 |
+ |
|
|
268 |
+ |
/** |
|
269 |
+ |
* The current visible page. |
|
270 |
+ |
*/ |
|
271 |
+ |
private int currentPage = -1; |
|
272 |
+ |
|
|
273 |
+ |
/** |
|
274 |
+ |
* The last request that was sent to the {@link TableModel}. |
|
275 |
+ |
*/ |
|
276 |
+ |
private Request lastRequest = null; |
|
277 |
+ |
|
|
278 |
+ |
/** |
|
279 |
+ |
* A boolean indicating that cross page selection is enabled. |
|
280 |
+ |
*/ |
|
281 |
+ |
private boolean isCrossPageSelectionEnabled; |
|
282 |
+ |
|
|
283 |
+ |
/** |
|
284 |
+ |
* The set of selected row values. |
|
285 |
+ |
*/ |
|
286 |
+ |
private Set<RowType> selectedRowValues = new HashSet<RowType>(); |
|
287 |
+ |
|
|
288 |
+ |
/** |
|
289 |
+ |
* A boolean indicating that the footer should be generated automatically. |
|
290 |
+ |
*/ |
|
291 |
+ |
private boolean isFooterGenerated; |
|
292 |
+ |
|
|
293 |
+ |
/** |
|
294 |
+ |
* A boolean indicating that the header should be generated automatically. |
|
295 |
+ |
*/ |
|
296 |
+ |
private boolean isHeaderGenerated; |
|
297 |
+ |
|
|
298 |
+ |
/** |
|
299 |
+ |
* A boolean indicating that the page is currently being loaded. |
|
300 |
+ |
*/ |
|
301 |
+ |
private boolean isPageLoading; |
|
302 |
+ |
|
|
303 |
+ |
/** |
|
304 |
+ |
* The old page count, used to detect when the number of pages changes. |
|
305 |
+ |
*/ |
|
306 |
+ |
private int oldPageCount; |
|
307 |
+ |
|
|
308 |
+ |
/** |
|
309 |
+ |
* The number of rows per page. If the number of rows per page is equal to the |
|
310 |
+ |
* number of rows, paging is disabled because only one page exists. |
|
311 |
+ |
*/ |
|
312 |
+ |
private int pageSize = 0; |
|
313 |
+ |
|
|
314 |
+ |
/** |
|
315 |
+ |
* The callback that handles page requests. |
|
316 |
+ |
*/ |
|
317 |
+ |
private Callback<RowType> pagingCallback = new Callback<RowType>() |
|
318 |
+ |
{ |
|
319 |
+ |
public void onFailure( Throwable caught ) |
|
320 |
+ |
{ |
|
321 |
+ |
isPageLoading = false; |
|
322 |
+ |
fireEvent( new PagingFailureEvent( caught ) ); |
|
323 |
+ |
} |
|
324 |
+ |
|
|
325 |
+ |
public void onRowsReady( Request request, Response<RowType> response ) |
|
326 |
+ |
{ |
|
327 |
+ |
if ( lastRequest == request ) |
|
328 |
+ |
{ |
|
329 |
+ |
setData( request.getStartRow(), response.getRowValues() ); |
|
330 |
+ |
lastRequest = null; |
|
331 |
+ |
} |
|
332 |
+ |
} |
|
333 |
+ |
}; |
|
334 |
+ |
|
|
335 |
+ |
/** |
|
336 |
+ |
* The values associated with each row. This is an optional list of data that |
|
337 |
+ |
* ties the visible content in each row to an underlying object. |
|
338 |
+ |
*/ |
|
339 |
+ |
private List<RowType> rowValues = new ArrayList<RowType>(); |
|
340 |
+ |
|
|
341 |
+ |
/** |
|
342 |
+ |
* The view of this table. |
|
343 |
+ |
*/ |
|
344 |
+ |
private AbstractRowView<RowType> rowView = new PagingScrollTableRowView<RowType>( this ); |
|
345 |
+ |
|
|
346 |
+ |
/** |
|
347 |
+ |
* The {@link CheckBox} used to select all rows. |
|
348 |
+ |
*/ |
|
349 |
+ |
private Widget selectAllWidget; |
|
350 |
+ |
|
|
351 |
+ |
/** |
|
352 |
+ |
* The underlying table model. |
|
353 |
+ |
*/ |
|
354 |
+ |
private TableModel<RowType> tableModel; |
|
355 |
+ |
|
|
356 |
+ |
/** |
|
357 |
+ |
* The {@link RendererCallback} used when table rendering completes. |
|
358 |
+ |
*/ |
|
359 |
+ |
private RendererCallback tableRendererCallback = new RendererCallback() |
|
360 |
+ |
{ |
|
361 |
+ |
public void onRendered() |
|
362 |
+ |
{ |
|
363 |
+ |
onDataTableRendered(); |
|
364 |
+ |
} |
|
365 |
+ |
}; |
|
366 |
+ |
|
|
367 |
+ |
/** |
|
368 |
+ |
* The columns that are currently visible. |
|
369 |
+ |
*/ |
|
370 |
+ |
private List<ColumnDefinition<RowType, ?>> visibleColumns = new ArrayList<ColumnDefinition<RowType, ?>>(); |
|
371 |
+ |
|
|
372 |
+ |
/** |
|
373 |
+ |
* The boolean indicating that the header tables are obsolete. |
|
374 |
+ |
*/ |
|
375 |
+ |
private boolean headersObsolete; |
|
376 |
+ |
|
|
377 |
+ |
/** |
|
378 |
+ |
* Construct a new {@link PagingScrollTable}. |
|
379 |
+ |
* |
|
380 |
+ |
* @param tableModel the underlying table model |
|
381 |
+ |
* @param tableDefinition the column definitions |
|
382 |
+ |
*/ |
|
383 |
+ |
public PagingScrollTable( TableModel<RowType> tableModel, TableDefinition<RowType> tableDefinition ) |
|
384 |
+ |
{ |
|
385 |
+ |
this( tableModel, new FixedWidthGrid(), new FixedWidthFlexTable(), tableDefinition ); |
|
386 |
+ |
isHeaderGenerated = true; |
|
387 |
+ |
isFooterGenerated = true; |
|
388 |
+ |
} |
|
389 |
+ |
|
|
390 |
+ |
/** |
|
391 |
+ |
* Construct a new {@link PagingScrollTable}. |
|
392 |
+ |
* |
|
393 |
+ |
* @param tableModel the underlying table model |
|
394 |
+ |
* @param dataTable the table used to display data |
|
395 |
+ |
* @param headerTable the header table |
|
396 |
+ |
* @param tableDefinition the column definitions |
|
397 |
+ |
*/ |
|
398 |
+ |
public PagingScrollTable( TableModel<RowType> tableModel, FixedWidthGrid dataTable, FixedWidthFlexTable headerTable, TableDefinition<RowType> tableDefinition ) |
|
399 |
+ |
{ |
|
400 |
+ |
this( tableModel, dataTable, headerTable, tableDefinition, GWT.<ScrollTableImages>create( ScrollTableImages.class ) ); |
|
401 |
+ |
} |
|
402 |
+ |
|
|
403 |
+ |
/** |
|
404 |
+ |
* Construct a new {@link PagingScrollTable} with custom images. |
|
405 |
+ |
* |
|
406 |
+ |
* @param tableModel the underlying table model |
|
407 |
+ |
* @param dataTable the table used to display data |
|
408 |
+ |
* @param headerTable the header table |
|
409 |
+ |
* @param tableDefinition the column definitions |
|
410 |
+ |
* @param images the images to use in the table |
|
411 |
+ |
*/ |
|
412 |
+ |
public PagingScrollTable( TableModel<RowType> tableModel, FixedWidthGrid dataTable, FixedWidthFlexTable headerTable, TableDefinition<RowType> tableDefinition, ScrollTableImages images ) |
|
413 |
+ |
{ |
|
414 |
+ |
super( dataTable, headerTable, images ); |
|
415 |
+ |
this.tableModel = tableModel; |
|
416 |
+ |
setTableDefinition( tableDefinition ); |
|
417 |
+ |
refreshVisibleColumnDefinitions(); |
|
418 |
+ |
oldPageCount = getPageCount(); |
|
419 |
+ |
|
|
420 |
+ |
// Setup the empty table widget wrapper |
|
421 |
+ |
emptyTableWidgetWrapper.getElement().getStyle().setProperty( "width", "100%" ); |
|
422 |
+ |
emptyTableWidgetWrapper.getElement().getStyle().setProperty( "overflow", "hidden" ); |
|
423 |
+ |
emptyTableWidgetWrapper.getElement().getStyle().setPropertyPx( "border", 0 ); |
|
424 |
+ |
emptyTableWidgetWrapper.getElement().getStyle().setPropertyPx( "margin", 0 ); |
|
425 |
+ |
emptyTableWidgetWrapper.getElement().getStyle().setPropertyPx( "padding", 0 ); |
|
426 |
+ |
insert( emptyTableWidgetWrapper, getAbsoluteElement(), 2, true ); |
|
427 |
+ |
setEmptyTableWidgetVisible( false ); |
|
428 |
+ |
|
|
429 |
+ |
// Listen to table model events |
|
430 |
+ |
tableModel.addRowCountChangeHandler( new RowCountChangeHandler() |
|
431 |
+ |
{ |
|
432 |
+ |
public void onRowCountChange( RowCountChangeEvent event ) |
|
433 |
+ |
{ |
|
434 |
+ |
int pageCount = getPageCount(); |
|
435 |
+ |
if ( pageCount != oldPageCount ) |
|
436 |
+ |
{ |
|
437 |
+ |
fireEvent( new PageCountChangeEvent( oldPageCount, pageCount ) ); |
|
438 |
+ |
oldPageCount = pageCount; |
|
439 |
+ |
} |
|
440 |
+ |
} |
|
441 |
+ |
} ); |
|
442 |
+ |
if ( tableModel instanceof HasRowInsertionHandlers ) |
|
443 |
+ |
{ |
|
444 |
+ |
((HasRowInsertionHandlers) tableModel).addRowInsertionHandler( new RowInsertionHandler() |
|
445 |
+ |
{ |
|
446 |
+ |
public void onRowInsertion( RowInsertionEvent event ) |
|
447 |
+ |
{ |
|
448 |
+ |
insertAbsoluteRow( event.getRowIndex() ); |
|
449 |
+ |
} |
|
450 |
+ |
} ); |
|
451 |
+ |
} |
|
452 |
+ |
if ( tableModel instanceof HasRowRemovalHandlers ) |
|
453 |
+ |
{ |
|
454 |
+ |
((HasRowRemovalHandlers) tableModel).addRowRemovalHandler( new RowRemovalHandler() |
|
455 |
+ |
{ |
|
456 |
+ |
public void onRowRemoval( RowRemovalEvent event ) |
|
457 |
+ |
{ |
|
458 |
+ |
removeAbsoluteRow( event.getRowIndex() ); |
|
459 |
+ |
} |
|
460 |
+ |
} ); |
|
461 |
+ |
} |
|
462 |
+ |
if ( tableModel instanceof HasRowValueChangeHandlers ) |
|
463 |
+ |
{ |
|
464 |
+ |
((HasRowValueChangeHandlers<RowType>) tableModel).addRowValueChangeHandler( new RowValueChangeHandler<RowType>() |
|
465 |
+ |
{ |
|
466 |
+ |
public void onRowValueChange( RowValueChangeEvent<RowType> event ) |
|
467 |
+ |
{ |
|
468 |
+ |
int rowIndex = event.getRowIndex(); |
|
469 |
+ |
if ( rowIndex < getAbsoluteFirstRowIndex() || rowIndex > getAbsoluteLastRowIndex() ) |
|
470 |
+ |
{ |
|
471 |
+ |
return; |
|
472 |
+ |
} |
|
473 |
+ |
setRowValue( rowIndex - getAbsoluteFirstRowIndex(), event.getRowValue() ); |
|
474 |
+ |
} |
|
475 |
+ |
} ); |
|
476 |
+ |
} |
|
477 |
+ |
|
|
478 |
+ |
// Listen for cell click events |
|
479 |
+ |
dataTable.addTableListener( new TableListener() |
|
480 |
+ |
{ |
|
481 |
+ |
public void onCellClicked( SourcesTableEvents sender, int row, int cell ) |
|
482 |
+ |
{ |
|
483 |
+ |
editCell( row, cell ); |
|
484 |
+ |
} |
|
485 |
+ |
} ); |
|
486 |
+ |
|
|
487 |
+ |
// Override the column sorter |
|
488 |
+ |
if ( dataTable.getColumnSorter() == null ) |
|
489 |
+ |
{ |
|
490 |
+ |
ColumnSorter sorter = new ColumnSorter() |
|
491 |
+ |
{ |
|
492 |
+ |
@Override |
|
493 |
+ |
public void onSortColumn( SortableGrid grid, ColumnSortList sortList, ColumnSorterCallback callback ) |
|
494 |
+ |
{ |
|
495 |
+ |
reloadPage(); |
|
496 |
+ |
callback.onSortingComplete(); |
|
497 |
+ |
} |
|
498 |
+ |
}; |
|
499 |
+ |
dataTable.setColumnSorter( sorter ); |
|
500 |
+ |
} |
|
501 |
+ |
|
|
502 |
+ |
// Listen for selection events |
|
503 |
+ |
dataTable.addRowSelectionHandler( new RowSelectionHandler() |
|
504 |
+ |
{ |
|
505 |
+ |
public void onRowSelection( RowSelectionEvent event ) |
|
506 |
+ |
{ |
|
507 |
+ |
if ( isPageLoading ) |
|
508 |
+ |
{ |
|
509 |
+ |
return; |
|
510 |
+ |
} |
|
511 |
+ |
Set<Row> deselected = event.getDeselectedRows(); |
|
512 |
+ |
for ( Row row : deselected ) |
|
513 |
+ |
{ |
|
514 |
+ |
selectedRowValues.remove( getRowValue( row.getRowIndex() ) ); |
|
515 |
+ |
} |
|
516 |
+ |
Set<Row> selected = event.getSelectedRows(); |
|
517 |
+ |
for ( Row row : selected ) |
|
518 |
+ |
{ |
|
519 |
+ |
selectedRowValues.add( getRowValue( row.getRowIndex() ) ); |
|
520 |
+ |
} |
|
521 |
+ |
} |
|
522 |
+ |
} ); |
|
523 |
+ |
} |
|
524 |
+ |
|
|
525 |
+ |
public HandlerRegistration addPageChangeHandler( PageChangeHandler handler ) |
|
526 |
+ |
{ |
|
527 |
+ |
return addHandler( PageChangeEvent.TYPE, handler ); |
|
528 |
+ |
} |
|
529 |
+ |
|
|
530 |
+ |
public HandlerRegistration addPageCountChangeHandler( PageCountChangeHandler handler ) |
|
531 |
+ |
{ |
|
532 |
+ |
return addHandler( PageCountChangeEvent.TYPE, handler ); |
|
533 |
+ |
} |
|
534 |
+ |
|
|
535 |
+ |
public HandlerRegistration addPageLoadHandler( PageLoadHandler handler ) |
|
536 |
+ |
{ |
|
537 |
+ |
return addHandler( PageLoadEvent.TYPE, handler ); |
|
538 |
+ |
} |
|
539 |
+ |
|
|
540 |
+ |
public HandlerRegistration addPagingFailureHandler( PagingFailureHandler handler ) |
|
541 |
+ |
{ |
|
542 |
+ |
return addHandler( PagingFailureEvent.TYPE, handler ); |
|
543 |
+ |
} |
|
544 |
+ |
|
|
545 |
+ |
/** |
|
546 |
+ |
* @return the absolute index of the first visible row |
|
547 |
+ |
*/ |
|
548 |
+ |
public int getAbsoluteFirstRowIndex() |
|
549 |
+ |
{ |
|
550 |
+ |
return currentPage * pageSize; |
|
551 |
+ |
} |
|
552 |
+ |
|
|
553 |
+ |
/** |
|
554 |
+ |
* @return the absolute index of the last visible row |
|
555 |
+ |
*/ |
|
556 |
+ |
public int getAbsoluteLastRowIndex() |
|
557 |
+ |
{ |
|
558 |
+ |
if ( tableModel.getRowCount() < 0 ) |
|
559 |
+ |
{ |
|
560 |
+ |
// Unknown row count, so just return based on current page |
|
561 |
+ |
return (currentPage + 1) * pageSize - 1; |
|
562 |
+ |
} |
|
563 |
+ |
else if ( pageSize == 0 ) |
|
564 |
+ |
{ |
|
565 |
+ |
// Only one page, so return row count |
|
566 |
+ |
return tableModel.getRowCount() - 1; |
|
567 |
+ |
} |
|
568 |
+ |
return Math.min( tableModel.getRowCount(), (currentPage + 1) * pageSize ) - 1; |
|
569 |
+ |
} |
|
570 |
+ |
|
|
571 |
+ |
/** |
|
572 |
+ |
* @return the current page |
|
573 |
+ |
*/ |
|
574 |
+ |
public int getCurrentPage() |
|
575 |
+ |
{ |
|
576 |
+ |
return currentPage; |
|
577 |
+ |
} |
|
578 |
+ |
|
|
579 |
+ |
/** |
|
580 |
+ |
* @return the widget displayed when the data table is empty |
|
581 |
+ |
*/ |
|
582 |
+ |
public Widget getEmptyTableWidget() |
|
583 |
+ |
{ |
|
584 |
+ |
return emptyTableWidgetWrapper.getWidget(); |
114 |
585 |
|
} |
115 |
586 |
|
|
116 |
587 |
|
@Override |
117 |
|
- |
public void setStyleAttribute(String attr, String value) { |
118 |
|
- |
table.getDataTable().getFixedWidthGridCellFormatter().getRawElement( |
119 |
|
- |
getRowIndex(), getCellIndex()).getStyle().setProperty(attr, value); |
|
588 |
+ |
public int getMaximumColumnWidth( int column ) |
|
589 |
+ |
{ |
|
590 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
591 |
+ |
if ( colDef == null ) |
|
592 |
+ |
{ |
|
593 |
+ |
return -1; |
|
594 |
+ |
} |
|
595 |
+ |
return colDef.getColumnProperty( MaximumWidthProperty.TYPE ).getMaximumColumnWidth(); |
120 |
596 |
|
} |
121 |
597 |
|
|
122 |
598 |
|
@Override |
123 |
|
- |
public void setStyleName(String stylename) { |
124 |
|
- |
table.getDataTable().getCellFormatter().setStyleName(getRowIndex(), |
125 |
|
- |
getCellIndex(), stylename); |
|
599 |
+ |
public int getMinimumColumnWidth( int column ) |
|
600 |
+ |
{ |
|
601 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
602 |
+ |
if ( colDef == null ) |
|
603 |
+ |
{ |
|
604 |
+ |
return FixedWidthGrid.MIN_COLUMN_WIDTH; |
|
605 |
+ |
} |
|
606 |
+ |
int minWidth = colDef.getColumnProperty( MinimumWidthProperty.TYPE ).getMinimumColumnWidth(); |
|
607 |
+ |
return Math.max( FixedWidthGrid.MIN_COLUMN_WIDTH, minWidth ); |
|
608 |
+ |
} |
|
609 |
+ |
|
|
610 |
+ |
/** |
|
611 |
+ |
* @return the number of pages, or -1 if not known |
|
612 |
+ |
*/ |
|
613 |
+ |
public int getPageCount() |
|
614 |
+ |
{ |
|
615 |
+ |
if ( pageSize < 1 ) |
|
616 |
+ |
{ |
|
617 |
+ |
return 1; |
|
618 |
+ |
} |
|
619 |
+ |
else |
|
620 |
+ |
{ |
|
621 |
+ |
int numDataRows = tableModel.getRowCount(); |
|
622 |
+ |
if ( numDataRows < 0 ) |
|
623 |
+ |
{ |
|
624 |
+ |
return -1; |
|
625 |
+ |
} |
|
626 |
+ |
return (int) Math.ceil( numDataRows / (pageSize + 0.0) ); |
|
627 |
+ |
} |
|
628 |
+ |
} |
|
629 |
+ |
|
|
630 |
+ |
/** |
|
631 |
+ |
* @return the number of rows per page |
|
632 |
+ |
*/ |
|
633 |
+ |
public int getPageSize() |
|
634 |
+ |
{ |
|
635 |
+ |
return pageSize; |
126 |
636 |
|
} |
127 |
637 |
|
|
128 |
638 |
|
@Override |
129 |
|
- |
public void setText(String text) { |
130 |
|
- |
table.getDataTable().setText(getRowIndex(), getCellIndex(), text); |
|
639 |
+ |
public int getPreferredColumnWidth( int column ) |
|
640 |
+ |
{ |
|
641 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
642 |
+ |
if ( colDef == null ) |
|
643 |
+ |
{ |
|
644 |
+ |
return FixedWidthGrid.DEFAULT_COLUMN_WIDTH; |
|
645 |
+ |
} |
|
646 |
+ |
return colDef.getColumnProperty( PreferredWidthProperty.TYPE ).getPreferredColumnWidth(); |
|
647 |
+ |
} |
|
648 |
+ |
|
|
649 |
+ |
/** |
|
650 |
+ |
* Get the value associated with a row. |
|
651 |
+ |
* |
|
652 |
+ |
* @param row the row index |
|
653 |
+ |
* |
|
654 |
+ |
* @return the value associated with the row |
|
655 |
+ |
*/ |
|
656 |
+ |
public RowType getRowValue( int row ) |
|
657 |
+ |
{ |
|
658 |
+ |
if ( rowValues.size() <= row ) |
|
659 |
+ |
{ |
|
660 |
+ |
return null; |
|
661 |
+ |
} |
|
662 |
+ |
return rowValues.get( row ); |
|
663 |
+ |
} |
|
664 |
+ |
|
|
665 |
+ |
/** |
|
666 |
+ |
* Get the selected row values. If cross page selection is enabled, this will |
|
667 |
+ |
* include row values selected on all pages. |
|
668 |
+ |
* |
|
669 |
+ |
* @return the selected row values |
|
670 |
+ |
* |
|
671 |
+ |
* @see #setCrossPageSelectionEnabled(boolean) |
|
672 |
+ |
*/ |
|
673 |
+ |
public Set<RowType> getSelectedRowValues() |
|
674 |
+ |
{ |
|
675 |
+ |
return selectedRowValues; |
|
676 |
+ |
} |
|
677 |
+ |
|
|
678 |
+ |
public TableDefinition<RowType> getTableDefinition() |
|
679 |
+ |
{ |
|
680 |
+ |
return tableDefinition; |
|
681 |
+ |
} |
|
682 |
+ |
|
|
683 |
+ |
/** |
|
684 |
+ |
* @return the table model |
|
685 |
+ |
*/ |
|
686 |
+ |
public TableModel<RowType> getTableModel() |
|
687 |
+ |
{ |
|
688 |
+ |
return tableModel; |
|
689 |
+ |
} |
|
690 |
+ |
|
|
691 |
+ |
/** |
|
692 |
+ |
* Go to the first page. |
|
693 |
+ |
*/ |
|
694 |
+ |
public void gotoFirstPage() |
|
695 |
+ |
{ |
|
696 |
+ |
gotoPage( 0, false ); |
|
697 |
+ |
} |
|
698 |
+ |
|
|
699 |
+ |
/** |
|
700 |
+ |
* Go to the last page. If the number of pages is not known, this method is |
|
701 |
+ |
* ignored. |
|
702 |
+ |
*/ |
|
703 |
+ |
public void gotoLastPage() |
|
704 |
+ |
{ |
|
705 |
+ |
if ( getPageCount() >= 0 ) |
|
706 |
+ |
{ |
|
707 |
+ |
gotoPage( getPageCount(), false ); |
|
708 |
+ |
} |
|
709 |
+ |
} |
|
710 |
+ |
|
|
711 |
+ |
/** |
|
712 |
+ |
* Go to the next page. |
|
713 |
+ |
*/ |
|
714 |
+ |
public void gotoNextPage() |
|
715 |
+ |
{ |
|
716 |
+ |
gotoPage( currentPage + 1, false ); |
|
717 |
+ |
} |
|
718 |
+ |
|
|
719 |
+ |
/** |
|
720 |
+ |
* Set the current page. If the page is out of bounds, it will be |
|
721 |
+ |
* automatically set to zero or the last page without throwing any errors. |
|
722 |
+ |
* |
|
723 |
+ |
* @param page the page |
|
724 |
+ |
* @param forced reload the page even if it is already loaded |
|
725 |
+ |
*/ |
|
726 |
+ |
public void gotoPage( int page, boolean forced ) |
|
727 |
+ |
{ |
|
728 |
+ |
int oldPage = currentPage; |
|
729 |
+ |
int numPages = getPageCount(); |
|
730 |
+ |
if ( numPages >= 0 ) |
|
731 |
+ |
{ |
|
732 |
+ |
currentPage = Math.max( 0, Math.min( page, numPages - 1 ) ); |
|
733 |
+ |
} |
|
734 |
+ |
else |
|
735 |
+ |
{ |
|
736 |
+ |
currentPage = page; |
|
737 |
+ |
} |
|
738 |
+ |
|
|
739 |
+ |
if ( currentPage != oldPage || forced ) |
|
740 |
+ |
{ |
|
741 |
+ |
isPageLoading = true; |
|
742 |
+ |
|
|
743 |
+ |
// Deselect rows when switching pages |
|
744 |
+ |
FixedWidthGrid dataTable = getDataTable(); |
|
745 |
+ |
dataTable.deselectAllRows(); |
|
746 |
+ |
if ( !isCrossPageSelectionEnabled ) |
|
747 |
+ |
{ |
|
748 |
+ |
selectedRowValues = new HashSet<RowType>(); |
|
749 |
+ |
} |
|
750 |
+ |
|
|
751 |
+ |
// Fire listeners |
|
752 |
+ |
fireEvent( new PageChangeEvent( oldPage, currentPage ) ); |
|
753 |
+ |
|
|
754 |
+ |
// Clear out existing data if we aren't bulk rendering |
|
755 |
+ |
if ( bulkRenderer == null ) |
|
756 |
+ |
{ |
|
757 |
+ |
int rowCount = getAbsoluteLastRowIndex() - getAbsoluteFirstRowIndex() + 1; |
|
758 |
+ |
if ( rowCount != dataTable.getRowCount() ) |
|
759 |
+ |
{ |
|
760 |
+ |
dataTable.resizeRows( rowCount ); |
|
761 |
+ |
} |
|
762 |
+ |
dataTable.clearAll(); |
|
763 |
+ |
} |
|
764 |
+ |
|
|
765 |
+ |
// Request the new data from the table model |
|
766 |
+ |
int firstRow = getAbsoluteFirstRowIndex(); |
|
767 |
+ |
int lastRow = pageSize == 0 ? tableModel.getRowCount() : pageSize; |
|
768 |
+ |
lastRequest = new Request( firstRow, lastRow, dataTable.getColumnSortList() ); |
|
769 |
+ |
tableModel.requestRows( lastRequest, pagingCallback ); |
|
770 |
+ |
} |
|
771 |
+ |
} |
|
772 |
+ |
|
|
773 |
+ |
/** |
|
774 |
+ |
* Go to the previous page. |
|
775 |
+ |
*/ |
|
776 |
+ |
public void gotoPreviousPage() |
|
777 |
+ |
{ |
|
778 |
+ |
gotoPage( currentPage - 1, false ); |
131 |
779 |
|
} |
132 |
780 |
|
|
133 |
781 |
|
@Override |
134 |
|
- |
public void setVerticalAlignment(VerticalAlignmentConstant align) { |
135 |
|
- |
table.getDataTable().getCellFormatter().setVerticalAlignment( |
136 |
|
- |
getRowIndex(), getCellIndex(), align); |
|
782 |
+ |
public boolean isColumnSortable( int column ) |
|
783 |
+ |
{ |
|
784 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
785 |
+ |
if ( colDef == null ) |
|
786 |
+ |
{ |
|
787 |
+ |
return true; |
|
788 |
+ |
} |
|
789 |
+ |
if ( getSortPolicy() == SortPolicy.DISABLED ) |
|
790 |
+ |
{ |
|
791 |
+ |
return false; |
|
792 |
+ |
} |
|
793 |
+ |
return colDef.getColumnProperty( SortableProperty.TYPE ).isColumnSortable(); |
137 |
794 |
|
} |
138 |
795 |
|
|
139 |
796 |
|
@Override |
140 |
|
- |
public void setWidget(Widget widget) { |
141 |
|
- |
table.getDataTable().setWidget(getRowIndex(), getCellIndex(), widget); |
|
797 |
+ |
public boolean isColumnTruncatable( int column ) |
|
798 |
+ |
{ |
|
799 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
800 |
+ |
if ( colDef == null ) |
|
801 |
+ |
{ |
|
802 |
+ |
return true; |
|
803 |
+ |
} |
|
804 |
+ |
return colDef.getColumnProperty( TruncationProperty.TYPE ).isColumnTruncatable(); |
142 |
805 |
|
} |
143 |
|
- |
} |
144 |
806 |
|
|
145 |
|
- |
/** |
146 |
|
- |
* A custom {@link AbstractRowView} used by the {@link PagingScrollTable}. |
147 |
|
- |
* |
148 |
|
- |
* @param <RowType> the type of the row values |
149 |
|
- |
*/ |
150 |
|
- |
protected static class PagingScrollTableRowView<RowType> extends |
151 |
|
- |
AbstractRowView<RowType> { |
152 |
|
- |
private PagingScrollTable<RowType> table; |
153 |
|
- |
|
154 |
|
- |
public PagingScrollTableRowView(PagingScrollTable<RowType> table) { |
155 |
|
- |
super(new PagingScrollTableCellView<RowType>(table)); |
156 |
|
- |
this.table = table; |
|
807 |
+ |
/** |
|
808 |
+ |
* @return true if cross page selection is enabled |
|
809 |
+ |
*/ |
|
810 |
+ |
public boolean isCrossPageSelectionEnabled() |
|
811 |
+ |
{ |
|
812 |
+ |
return isCrossPageSelectionEnabled; |
157 |
813 |
|
} |
158 |
814 |
|
|
159 |
815 |
|
@Override |
160 |
|
- |
public void setStyleAttribute(String attr, String value) { |
161 |
|
- |
table.getDataTable().getFixedWidthGridRowFormatter().getRawElement( |
162 |
|
- |
getRowIndex()).getStyle().setProperty(attr, value); |
|
816 |
+ |
public boolean isFooterColumnTruncatable( int column ) |
|
817 |
+ |
{ |
|
818 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
819 |
+ |
if ( colDef == null ) |
|
820 |
+ |
{ |
|
821 |
+ |
return true; |
|
822 |
+ |
} |
|
823 |
+ |
return colDef.getColumnProperty( TruncationProperty.TYPE ).isFooterTruncatable(); |
163 |
824 |
|
} |
164 |
825 |
|
|
165 |
|
- |
@Override |
166 |
|
- |
public void setStyleName(String stylename) { |
167 |
|
- |
// If the row is selected, add the selected style name back |
168 |
|
- |
if (table.getDataTable().isRowSelected(getRowIndex())) { |
169 |
|
- |
stylename += " selected"; |
170 |
|
- |
} |
171 |
|
- |
table.getDataTable().getRowFormatter().setStyleName(getRowIndex(), |
172 |
|
- |
stylename); |
173 |
|
- |
} |
174 |
|
- |
} |
175 |
|
- |
|
176 |
|
- |
/** |
177 |
|
- |
* Information about a column header. |
178 |
|
- |
*/ |
179 |
|
- |
private static class ColumnHeaderInfo { |
180 |
|
- |
private int rowSpan = 1; |
181 |
|
- |
private Object header; |
182 |
|
- |
|
183 |
|
- |
public ColumnHeaderInfo(Object header) { |
184 |
|
- |
this.header = (header == null) ? "" : header; |
185 |
|
- |
} |
186 |
|
- |
|
187 |
|
- |
public ColumnHeaderInfo(Object header, int rowSpan) { |
188 |
|
- |
this.header = (header == null) ? " " : header; |
189 |
|
- |
this.rowSpan = rowSpan; |
|
826 |
+ |
/** |
|
827 |
+ |
* @return true if the footer table is automatically generated |
|
828 |
+ |
*/ |
|
829 |
+ |
public boolean isFooterGenerated() |
|
830 |
+ |
{ |
|
831 |
+ |
return isFooterGenerated; |
190 |
832 |
|
} |
191 |
833 |
|
|
192 |
834 |
|
@Override |
193 |
|
- |
public boolean equals(Object o) { |
194 |
|
- |
if (o == null) { |
195 |
|
- |
return false; |
196 |
|
- |
} |
197 |
|
- |
if (o instanceof ColumnHeaderInfo) { |
198 |
|
- |
ColumnHeaderInfo info = (ColumnHeaderInfo) o; |
199 |
|
- |
return (rowSpan == info.rowSpan) && header.equals(info.header); |
200 |
|
- |
} |
201 |
|
- |
return false; |
202 |
|
- |
} |
203 |
|
- |
|
204 |
|
- |
public Object getHeader() { |
205 |
|
- |
return header; |
206 |
|
- |
} |
207 |
|
- |
|
208 |
|
- |
public int getRowSpan() { |
209 |
|
- |
return rowSpan; |
210 |
|
- |
} |
211 |
|
- |
|
212 |
|
- |
public void incrementRowSpan() { |
213 |
|
- |
rowSpan++; |
214 |
|
- |
} |
215 |
|
- |
} |
216 |
|
- |
|
217 |
|
- |
/** |
218 |
|
- |
* An iterator over the visible rows in an iterator over many rows. |
219 |
|
- |
*/ |
220 |
|
- |
private class VisibleRowsIterator implements Iterator<RowType> { |
221 |
|
- |
/** |
222 |
|
- |
* The iterator of row data. |
223 |
|
- |
*/ |
224 |
|
- |
private Iterator<RowType> rows; |
225 |
|
- |
|
226 |
|
- |
/** |
227 |
|
- |
* The current row of the rows iterator. |
228 |
|
- |
*/ |
229 |
|
- |
private int curRow; |
230 |
|
- |
|
231 |
|
- |
/** |
232 |
|
- |
* The last visible row in the grid. |
233 |
|
- |
*/ |
234 |
|
- |
private int lastVisibleRow; |
235 |
|
- |
|
236 |
|
- |
/** |
237 |
|
- |
* Constructor. |
238 |
|
- |
* |
239 |
|
- |
* @param rows the iterator over row data |
240 |
|
- |
* @param firstRow the first absolute row of the rows iterator |
241 |
|
- |
* @param firstVisibleRow the first visible row in this grid |
242 |
|
- |
* @param lastVisibleRow the last visible row in this grid |
243 |
|
- |
*/ |
244 |
|
- |
public VisibleRowsIterator(Iterator<RowType> rows, int firstRow, |
245 |
|
- |
int firstVisibleRow, int lastVisibleRow) { |
246 |
|
- |
this.curRow = firstRow; |
247 |
|
- |
this.lastVisibleRow = lastVisibleRow; |
248 |
|
- |
|
249 |
|
- |
// Iterate up to the first row |
250 |
|
- |
while (curRow < firstVisibleRow && rows.hasNext()) { |
251 |
|
- |
rows.next(); |
252 |
|
- |
curRow++; |
253 |
|
- |
} |
254 |
|
- |
this.rows = rows; |
255 |
|
- |
} |
256 |
|
- |
|
257 |
|
- |
public boolean hasNext() { |
258 |
|
- |
return (curRow <= lastVisibleRow && rows.hasNext()); |
259 |
|
- |
} |
260 |
|
- |
|
261 |
|
- |
public RowType next() { |
262 |
|
- |
// Check that the next row exists |
263 |
|
- |
if (!hasNext()) { |
264 |
|
- |
throw new NoSuchElementException(); |
265 |
|
- |
} |
266 |
|
- |
return rows.next(); |
267 |
|
- |
} |
268 |
|
- |
|
269 |
|
- |
public void remove() { |
270 |
|
- |
throw new UnsupportedOperationException("Remove not supported"); |
271 |
|
- |
} |
272 |
|
- |
} |
273 |
|
- |
|
274 |
|
- |
/** |
275 |
|
- |
* The bulk render used to render the contents of this table. |
276 |
|
- |
*/ |
277 |
|
- |
private FixedWidthGridBulkRenderer<RowType> bulkRenderer = null; |
278 |
|
- |
|
279 |
|
- |
/** |
280 |
|
- |
* The wrapper around the empty table widget. |
281 |
|
- |
*/ |
282 |
|
- |
private SimplePanel emptyTableWidgetWrapper = new SimplePanel(); |
283 |
|
- |
|
284 |
|
- |
/** |
285 |
|
- |
* The definition of the columns in the table. |
286 |
|
- |
*/ |
287 |
|
- |
private TableDefinition<RowType> tableDefinition = null; |
288 |
|
- |
|
289 |
|
- |
/** |
290 |
|
- |
* The current visible page. |
291 |
|
- |
*/ |
292 |
|
- |
private int currentPage = -1; |
293 |
|
- |
|
294 |
|
- |
/** |
295 |
|
- |
* The last request that was sent to the {@link TableModel}. |
296 |
|
- |
*/ |
297 |
|
- |
private Request lastRequest = null; |
298 |
|
- |
|
299 |
|
- |
/** |
300 |
|
- |
* A boolean indicating that cross page selection is enabled. |
301 |
|
- |
*/ |
302 |
|
- |
private boolean isCrossPageSelectionEnabled; |
303 |
|
- |
|
304 |
|
- |
/** |
305 |
|
- |
* The set of selected row values. |
306 |
|
- |
*/ |
307 |
|
- |
private Set<RowType> selectedRowValues = new HashSet<RowType>(); |
308 |
|
- |
|
309 |
|
- |
/** |
310 |
|
- |
* A boolean indicating that the footer should be generated automatically. |
311 |
|
- |
*/ |
312 |
|
- |
private boolean isFooterGenerated; |
313 |
|
- |
|
314 |
|
- |
/** |
315 |
|
- |
* A boolean indicating that the header should be generated automatically. |
316 |
|
- |
*/ |
317 |
|
- |
private boolean isHeaderGenerated; |
318 |
|
- |
|
319 |
|
- |
/** |
320 |
|
- |
* A boolean indicating that the page is currently being loaded. |
321 |
|
- |
*/ |
322 |
|
- |
private boolean isPageLoading; |
323 |
|
- |
|
324 |
|
- |
/** |
325 |
|
- |
* The old page count, used to detect when the number of pages changes. |
326 |
|
- |
*/ |
327 |
|
- |
private int oldPageCount; |
328 |
|
- |
|
329 |
|
- |
/** |
330 |
|
- |
* The number of rows per page. If the number of rows per page is equal to the |
331 |
|
- |
* number of rows, paging is disabled because only one page exists. |
332 |
|
- |
*/ |
333 |
|
- |
private int pageSize = 0; |
334 |
|
- |
|
335 |
|
- |
/** |
336 |
|
- |
* The callback that handles page requests. |
337 |
|
- |
*/ |
338 |
|
- |
private Callback<RowType> pagingCallback = new Callback<RowType>() { |
339 |
|
- |
public void onFailure(Throwable caught) { |
340 |
|
- |
isPageLoading = false; |
341 |
|
- |
fireEvent(new PagingFailureEvent(caught)); |
342 |
|
- |
} |
343 |
|
- |
|
344 |
|
- |
public void onRowsReady(Request request, Response<RowType> response) { |
345 |
|
- |
if (lastRequest == request) { |
346 |
|
- |
setData(request.getStartRow(), response.getRowValues()); |
347 |
|
- |
lastRequest = null; |
348 |
|
- |
} |
349 |
|
- |
} |
350 |
|
- |
}; |
351 |
|
- |
|
352 |
|
- |
/** |
353 |
|
- |
* The values associated with each row. This is an optional list of data that |
354 |
|
- |
* ties the visible content in each row to an underlying object. |
355 |
|
- |
*/ |
356 |
|
- |
private List<RowType> rowValues = new ArrayList<RowType>(); |
357 |
|
- |
|
358 |
|
- |
/** |
359 |
|
- |
* The view of this table. |
360 |
|
- |
*/ |
361 |
|
- |
private AbstractRowView<RowType> rowView = new PagingScrollTableRowView<RowType>( |
362 |
|
- |
this); |
363 |
|
- |
|
364 |
|
- |
/** |
365 |
|
- |
* The {@link CheckBox} used to select all rows. |
366 |
|
- |
*/ |
367 |
|
- |
private Widget selectAllWidget; |
368 |
|
- |
|
369 |
|
- |
/** |
370 |
|
- |
* The underlying table model. |
371 |
|
- |
*/ |
372 |
|
- |
private TableModel<RowType> tableModel; |
373 |
|
- |
|
374 |
|
- |
/** |
375 |
|
- |
* The {@link RendererCallback} used when table rendering completes. |
376 |
|
- |
*/ |
377 |
|
- |
private RendererCallback tableRendererCallback = new RendererCallback() { |
378 |
|
- |
public void onRendered() { |
379 |
|
- |
onDataTableRendered(); |
380 |
|
- |
} |
381 |
|
- |
}; |
382 |
|
- |
|
383 |
|
- |
/** |
384 |
|
- |
* The columns that are currently visible. |
385 |
|
- |
*/ |
386 |
|
- |
private List<ColumnDefinition<RowType, ?>> visibleColumns = new ArrayList<ColumnDefinition<RowType, ?>>(); |
387 |
|
- |
|
388 |
|
- |
/** |
389 |
|
- |
* The boolean indicating that the header tables are obsolete. |
390 |
|
- |
*/ |
391 |
|
- |
private boolean headersObsolete; |
392 |
|
- |
|
393 |
|
- |
/** |
394 |
|
- |
* Construct a new {@link PagingScrollTable}. |
395 |
|
- |
* |
396 |
|
- |
* @param tableModel the underlying table model |
397 |
|
- |
* @param tableDefinition the column definitions |
398 |
|
- |
*/ |
399 |
|
- |
public PagingScrollTable(TableModel<RowType> tableModel, |
400 |
|
- |
TableDefinition<RowType> tableDefinition) { |
401 |
|
- |
this(tableModel, new FixedWidthGrid(), new FixedWidthFlexTable(), |
402 |
|
- |
tableDefinition); |
403 |
|
- |
isHeaderGenerated = true; |
404 |
|
- |
isFooterGenerated = true; |
405 |
|
- |
} |
406 |
|
- |
|
407 |
|
- |
/** |
408 |
|
- |
* Construct a new {@link PagingScrollTable}. |
409 |
|
- |
* |
410 |
|
- |
* @param tableModel the underlying table model |
411 |
|
- |
* @param dataTable the table used to display data |
412 |
|
- |
* @param headerTable the header table |
413 |
|
- |
* @param tableDefinition the column definitions |
414 |
|
- |
*/ |
415 |
|
- |
public PagingScrollTable(TableModel<RowType> tableModel, |
416 |
|
- |
FixedWidthGrid dataTable, FixedWidthFlexTable headerTable, |
417 |
|
- |
TableDefinition<RowType> tableDefinition) { |
418 |
|
- |
this(tableModel, dataTable, headerTable, tableDefinition, |
419 |
|
- |
GWT.<ScrollTableImages> create(ScrollTableImages.class)); |
420 |
|
- |
} |
421 |
|
- |
|
422 |
|
- |
/** |
423 |
|
- |
* Construct a new {@link PagingScrollTable} with custom images. |
424 |
|
- |
* |
425 |
|
- |
* @param tableModel the underlying table model |
426 |
|
- |
* @param dataTable the table used to display data |
427 |
|
- |
* @param headerTable the header table |
428 |
|
- |
* @param tableDefinition the column definitions |
429 |
|
- |
* @param images the images to use in the table |
430 |
|
- |
*/ |
431 |
|
- |
public PagingScrollTable(TableModel<RowType> tableModel, |
432 |
|
- |
FixedWidthGrid dataTable, FixedWidthFlexTable headerTable, |
433 |
|
- |
TableDefinition<RowType> tableDefinition, ScrollTableImages images) { |
434 |
|
- |
super(dataTable, headerTable, images); |
435 |
|
- |
this.tableModel = tableModel; |
436 |
|
- |
setTableDefinition(tableDefinition); |
437 |
|
- |
refreshVisibleColumnDefinitions(); |
438 |
|
- |
oldPageCount = getPageCount(); |
439 |
|
- |
|
440 |
|
- |
// Setup the empty table widget wrapper |
441 |
|
- |
emptyTableWidgetWrapper.getElement().getStyle().setProperty("width", "100%"); |
442 |
|
- |
emptyTableWidgetWrapper.getElement().getStyle().setProperty("overflow", |
443 |
|
- |
"hidden"); |
444 |
|
- |
emptyTableWidgetWrapper.getElement().getStyle().setPropertyPx("border", 0); |
445 |
|
- |
emptyTableWidgetWrapper.getElement().getStyle().setPropertyPx("margin", 0); |
446 |
|
- |
emptyTableWidgetWrapper.getElement().getStyle().setPropertyPx("padding", 0); |
447 |
|
- |
insert(emptyTableWidgetWrapper, getAbsoluteElement(), 2, true); |
448 |
|
- |
setEmptyTableWidgetVisible(false); |
449 |
|
- |
|
450 |
|
- |
// Listen to table model events |
451 |
|
- |
tableModel.addRowCountChangeHandler(new RowCountChangeHandler() { |
452 |
|
- |
public void onRowCountChange(RowCountChangeEvent event) { |
|
835 |
+ |
public boolean isHeaderColumnTruncatable( int column ) |
|
836 |
+ |
{ |
|
837 |
+ |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition( column ); |
|
838 |
+ |
if ( colDef == null ) |
|
839 |
+ |
{ |
|
840 |
+ |
return true; |
|
841 |
+ |
} |
|
842 |
+ |
return colDef.getColumnProperty( TruncationProperty.TYPE ).isHeaderTruncatable(); |
|
843 |
+ |
} |
|
844 |
+ |
|
|
845 |
+ |
/** |
|
846 |
+ |
* @return true if the header table is automatically generated |
|
847 |
+ |
*/ |
|
848 |
+ |
public boolean isHeaderGenerated() |
|
849 |
+ |
{ |
|
850 |
+ |
return isHeaderGenerated; |
|
851 |
+ |
} |
|
852 |
+ |
|
|
853 |
+ |
/** |
|
854 |
+ |
* @return true if a page load is pending |
|
855 |
+ |
*/ |
|
856 |
+ |
public boolean isPageLoading() |
|
857 |
+ |
{ |
|
858 |
+ |
return isPageLoading; |
|
859 |
+ |
} |
|
860 |
+ |
|
|
861 |
+ |
/** |
|
862 |
+ |
* Reload the current page. |
|
863 |
+ |
*/ |
|
864 |
+ |
public void reloadPage() |
|
865 |
+ |
{ |
|
866 |
+ |
if ( currentPage >= 0 ) |
|
867 |
+ |
{ |
|
868 |
+ |
gotoPage( currentPage, true ); |
|
869 |
+ |
} |
|
870 |
+ |
else |
|
871 |
+ |
{ |
|
872 |
+ |
gotoPage( 0, true ); |
|
873 |
+ |
} |
|
874 |
+ |
} |
|
875 |
+ |
|
|
876 |
+ |
/** |
|
877 |
+ |
* Set the {@link FixedWidthGridBulkRenderer} used to render the data table. |
|
878 |
+ |
* |
|
879 |
+ |
* @param bulkRenderer the table renderer |
|
880 |
+ |
*/ |
|
881 |
+ |
public void setBulkRenderer( FixedWidthGridBulkRenderer<RowType> bulkRenderer ) |
|
882 |
+ |
{ |
|
883 |
+ |
this.bulkRenderer = bulkRenderer; |
|
884 |
+ |
} |
|
885 |
+ |
|
|
886 |
+ |
/** |
|
887 |
+ |
* Enable or disable cross page selection. When enabled, row value selections |
|
888 |
+ |
* are maintained across page loads. Selections are remembered by type (not by |
|
889 |
+ |
* row index), so row values can move around and still maintain their |
|
890 |
+ |
* selection. |
|
891 |
+ |
* |
|
892 |
+ |
* @param enabled true to enable, false to disable |
|
893 |
+ |
*/ |
|
894 |
+ |
public void setCrossPageSelectionEnabled( boolean enabled ) |
|
895 |
+ |
{ |
|
896 |
+ |
if ( isCrossPageSelectionEnabled != enabled ) |
|
897 |
+ |
{ |
|
898 |
+ |
this.isCrossPageSelectionEnabled = enabled; |
|
899 |
+ |
|
|
900 |
+ |
// Reselected only the rows on this page |
|
901 |
+ |
if ( !enabled ) |
|
902 |
+ |
{ |
|
903 |
+ |
selectedRowValues = new HashSet<RowType>(); |
|
904 |
+ |
Set<Integer> selectedRows = getDataTable().getSelectedRows(); |
|
905 |
+ |
for ( Integer selectedRow : selectedRows ) |
|
906 |
+ |
{ |
|
907 |
+ |
selectedRowValues.add( getRowValue( selectedRow ) ); |
|
908 |
+ |
} |
|
909 |
+ |
} |
|
910 |
+ |
} |
|
911 |
+ |
} |
|
912 |
+ |
|
|
913 |
+ |
/** |
|
914 |
+ |
* Set the {@link Widget} that will be displayed in place of the data table |
|
915 |
+ |
* when the data table has no data to display. |
|
916 |
+ |
* |
|
917 |
+ |
* @param emptyTableWidget the widget to display when the data table is empty |
|
918 |
+ |
*/ |
|
919 |
+ |
public void setEmptyTableWidget( Widget emptyTableWidget ) |
|
920 |
+ |
{ |
|
921 |
+ |
emptyTableWidgetWrapper.setWidget( emptyTableWidget ); |
|
922 |
+ |
} |
|
923 |
+ |
|
|
924 |
+ |
/** |
|
925 |
+ |
* Set whether or not the footer table should be automatically generated. |
|
926 |
+ |
* |
|
927 |
+ |
* @param isGenerated true to enable, false to disable |
|
928 |
+ |
*/ |
|
929 |
+ |
public void setFooterGenerated( boolean isGenerated ) |
|
930 |
+ |
{ |
|
931 |
+ |
this.isFooterGenerated = isGenerated; |
|
932 |
+ |
if ( isGenerated ) |
|
933 |
+ |
{ |
|
934 |
+ |
refreshFooterTable(); |
|
935 |
+ |
} |
|
936 |
+ |
} |
|
937 |
+ |
|
|
938 |
+ |
/** |
|
939 |
+ |
* Set whether or not the header table should be automatically generated. |
|
940 |
+ |
* |
|
941 |
+ |
* @param isGenerated true to enable, false to disable |
|
942 |
+ |
*/ |
|
943 |
+ |
public void setHeaderGenerated( boolean isGenerated ) |
|
944 |
+ |
{ |
|
945 |
+ |
this.isHeaderGenerated = isGenerated; |
|
946 |
+ |
if ( isGenerated ) |
|
947 |
+ |
{ |
|
948 |
+ |
refreshHeaderTable(); |
|
949 |
+ |
} |
|
950 |
+ |
} |
|
951 |
+ |
|
|
952 |
+ |
/** |
|
953 |
+ |
* Set the number of rows per page. |
|
954 |
+ |
* <p/> |
|
955 |
+ |
* By default, the page size is zero, which indicates that all rows should be |
|
956 |
+ |
* shown on the page. |
|
957 |
+ |
* |
|
958 |
+ |
* @param pageSize the number of rows per page |
|
959 |
+ |
*/ |
|
960 |
+ |
public void setPageSize( int pageSize ) |
|
961 |
+ |
{ |
|
962 |
+ |
pageSize = Math.max( 0, pageSize ); |
|
963 |
+ |
this.pageSize = pageSize; |
|
964 |
+ |
|
453 |
965 |
|
int pageCount = getPageCount(); |
454 |
|
- |
if (pageCount != oldPageCount) { |
455 |
|
- |
fireEvent(new PageCountChangeEvent(oldPageCount, pageCount)); |
456 |
|
- |
oldPageCount = pageCount; |
457 |
|
- |
} |
458 |
|
- |
} |
459 |
|
- |
}); |
460 |
|
- |
if (tableModel instanceof HasRowInsertionHandlers) { |
461 |
|
- |
((HasRowInsertionHandlers) tableModel).addRowInsertionHandler(new RowInsertionHandler() { |
462 |
|
- |
public void onRowInsertion(RowInsertionEvent event) { |
463 |
|
- |
insertAbsoluteRow(event.getRowIndex()); |
464 |
|
- |
} |
465 |
|
- |
}); |
466 |
|
- |
} |
467 |
|
- |
if (tableModel instanceof HasRowRemovalHandlers) { |
468 |
|
- |
((HasRowRemovalHandlers) tableModel).addRowRemovalHandler(new RowRemovalHandler() { |
469 |
|
- |
public void onRowRemoval(RowRemovalEvent event) { |
470 |
|
- |
removeAbsoluteRow(event.getRowIndex()); |
471 |
|
- |
} |
472 |
|
- |
}); |
473 |
|
- |
} |
474 |
|
- |
if (tableModel instanceof HasRowValueChangeHandlers) { |
475 |
|
- |
((HasRowValueChangeHandlers<RowType>) tableModel).addRowValueChangeHandler(new RowValueChangeHandler<RowType>() { |
476 |
|
- |
public void onRowValueChange(RowValueChangeEvent<RowType> event) { |
477 |
|
- |
int rowIndex = event.getRowIndex(); |
478 |
|
- |
if (rowIndex < getAbsoluteFirstRowIndex() |
479 |
|
- |
|| rowIndex > getAbsoluteLastRowIndex()) { |
|
966 |
+ |
if ( pageCount != oldPageCount ) |
|
967 |
+ |
{ |
|
968 |
+ |
fireEvent( new PageCountChangeEvent( oldPageCount, pageCount ) ); |
|
969 |
+ |
oldPageCount = pageCount; |
|
970 |
+ |
} |
|
971 |
+ |
|
|
972 |
+ |
// Reset the page |
|
973 |
+ |
if ( currentPage >= 0 ) |
|
974 |
+ |
{ |
|
975 |
+ |
gotoPage( currentPage, true ); |
|
976 |
+ |
} |
|
977 |
+ |
} |
|
978 |
+ |
|
|
979 |
+ |
/** |
|
980 |
+ |
* Associate a row in the table with a value. |
|
981 |
+ |
* |
|
982 |
+ |
* @param row the row index |
|
983 |
+ |
* @param value the value to associate |
|
984 |
+ |
*/ |
|
985 |
+ |
public void setRowValue( int row, RowType value ) |
|
986 |
+ |
{ |
|
987 |
+ |
// Make sure the list can fit the row |
|
988 |
+ |
for ( int i = rowValues.size(); i <= row; i++ ) |
|
989 |
+ |
{ |
|
990 |
+ |
rowValues.add( null ); |
|
991 |
+ |
} |
|
992 |
+ |
|
|
993 |
+ |
// Set the row value |
|
994 |
+ |
rowValues.set( row, value ); |
|
995 |
+ |
|
|
996 |
+ |
// Render the new row value |
|
997 |
+ |
refreshRow( row ); |
|
998 |
+ |
} |
|
999 |
+ |
|
|
1000 |
+ |
/** |
|
1001 |
+ |
* Set the {@link TableDefinition} used to define the columns. |
|
1002 |
+ |
* |
|
1003 |
+ |
* @param tableDefinition the new table definition. |
|
1004 |
+ |
*/ |
|
1005 |
+ |
public void setTableDefinition( TableDefinition<RowType> tableDefinition ) |
|
1006 |
+ |
{ |
|
1007 |
+ |
assert tableDefinition != null : "tableDefinition cannot be null"; |
|
1008 |
+ |
this.tableDefinition = tableDefinition; |
|
1009 |
+ |
} |
|
1010 |
+ |
|
|
1011 |
+ |
/** |
|
1012 |
+ |
* Invoke the cell editor on a cell, if one is set. If a cell editor is not |
|
1013 |
+ |
* specified, this method has no effect. |
|
1014 |
+ |
*/ |
|
1015 |
+ |
protected void editCell( int row, int column ) |
|
1016 |
+ |
{ |
|
1017 |
+ |
// Get the cell editor |
|
1018 |
+ |
final ColumnDefinition colDef = getColumnDefinition( column ); |
|
1019 |
+ |
if ( colDef == null ) |
|
1020 |
+ |
{ |
480 |
1021 |
|
return; |
481 |
|
- |
} |
482 |
|
- |
setRowValue(rowIndex - getAbsoluteFirstRowIndex(), |
483 |
|
- |
event.getRowValue()); |
484 |
|
- |
} |
485 |
|
- |
}); |
486 |
|
- |
} |
487 |
|
- |
|
488 |
|
- |
// Listen for cell click events |
489 |
|
- |
dataTable.addTableListener(new TableListener() { |
490 |
|
- |
public void onCellClicked(SourcesTableEvents sender, int row, int cell) { |
491 |
|
- |
editCell(row, cell); |
492 |
|
- |
} |
493 |
|
- |
}); |
494 |
|
- |
|
495 |
|
- |
// Override the column sorter |
496 |
|
- |
if (dataTable.getColumnSorter() == null) { |
497 |
|
- |
ColumnSorter sorter = new ColumnSorter() { |
498 |
|
- |
@Override |
499 |
|
- |
public void onSortColumn(SortableGrid grid, ColumnSortList sortList, |
500 |
|
- |
ColumnSorterCallback callback) { |
501 |
|
- |
reloadPage(); |
502 |
|
- |
callback.onSortingComplete(); |
503 |
|
- |
} |
504 |
|
- |
}; |
505 |
|
- |
dataTable.setColumnSorter(sorter); |
506 |
|
- |
} |
507 |
|
- |
|
508 |
|
- |
// Listen for selection events |
509 |
|
- |
dataTable.addRowSelectionHandler(new RowSelectionHandler() { |
510 |
|
- |
public void onRowSelection(RowSelectionEvent event) { |
511 |
|
- |
if (isPageLoading) { |
512 |
|
- |
return; |
513 |
|
- |
} |
514 |
|
- |
Set<Row> deselected = event.getDeselectedRows(); |
515 |
|
- |
for (Row row : deselected) { |
516 |
|
- |
selectedRowValues.remove(getRowValue(row.getRowIndex())); |
517 |
|
- |
} |
518 |
|
- |
Set<Row> selected = event.getSelectedRows(); |
519 |
|
- |
for (Row row : selected) { |
520 |
|
- |
selectedRowValues.add(getRowValue(row.getRowIndex())); |
521 |
|
- |
} |
522 |
|
- |
} |
523 |
|
- |
}); |
524 |
|
- |
} |
525 |
|
- |
|
526 |
|
- |
public HandlerRegistration addPageChangeHandler(PageChangeHandler handler) { |
527 |
|
- |
return addHandler(PageChangeEvent.TYPE, handler); |
528 |
|
- |
} |
529 |
|
- |
|
530 |
|
- |
public HandlerRegistration addPageCountChangeHandler( |
531 |
|
- |
PageCountChangeHandler handler) { |
532 |
|
- |
return addHandler(PageCountChangeEvent.TYPE, handler); |
533 |
|
- |
} |
534 |
|
- |
|
535 |
|
- |
public HandlerRegistration addPageLoadHandler(PageLoadHandler handler) { |
536 |
|
- |
return addHandler(PageLoadEvent.TYPE, handler); |
537 |
|
- |
} |
538 |
|
- |
|
539 |
|
- |
public HandlerRegistration addPagingFailureHandler( |
540 |
|
- |
PagingFailureHandler handler) { |
541 |
|
- |
return addHandler(PagingFailureEvent.TYPE, handler); |
542 |
|
- |
} |
543 |
|
- |
|
544 |
|
- |
/** |
545 |
|
- |
* @return the absolute index of the first visible row |
546 |
|
- |
*/ |
547 |
|
- |
public int getAbsoluteFirstRowIndex() { |
548 |
|
- |
return currentPage * pageSize; |
549 |
|
- |
} |
550 |
|
- |
|
551 |
|
- |
/** |
552 |
|
- |
* @return the absolute index of the last visible row |
553 |
|
- |
*/ |
554 |
|
- |
public int getAbsoluteLastRowIndex() { |
555 |
|
- |
if (tableModel.getRowCount() < 0) { |
556 |
|
- |
// Unknown row count, so just return based on current page |
557 |
|
- |
return (currentPage + 1) * pageSize - 1; |
558 |
|
- |
} else if (pageSize == 0) { |
559 |
|
- |
// Only one page, so return row count |
560 |
|
- |
return tableModel.getRowCount() - 1; |
561 |
|
- |
} |
562 |
|
- |
return Math.min(tableModel.getRowCount(), (currentPage + 1) * pageSize) - 1; |
563 |
|
- |
} |
564 |
|
- |
|
565 |
|
- |
/** |
566 |
|
- |
* @return the current page |
567 |
|
- |
*/ |
568 |
|
- |
public int getCurrentPage() { |
569 |
|
- |
return currentPage; |
570 |
|
- |
} |
571 |
|
- |
|
572 |
|
- |
/** |
573 |
|
- |
* @return the widget displayed when the data table is empty |
574 |
|
- |
*/ |
575 |
|
- |
public Widget getEmptyTableWidget() { |
576 |
|
- |
return emptyTableWidgetWrapper.getWidget(); |
577 |
|
- |
} |
578 |
|
- |
|
579 |
|
- |
@Override |
580 |
|
- |
public int getMaximumColumnWidth(int column) { |
581 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
582 |
|
- |
if (colDef == null) { |
583 |
|
- |
return -1; |
584 |
|
- |
} |
585 |
|
- |
return colDef.getColumnProperty(MaximumWidthProperty.TYPE).getMaximumColumnWidth(); |
586 |
|
- |
} |
587 |
|
- |
|
588 |
|
- |
@Override |
589 |
|
- |
public int getMinimumColumnWidth(int column) { |
590 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
591 |
|
- |
if (colDef == null) { |
592 |
|
- |
return FixedWidthGrid.MIN_COLUMN_WIDTH; |
593 |
|
- |
} |
594 |
|
- |
int minWidth = colDef.getColumnProperty(MinimumWidthProperty.TYPE).getMinimumColumnWidth(); |
595 |
|
- |
return Math.max(FixedWidthGrid.MIN_COLUMN_WIDTH, minWidth); |
596 |
|
- |
} |
597 |
|
- |
|
598 |
|
- |
/** |
599 |
|
- |
* @return the number of pages, or -1 if not known |
600 |
|
- |
*/ |
601 |
|
- |
public int getPageCount() { |
602 |
|
- |
if (pageSize < 1) { |
603 |
|
- |
return 1; |
604 |
|
- |
} else { |
605 |
|
- |
int numDataRows = tableModel.getRowCount(); |
606 |
|
- |
if (numDataRows < 0) { |
607 |
|
- |
return -1; |
608 |
|
- |
} |
609 |
|
- |
return (int) Math.ceil(numDataRows / (pageSize + 0.0)); |
610 |
|
- |
} |
611 |
|
- |
} |
612 |
|
- |
|
613 |
|
- |
/** |
614 |
|
- |
* @return the number of rows per page |
615 |
|
- |
*/ |
616 |
|
- |
public int getPageSize() { |
617 |
|
- |
return pageSize; |
618 |
|
- |
} |
619 |
|
- |
|
620 |
|
- |
@Override |
621 |
|
- |
public int getPreferredColumnWidth(int column) { |
622 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
623 |
|
- |
if (colDef == null) { |
624 |
|
- |
return FixedWidthGrid.DEFAULT_COLUMN_WIDTH; |
625 |
|
- |
} |
626 |
|
- |
return colDef.getColumnProperty(PreferredWidthProperty.TYPE).getPreferredColumnWidth(); |
627 |
|
- |
} |
628 |
|
- |
|
629 |
|
- |
/** |
630 |
|
- |
* Get the value associated with a row. |
631 |
|
- |
* |
632 |
|
- |
* @param row the row index |
633 |
|
- |
* @return the value associated with the row |
634 |
|
- |
*/ |
635 |
|
- |
public RowType getRowValue(int row) { |
636 |
|
- |
if (rowValues.size() <= row) { |
637 |
|
- |
return null; |
638 |
|
- |
} |
639 |
|
- |
return rowValues.get(row); |
640 |
|
- |
} |
641 |
|
- |
|
642 |
|
- |
/** |
643 |
|
- |
* Get the selected row values. If cross page selection is enabled, this will |
644 |
|
- |
* include row values selected on all pages. |
645 |
|
- |
* |
646 |
|
- |
* @return the selected row values |
647 |
|
- |
* @see #setCrossPageSelectionEnabled(boolean) |
648 |
|
- |
*/ |
649 |
|
- |
public Set<RowType> getSelectedRowValues() { |
650 |
|
- |
return selectedRowValues; |
651 |
|
- |
} |
652 |
|
- |
|
653 |
|
- |
public TableDefinition<RowType> getTableDefinition() { |
654 |
|
- |
return tableDefinition; |
655 |
|
- |
} |
656 |
|
- |
|
657 |
|
- |
/** |
658 |
|
- |
* @return the table model |
659 |
|
- |
*/ |
660 |
|
- |
public TableModel<RowType> getTableModel() { |
661 |
|
- |
return tableModel; |
662 |
|
- |
} |
663 |
|
- |
|
664 |
|
- |
/** |
665 |
|
- |
* Go to the first page. |
666 |
|
- |
*/ |
667 |
|
- |
public void gotoFirstPage() { |
668 |
|
- |
gotoPage(0, false); |
669 |
|
- |
} |
670 |
|
- |
|
671 |
|
- |
/** |
672 |
|
- |
* Go to the last page. If the number of pages is not known, this method is |
673 |
|
- |
* ignored. |
674 |
|
- |
*/ |
675 |
|
- |
public void gotoLastPage() { |
676 |
|
- |
if (getPageCount() >= 0) { |
677 |
|
- |
gotoPage(getPageCount(), false); |
678 |
|
- |
} |
679 |
|
- |
} |
680 |
|
- |
|
681 |
|
- |
/** |
682 |
|
- |
* Go to the next page. |
683 |
|
- |
*/ |
684 |
|
- |
public void gotoNextPage() { |
685 |
|
- |
gotoPage(currentPage + 1, false); |
686 |
|
- |
} |
687 |
|
- |
|
688 |
|
- |
/** |
689 |
|
- |
* Set the current page. If the page is out of bounds, it will be |
690 |
|
- |
* automatically set to zero or the last page without throwing any errors. |
691 |
|
- |
* |
692 |
|
- |
* @param page the page |
693 |
|
- |
* @param forced reload the page even if it is already loaded |
694 |
|
- |
*/ |
695 |
|
- |
public void gotoPage(int page, boolean forced) { |
696 |
|
- |
int oldPage = currentPage; |
697 |
|
- |
int numPages = getPageCount(); |
698 |
|
- |
if (numPages >= 0) { |
699 |
|
- |
currentPage = Math.max(0, Math.min(page, numPages - 1)); |
700 |
|
- |
} else { |
701 |
|
- |
currentPage = page; |
702 |
|
- |
} |
703 |
|
- |
|
704 |
|
- |
if (currentPage != oldPage || forced) { |
705 |
|
- |
isPageLoading = true; |
706 |
|
- |
|
707 |
|
- |
// Deselect rows when switching pages |
708 |
|
- |
FixedWidthGrid dataTable = getDataTable(); |
709 |
|
- |
dataTable.deselectAllRows(); |
710 |
|
- |
if (!isCrossPageSelectionEnabled) { |
711 |
|
- |
selectedRowValues = new HashSet<RowType>(); |
712 |
|
- |
} |
713 |
|
- |
|
714 |
|
- |
// Fire listeners |
715 |
|
- |
fireEvent(new PageChangeEvent(oldPage, currentPage)); |
716 |
|
- |
|
717 |
|
- |
// Clear out existing data if we aren't bulk rendering |
718 |
|
- |
if (bulkRenderer == null) { |
719 |
|
- |
int rowCount = getAbsoluteLastRowIndex() - getAbsoluteFirstRowIndex() |
720 |
|
- |
+ 1; |
721 |
|
- |
if (rowCount != dataTable.getRowCount()) { |
722 |
|
- |
dataTable.resizeRows(rowCount); |
723 |
|
- |
} |
724 |
|
- |
dataTable.clearAll(); |
725 |
|
- |
} |
726 |
|
- |
|
727 |
|
- |
// Request the new data from the table model |
728 |
|
- |
int firstRow = getAbsoluteFirstRowIndex(); |
729 |
|
- |
int lastRow = pageSize == 0 ? tableModel.getRowCount() : pageSize; |
730 |
|
- |
lastRequest = new Request(firstRow, lastRow, |
731 |
|
- |
dataTable.getColumnSortList()); |
732 |
|
- |
tableModel.requestRows(lastRequest, pagingCallback); |
733 |
|
- |
} |
734 |
|
- |
} |
735 |
|
- |
|
736 |
|
- |
/** |
737 |
|
- |
* Go to the previous page. |
738 |
|
- |
*/ |
739 |
|
- |
public void gotoPreviousPage() { |
740 |
|
- |
gotoPage(currentPage - 1, false); |
741 |
|
- |
} |
742 |
|
- |
|
743 |
|
- |
@Override |
744 |
|
- |
public boolean isColumnSortable(int column) { |
745 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
746 |
|
- |
if (colDef == null) { |
747 |
|
- |
return true; |
748 |
|
- |
} |
749 |
|
- |
if (getSortPolicy() == SortPolicy.DISABLED) { |
750 |
|
- |
return false; |
751 |
|
- |
} |
752 |
|
- |
return colDef.getColumnProperty(SortableProperty.TYPE).isColumnSortable(); |
753 |
|
- |
} |
754 |
|
- |
|
755 |
|
- |
@Override |
756 |
|
- |
public boolean isColumnTruncatable(int column) { |
757 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
758 |
|
- |
if (colDef == null) { |
759 |
|
- |
return true; |
760 |
|
- |
} |
761 |
|
- |
return colDef.getColumnProperty(TruncationProperty.TYPE).isColumnTruncatable(); |
762 |
|
- |
} |
763 |
|
- |
|
764 |
|
- |
/** |
765 |
|
- |
* @return true if cross page selection is enabled |
766 |
|
- |
*/ |
767 |
|
- |
public boolean isCrossPageSelectionEnabled() { |
768 |
|
- |
return isCrossPageSelectionEnabled; |
769 |
|
- |
} |
770 |
|
- |
|
771 |
|
- |
@Override |
772 |
|
- |
public boolean isFooterColumnTruncatable(int column) { |
773 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
774 |
|
- |
if (colDef == null) { |
775 |
|
- |
return true; |
776 |
|
- |
} |
777 |
|
- |
return colDef.getColumnProperty(TruncationProperty.TYPE).isFooterTruncatable(); |
778 |
|
- |
} |
779 |
|
- |
|
780 |
|
- |
/** |
781 |
|
- |
* @return true if the footer table is automatically generated |
782 |
|
- |
*/ |
783 |
|
- |
public boolean isFooterGenerated() { |
784 |
|
- |
return isFooterGenerated; |
785 |
|
- |
} |
786 |
|
- |
|
787 |
|
- |
@Override |
788 |
|
- |
public boolean isHeaderColumnTruncatable(int column) { |
789 |
|
- |
ColumnDefinition<RowType, ?> colDef = getColumnDefinition(column); |
790 |
|
- |
if (colDef == null) { |
791 |
|
- |
return true; |
792 |
|
- |
} |
793 |
|
- |
return colDef.getColumnProperty(TruncationProperty.TYPE).isHeaderTruncatable(); |
794 |
|
- |
} |
795 |
|
- |
|
796 |
|
- |
/** |
797 |
|
- |
* @return true if the header table is automatically generated |
798 |
|
- |
*/ |
799 |
|
- |
public boolean isHeaderGenerated() { |
800 |
|
- |
return isHeaderGenerated; |
801 |
|
- |
} |
802 |
|
- |
|
803 |
|
- |
/** |
804 |
|
- |
* @return true if a page load is pending |
805 |
|
- |
*/ |
806 |
|
- |
public boolean isPageLoading() { |
807 |
|
- |
return isPageLoading; |
808 |
|
- |
} |
809 |
|
- |
|
810 |
|
- |
/** |
811 |
|
- |
* Reload the current page. |
812 |
|
- |
*/ |
813 |
|
- |
public void reloadPage() { |
814 |
|
- |
if (currentPage >= 0) { |
815 |
|
- |
gotoPage(currentPage, true); |
816 |
|
- |
} else { |
817 |
|
- |
gotoPage(0, true); |
818 |
|
- |
} |
819 |
|
- |
} |
820 |
|
- |
|
821 |
|
- |
/** |
822 |
|
- |
* Set the {@link FixedWidthGridBulkRenderer} used to render the data table. |
823 |
|
- |
* |
824 |
|
- |
* @param bulkRenderer the table renderer |
825 |
|
- |
*/ |
826 |
|
- |
public void setBulkRenderer(FixedWidthGridBulkRenderer<RowType> bulkRenderer) { |
827 |
|
- |
this.bulkRenderer = bulkRenderer; |
828 |
|
- |
} |
829 |
|
- |
|
830 |
|
- |
/** |
831 |
|
- |
* Enable or disable cross page selection. When enabled, row value selections |
832 |
|
- |
* are maintained across page loads. Selections are remembered by type (not by |
833 |
|
- |
* row index), so row values can move around and still maintain their |
834 |
|
- |
* selection. |
835 |
|
- |
* |
836 |
|
- |
* @param enabled true to enable, false to disable |
837 |
|
- |
*/ |
838 |
|
- |
public void setCrossPageSelectionEnabled(boolean enabled) { |
839 |
|
- |
if (isCrossPageSelectionEnabled != enabled) { |
840 |
|
- |
this.isCrossPageSelectionEnabled = enabled; |
841 |
|
- |
|
842 |
|
- |
// Reselected only the rows on this page |
843 |
|
- |
if (!enabled) { |
844 |
|
- |
selectedRowValues = new HashSet<RowType>(); |
845 |
|
- |
Set<Integer> selectedRows = getDataTable().getSelectedRows(); |
846 |
|
- |
for (Integer selectedRow : selectedRows) { |
847 |
|
- |
selectedRowValues.add(getRowValue(selectedRow)); |
848 |
|
- |
} |
849 |
|
- |
} |
850 |
|
- |
} |
851 |
|
- |
} |
852 |
|
- |
|
853 |
|
- |
/** |
854 |
|
- |
* Set the {@link Widget} that will be displayed in place of the data table |
855 |
|
- |
* when the data table has no data to display. |
856 |
|
- |
* |
857 |
|
- |
* @param emptyTableWidget the widget to display when the data table is empty |
858 |
|
- |
*/ |
859 |
|
- |
public void setEmptyTableWidget(Widget emptyTableWidget) { |
860 |
|
- |
emptyTableWidgetWrapper.setWidget(emptyTableWidget); |
861 |
|
- |
} |
862 |
|
- |
|
863 |
|
- |
/** |
864 |
|
- |
* Set whether or not the footer table should be automatically generated. |
865 |
|
- |
* |
866 |
|
- |
* @param isGenerated true to enable, false to disable |
867 |
|
- |
*/ |
868 |
|
- |
public void setFooterGenerated(boolean isGenerated) { |
869 |
|
- |
this.isFooterGenerated = isGenerated; |
870 |
|
- |
if (isGenerated) { |
871 |
|
- |
refreshFooterTable(); |
872 |
|
- |
} |
873 |
|
- |
} |
874 |
|
- |
|
875 |
|
- |
/** |
876 |
|
- |
* Set whether or not the header table should be automatically generated. |
877 |
|
- |
* |
878 |
|
- |
* @param isGenerated true to enable, false to disable |
879 |
|
- |
*/ |
880 |
|
- |
public void setHeaderGenerated(boolean isGenerated) { |
881 |
|
- |
this.isHeaderGenerated = isGenerated; |
882 |
|
- |
if (isGenerated) { |
883 |
|
- |
refreshHeaderTable(); |
884 |
|
- |
} |
885 |
|
- |
} |
886 |
|
- |
|
887 |
|
- |
/** |
888 |
|
- |
* Set the number of rows per page. |
889 |
|
- |
* |
890 |
|
- |
* By default, the page size is zero, which indicates that all rows should be |
891 |
|
- |
* shown on the page. |
892 |
|
- |
* |
893 |
|
- |
* @param pageSize the number of rows per page |
894 |
|
- |
*/ |
895 |
|
- |
public void setPageSize(int pageSize) { |
896 |
|
- |
pageSize = Math.max(0, pageSize); |
897 |
|
- |
this.pageSize = pageSize; |
898 |
|
- |
|
899 |
|
- |
int pageCount = getPageCount(); |
900 |
|
- |
if (pageCount != oldPageCount) { |
901 |
|
- |
fireEvent(new PageCountChangeEvent(oldPageCount, pageCount)); |
902 |
|
- |
oldPageCount = pageCount; |
903 |
|
- |
} |
904 |
|
- |
|
905 |
|
- |
// Reset the page |
906 |
|
- |
if (currentPage >= 0) { |
907 |
|
- |
gotoPage(currentPage, true); |
908 |
|
- |
} |
909 |
|
- |
} |
910 |
|
- |
|
911 |
|
- |
/** |
912 |
|
- |
* Associate a row in the table with a value. |
913 |
|
- |
* |
914 |
|
- |
* @param row the row index |
915 |
|
- |
* @param value the value to associate |
916 |
|
- |
*/ |
917 |
|
- |
public void setRowValue(int row, RowType value) { |
918 |
|
- |
// Make sure the list can fit the row |
919 |
|
- |
for (int i = rowValues.size(); i <= row; i++) { |
920 |
|
- |
rowValues.add(null); |
921 |
|
- |
} |
922 |
|
- |
|
923 |
|
- |
// Set the row value |
924 |
|
- |
rowValues.set(row, value); |
925 |
|
- |
|
926 |
|
- |
// Render the new row value |
927 |
|
- |
refreshRow(row); |
928 |
|
- |
} |
929 |
|
- |
|
930 |
|
- |
/** |
931 |
|
- |
* Set the {@link TableDefinition} used to define the columns. |
932 |
|
- |
* |
933 |
|
- |
* @param tableDefinition the new table definition. |
934 |
|
- |
*/ |
935 |
|
- |
public void setTableDefinition(TableDefinition<RowType> tableDefinition) { |
936 |
|
- |
assert tableDefinition != null : "tableDefinition cannot be null"; |
937 |
|
- |
this.tableDefinition = tableDefinition; |
938 |
|
- |
} |
939 |
|
- |
|
940 |
|
- |
/** |
941 |
|
- |
* Invoke the cell editor on a cell, if one is set. If a cell editor is not |
942 |
|
- |
* specified, this method has no effect. |
943 |
|
- |
*/ |
944 |
|
- |
protected void editCell(int row, int column) { |
945 |
|
- |
// Get the cell editor |
946 |
|
- |
final ColumnDefinition colDef = getColumnDefinition(column); |
947 |
|
- |
if (colDef == null) { |
948 |
|
- |
return; |
949 |
|
- |
} |
950 |
|
- |
CellEditor cellEditor = colDef.getCellEditor(); |
951 |
|
- |
if (cellEditor == null) { |
952 |
|
- |
return; |
953 |
|
- |
} |
954 |
|
- |
|
955 |
|
- |
// Forward the request to the cell editor |
956 |
|
- |
final RowType rowValue = getRowValue(row); |
957 |
|
- |
CellEditInfo editInfo = new CellEditInfo(getDataTable(), row, column); |
958 |
|
- |
cellEditor.editCell(editInfo, colDef.getCellValue(rowValue), |
959 |
|
- |
new CellEditor.Callback() { |
960 |
|
- |
public void onCancel(CellEditInfo cellEditInfo) { |
961 |
|
- |
} |
962 |
|
- |
|
963 |
|
- |
public void onComplete(CellEditInfo cellEditInfo, Object cellValue) { |
964 |
|
- |
colDef.setCellValue(rowValue, cellValue); |
965 |
|
- |
if (tableModel instanceof MutableTableModel) { |
966 |
|
- |
int row = getAbsoluteFirstRowIndex() + cellEditInfo.getRowIndex(); |
967 |
|
- |
((MutableTableModel<RowType>) tableModel).setRowValue(row, |
968 |
|
- |
rowValue); |
969 |
|
- |
} else { |
970 |
|
- |
refreshRow(cellEditInfo.getRowIndex()); |
971 |
|
- |
} |
972 |
|
- |
} |
973 |
|
- |
}); |
974 |
|
- |
} |
975 |
|
- |
|
976 |
|
- |
/** |
977 |
|
- |
* Get the {@link ColumnDefinition} currently associated with a column. |
978 |
|
- |
* |
979 |
|
- |
* @param colIndex the index of the column |
980 |
|
- |
* @return the {@link ColumnDefinition} associated with the column, or null |
981 |
|
- |
*/ |
982 |
|
- |
protected ColumnDefinition<RowType, ?> getColumnDefinition(int colIndex) { |
983 |
|
- |
if (colIndex < visibleColumns.size()) { |
984 |
|
- |
return visibleColumns.get(colIndex); |
985 |
|
- |
} |
986 |
|
- |
return null; |
987 |
|
- |
} |
988 |
|
- |
|
989 |
|
- |
/** |
990 |
|
- |
* @return the index of the first visible row |
991 |
|
- |
* @deprecated use {@link #getAbsoluteFirstRowIndex()} instead |
992 |
|
- |
*/ |
993 |
|
- |
@Deprecated |
994 |
|
- |
protected int getFirstRow() { |
995 |
|
- |
return getAbsoluteFirstRowIndex(); |
996 |
|
- |
} |
997 |
|
- |
|
998 |
|
- |
/** |
999 |
|
- |
* @return the index of the last visible row |
1000 |
|
- |
* @deprecated use {@link #getAbsoluteLastRowIndex()} instead |
1001 |
|
- |
*/ |
1002 |
|
- |
@Deprecated |
1003 |
|
- |
protected int getLastRow() { |
1004 |
|
- |
return getAbsoluteLastRowIndex(); |
1005 |
|
- |
} |
1006 |
|
- |
|
1007 |
|
- |
/** |
1008 |
|
- |
* Get the list of row values associated with the table. |
1009 |
|
- |
* |
1010 |
|
- |
* @return the list of row value |
1011 |
|
- |
*/ |
1012 |
|
- |
protected List<RowType> getRowValues() { |
1013 |
|
- |
return rowValues; |
1014 |
|
- |
} |
1015 |
|
- |
|
1016 |
|
- |
/** |
1017 |
|
- |
* @return the header widget used to select all rows |
1018 |
|
- |
*/ |
1019 |
|
- |
protected Widget getSelectAllWidget() { |
1020 |
|
- |
if (selectAllWidget == null) { |
1021 |
|
- |
final CheckBox box = new CheckBox(); |
1022 |
|
- |
selectAllWidget = box; |
1023 |
|
- |
box.addClickHandler(new ClickHandler() { |
1024 |
|
- |
public void onClick(ClickEvent event) { |
1025 |
|
- |
if (box.getValue()) { |
1026 |
|
- |
getDataTable().selectAllRows(); |
1027 |
|
- |
} else { |
1028 |
|
- |
getDataTable().deselectAllRows(); |
1029 |
|
- |
} |
1030 |
|
- |
} |
1031 |
|
- |
}); |
1032 |
|
- |
} |
1033 |
|
- |
return selectAllWidget; |
1034 |
|
- |
} |
1035 |
|
- |
|
1036 |
|
- |
/** |
1037 |
|
- |
* @return the list of current visible column definitions |
1038 |
|
- |
*/ |
1039 |
|
- |
protected List<ColumnDefinition<RowType, ?>> getVisibleColumnDefinitions() { |
1040 |
|
- |
return visibleColumns; |
1041 |
|
- |
} |
1042 |
|
- |
|
1043 |
|
- |
/** |
1044 |
|
- |
* Insert a row into the table relative to the total number of rows. |
1045 |
|
- |
* |
1046 |
|
- |
* @param beforeRow the row index |
1047 |
|
- |
*/ |
1048 |
|
- |
protected void insertAbsoluteRow(int beforeRow) { |
1049 |
|
- |
// Physically insert the row |
1050 |
|
- |
int lastRow = getAbsoluteLastRowIndex() + 1; |
1051 |
|
- |
if (beforeRow <= lastRow) { |
1052 |
|
- |
int firstRow = getAbsoluteFirstRowIndex(); |
1053 |
|
- |
if (beforeRow >= firstRow) { |
1054 |
|
- |
// Insert row in the middle of the page |
1055 |
|
- |
getDataTable().insertRow(beforeRow - firstRow); |
1056 |
|
- |
} else { |
1057 |
|
- |
// Insert zero row because row is before this page |
1058 |
|
- |
getDataTable().insertRow(0); |
1059 |
|
- |
} |
1060 |
|
- |
if (getDataTable().getRowCount() > pageSize) { |
1061 |
|
- |
getDataTable().removeRow(pageSize); |
1062 |
|
- |
} |
1063 |
|
- |
} |
1064 |
|
- |
} |
1065 |
|
- |
|
1066 |
|
- |
/** |
1067 |
|
- |
* Called when the data table has finished rendering. |
1068 |
|
- |
*/ |
1069 |
|
- |
protected void onDataTableRendered() { |
1070 |
|
- |
// Refresh the headers if needed |
1071 |
|
- |
if (headersObsolete) { |
1072 |
|
- |
refreshHeaderTable(); |
1073 |
|
- |
refreshFooterTable(); |
1074 |
|
- |
headersObsolete = false; |
1075 |
|
- |
} |
1076 |
|
- |
|
1077 |
|
- |
// Select rows |
1078 |
|
- |
FixedWidthGrid dataTable = getDataTable(); |
1079 |
|
- |
int rowCount = dataTable.getRowCount(); |
1080 |
|
- |
for (int i = 0; i < rowCount; i++) { |
1081 |
|
- |
if (selectedRowValues.contains(getRowValue(i))) { |
1082 |
|
- |
dataTable.selectRow(i, false); |
1083 |
|
- |
} |
1084 |
|
- |
} |
1085 |
|
- |
|
1086 |
|
- |
// Update the UI of the table |
1087 |
|
- |
dataTable.clearIdealWidths(); |
1088 |
|
- |
redraw(); |
1089 |
|
- |
isPageLoading = false; |
1090 |
|
- |
fireEvent(new PageLoadEvent(currentPage)); |
1091 |
|
- |
} |
1092 |
|
- |
|
1093 |
|
- |
/** |
1094 |
|
- |
* Update the footer table based on the new {@link ColumnDefinition}. |
1095 |
|
- |
*/ |
1096 |
|
- |
protected void refreshFooterTable() { |
1097 |
|
- |
if (!isFooterGenerated) { |
1098 |
|
- |
return; |
1099 |
|
- |
} |
1100 |
|
- |
|
1101 |
|
- |
// Generate the list of lists of ColumnHeaderInfo. |
1102 |
|
- |
List<List<ColumnHeaderInfo>> allInfos = new ArrayList<List<ColumnHeaderInfo>>(); |
1103 |
|
- |
int columnCount = visibleColumns.size(); |
1104 |
|
- |
int footerCounts[] = new int[columnCount]; |
1105 |
|
- |
int maxFooterCount = 0; |
1106 |
|
- |
for (int col = 0; col < columnCount; col++) { |
1107 |
|
- |
// Get the header property. |
1108 |
|
- |
ColumnDefinition<RowType, ?> colDef = visibleColumns.get(col); |
1109 |
|
- |
FooterProperty prop = colDef.getColumnProperty(FooterProperty.TYPE); |
1110 |
|
- |
int footerCount = prop.getFooterCount(); |
1111 |
|
- |
footerCounts[col] = footerCount; |
1112 |
|
- |
maxFooterCount = Math.max(maxFooterCount, footerCount); |
1113 |
|
- |
|
1114 |
|
- |
// Add each ColumnHeaderInfo |
1115 |
|
- |
List<ColumnHeaderInfo> infos = new ArrayList<ColumnHeaderInfo>(); |
1116 |
|
- |
ColumnHeaderInfo prev = null; |
1117 |
|
- |
for (int row = 0; row < footerCount; row++) { |
1118 |
|
- |
Object footer = prop.getFooter(row, col); |
1119 |
|
- |
if (prev != null && prev.header.equals(footer)) { |
1120 |
|
- |
prev.incrementRowSpan(); |
1121 |
|
- |
} else { |
1122 |
|
- |
prev = new ColumnHeaderInfo(footer); |
1123 |
|
- |
infos.add(prev); |
1124 |
|
- |
} |
1125 |
|
- |
} |
1126 |
|
- |
allInfos.add(infos); |
1127 |
|
- |
} |
1128 |
|
- |
|
1129 |
|
- |
// Return early if there is no footer |
1130 |
|
- |
if (maxFooterCount == 0) { |
1131 |
|
- |
return; |
1132 |
|
- |
} |
1133 |
|
- |
|
1134 |
|
- |
// Fill in missing rows |
1135 |
|
- |
for (int col = 0; col < columnCount; col++) { |
1136 |
|
- |
int footerCount = footerCounts[col]; |
1137 |
|
- |
if (footerCount < maxFooterCount) { |
1138 |
|
- |
allInfos.get(col).add( |
1139 |
|
- |
new ColumnHeaderInfo(null, maxFooterCount - footerCount)); |
1140 |
|
- |
} |
1141 |
|
- |
} |
1142 |
|
- |
|
1143 |
|
- |
// Ensure that we have a footer table |
1144 |
|
- |
if (getFooterTable() == null) { |
1145 |
|
- |
setFooterTable(new FixedWidthFlexTable()); |
1146 |
|
- |
} |
1147 |
|
- |
|
1148 |
|
- |
// Refresh the table |
1149 |
|
- |
refreshHeaderTable(getFooterTable(), allInfos, false); |
1150 |
|
- |
} |
1151 |
|
- |
|
1152 |
|
- |
/** |
1153 |
|
- |
* Update the header table based on the new {@link ColumnDefinition}. |
1154 |
|
- |
*/ |
1155 |
|
- |
protected void refreshHeaderTable() { |
1156 |
|
- |
if (!isHeaderGenerated) { |
1157 |
|
- |
return; |
1158 |
|
- |
} |
1159 |
|
- |
|
1160 |
|
- |
// Generate the list of lists of ColumnHeaderInfo. |
1161 |
|
- |
List<List<ColumnHeaderInfo>> allInfos = new ArrayList<List<ColumnHeaderInfo>>(); |
1162 |
|
- |
int columnCount = visibleColumns.size(); |
1163 |
|
- |
int headerCounts[] = new int[columnCount]; |
1164 |
|
- |
int maxHeaderCount = 0; |
1165 |
|
- |
for (int col = 0; col < columnCount; col++) { |
1166 |
|
- |
// Get the header property. |
1167 |
|
- |
ColumnDefinition<RowType, ?> colDef = visibleColumns.get(col); |
1168 |
|
- |
HeaderProperty prop = colDef.getColumnProperty(HeaderProperty.TYPE); |
1169 |
|
- |
int headerCount = prop.getHeaderCount(); |
1170 |
|
- |
headerCounts[col] = headerCount; |
1171 |
|
- |
maxHeaderCount = Math.max(maxHeaderCount, headerCount); |
1172 |
|
- |
|
1173 |
|
- |
// Add each ColumnHeaderInfo |
1174 |
|
- |
List<ColumnHeaderInfo> infos = new ArrayList<ColumnHeaderInfo>(); |
1175 |
|
- |
ColumnHeaderInfo prev = null; |
1176 |
|
- |
for (int row = 0; row < headerCount; row++) { |
1177 |
|
- |
Object header = prop.getHeader(row, col); |
1178 |
|
- |
if (prev != null && prev.header.equals(header)) { |
1179 |
|
- |
prev.incrementRowSpan(); |
1180 |
|
- |
} else { |
1181 |
|
- |
prev = new ColumnHeaderInfo(header); |
1182 |
|
- |
infos.add(0, prev); |
1183 |
|
- |
} |
1184 |
|
- |
} |
1185 |
|
- |
allInfos.add(infos); |
1186 |
|
- |
} |
1187 |
|
- |
|
1188 |
|
- |
// Return early if there is no header |
1189 |
|
- |
if (maxHeaderCount == 0) { |
1190 |
|
- |
return; |
1191 |
|
- |
} |
1192 |
|
- |
|
1193 |
|
- |
// Fill in missing rows |
1194 |
|
- |
for (int col = 0; col < columnCount; col++) { |
1195 |
|
- |
int headerCount = headerCounts[col]; |
1196 |
|
- |
if (headerCount < maxHeaderCount) { |
1197 |
|
- |
allInfos.get(col).add(0, |
1198 |
|
- |
new ColumnHeaderInfo(null, maxHeaderCount - headerCount)); |
1199 |
|
- |
} |
1200 |
|
- |
} |
1201 |
|
- |
|
1202 |
|
- |
// Refresh the table |
1203 |
|
- |
refreshHeaderTable(getHeaderTable(), allInfos, true); |
1204 |
|
- |
} |
1205 |
|
- |
|
1206 |
|
- |
/** |
1207 |
|
- |
* Refresh the list of the currently visible column definitions based on the |
1208 |
|
- |
* {@link TableDefinition}. |
1209 |
|
- |
*/ |
1210 |
|
- |
protected void refreshVisibleColumnDefinitions() { |
1211 |
|
- |
List<ColumnDefinition<RowType, ?>> colDefs = new ArrayList<ColumnDefinition<RowType, ?>>( |
1212 |
|
- |
tableDefinition.getVisibleColumnDefinitions()); |
1213 |
|
- |
if (!colDefs.equals(visibleColumns)) { |
1214 |
|
- |
visibleColumns = colDefs; |
1215 |
|
- |
headersObsolete = true; |
1216 |
|
- |
} else { |
1217 |
|
- |
// Check if any of the headers are dynamic |
1218 |
|
- |
for (ColumnDefinition<RowType, ?> colDef : colDefs) { |
1219 |
|
- |
if (colDef.getColumnProperty(HeaderProperty.TYPE).isDynamic() |
1220 |
|
- |
|| colDef.getColumnProperty(FooterProperty.TYPE).isDynamic()) { |
1221 |
|
- |
headersObsolete = true; |
1222 |
|
- |
return; |
1223 |
|
- |
} |
1224 |
|
- |
} |
1225 |
|
- |
} |
1226 |
|
- |
} |
1227 |
|
- |
|
1228 |
|
- |
/** |
1229 |
|
- |
* Remove a row from the table relative to the total number of rows. |
1230 |
|
- |
* |
1231 |
|
- |
* @param row the row index |
1232 |
|
- |
*/ |
1233 |
|
- |
protected void removeAbsoluteRow(int row) { |
1234 |
|
- |
// Physically remove the row if it is in the middle of the data table |
1235 |
|
- |
int firstRow = getAbsoluteFirstRowIndex(); |
1236 |
|
- |
int lastRow = getAbsoluteLastRowIndex(); |
1237 |
|
- |
if (row <= lastRow && row >= firstRow) { |
1238 |
|
- |
FixedWidthGrid dataTable = getDataTable(); |
1239 |
|
- |
int relativeRow = row - firstRow; |
1240 |
|
- |
if (relativeRow < dataTable.getRowCount()) { |
1241 |
|
- |
dataTable.removeRow(relativeRow); |
1242 |
|
- |
} |
1243 |
|
- |
} |
1244 |
|
- |
} |
1245 |
|
- |
|
1246 |
|
- |
/** |
1247 |
|
- |
* Set a block of data. This method is used when responding to data requests. |
1248 |
|
- |
* |
1249 |
|
- |
* This method takes an iterator of iterators, where each iterator represents |
1250 |
|
- |
* one row of data starting with the first row. |
1251 |
|
- |
* |
1252 |
|
- |
* @param firstRow the row index that the rows iterator starts with |
1253 |
|
- |
* @param rows the values associated with each row |
1254 |
|
- |
*/ |
1255 |
|
- |
protected void setData(int firstRow, Iterator<RowType> rows) { |
1256 |
|
- |
getDataTable().deselectAllRows(); |
1257 |
|
- |
rowValues = new ArrayList<RowType>(); |
1258 |
|
- |
if (rows != null && rows.hasNext()) { |
1259 |
|
- |
setEmptyTableWidgetVisible(false); |
1260 |
|
- |
|
1261 |
|
- |
// Get an iterator over the visible rows |
1262 |
|
- |
int firstVisibleRow = getAbsoluteFirstRowIndex(); |
1263 |
|
- |
int lastVisibleRow = getAbsoluteLastRowIndex(); |
1264 |
|
- |
Iterator<RowType> visibleIter = new VisibleRowsIterator(rows, firstRow, |
1265 |
|
- |
firstVisibleRow, lastVisibleRow); |
1266 |
|
- |
|
1267 |
|
- |
// Set the row values |
1268 |
|
- |
while (visibleIter.hasNext()) { |
1269 |
|
- |
rowValues.add(visibleIter.next()); |
1270 |
|
- |
} |
1271 |
|
- |
|
1272 |
|
- |
// Copy the visible column definitions |
1273 |
|
- |
refreshVisibleColumnDefinitions(); |
1274 |
|
- |
|
1275 |
|
- |
// Render using the bulk renderer |
1276 |
|
- |
if (bulkRenderer != null) { |
1277 |
|
- |
bulkRenderer.renderRows(rowValues.iterator(), tableRendererCallback); |
1278 |
|
- |
return; |
1279 |
|
- |
} |
1280 |
|
- |
|
1281 |
|
- |
// Get rid of unneeded rows and columns |
1282 |
|
- |
int rowCount = rowValues.size(); |
1283 |
|
- |
int colCount = visibleColumns.size(); |
1284 |
|
- |
getDataTable().resize(rowCount, colCount); |
1285 |
|
- |
|
1286 |
|
- |
// Render the rows |
1287 |
|
- |
tableDefinition.renderRows(0, rowValues.iterator(), rowView); |
1288 |
|
- |
} else { |
1289 |
|
- |
setEmptyTableWidgetVisible(true); |
1290 |
|
- |
} |
1291 |
|
- |
|
1292 |
|
- |
// Fire page loaded event |
1293 |
|
- |
onDataTableRendered(); |
1294 |
|
- |
} |
1295 |
|
- |
|
1296 |
|
- |
/** |
1297 |
|
- |
* Set whether or not the empty table widget is visible. |
1298 |
|
- |
* |
1299 |
|
- |
* @param visible true to show the empty table widget |
1300 |
|
- |
*/ |
1301 |
|
- |
protected void setEmptyTableWidgetVisible(boolean visible) { |
1302 |
|
- |
emptyTableWidgetWrapper.setVisible(visible); |
1303 |
|
- |
if (visible) { |
1304 |
|
- |
getDataWrapper().getStyle().setProperty("display", "none"); |
1305 |
|
- |
} else { |
1306 |
|
- |
getDataWrapper().getStyle().setProperty("display", ""); |
1307 |
|
- |
} |
1308 |
|
- |
} |
1309 |
|
- |
|
1310 |
|
- |
/** |
1311 |
|
- |
* Update the header or footer tables based on the new |
1312 |
|
- |
* {@link ColumnDefinition}. |
1313 |
|
- |
* |
1314 |
|
- |
* @param table the header or footer table |
1315 |
|
- |
* @param allInfos the header info |
1316 |
|
- |
* @param isHeader false if refreshing the footer table |
1317 |
|
- |
*/ |
1318 |
|
- |
private void refreshHeaderTable(FixedWidthFlexTable table, |
1319 |
|
- |
List<List<ColumnHeaderInfo>> allInfos, boolean isHeader) { |
1320 |
|
- |
// Return if we have no column definitions. |
1321 |
|
- |
if (visibleColumns == null) { |
1322 |
|
- |
return; |
1323 |
|
- |
} |
1324 |
|
- |
|
1325 |
|
- |
// Reset the header table. |
1326 |
|
- |
int rowCount = table.getRowCount(); |
1327 |
|
- |
for (int i = 0; i < rowCount; i++) { |
1328 |
|
- |
table.removeRow(0); |
1329 |
|
- |
} |
1330 |
|
- |
|
1331 |
|
- |
// Generate the header table |
1332 |
|
- |
int columnCount = allInfos.size(); |
1333 |
|
- |
FlexCellFormatter formatter = table.getFlexCellFormatter(); |
1334 |
|
- |
List<ColumnHeaderInfo> prevInfos = null; |
1335 |
|
- |
for (int col = 0; col < columnCount; col++) { |
1336 |
|
- |
List<ColumnHeaderInfo> infos = allInfos.get(col); |
1337 |
|
- |
int row = 0; |
1338 |
|
- |
for (ColumnHeaderInfo info : infos) { |
1339 |
|
- |
// Get the actual row and cell index |
1340 |
|
- |
int rowSpan = info.getRowSpan(); |
1341 |
|
- |
int cell = 0; |
1342 |
|
- |
if (table.getRowCount() > row) { |
1343 |
|
- |
cell = table.getCellCount(row); |
1344 |
|
- |
} |
1345 |
|
- |
|
1346 |
|
- |
// Compare to the cell in the previous column |
1347 |
|
- |
if (prevInfos != null) { |
1348 |
|
- |
boolean headerAdded = false; |
1349 |
|
- |
int prevRow = 0; |
1350 |
|
- |
for (ColumnHeaderInfo prevInfo : prevInfos) { |
1351 |
|
- |
// Increase the colSpan of the previous cell |
1352 |
|
- |
if (prevRow == row && info.equals(prevInfo)) { |
1353 |
|
- |
int colSpan = formatter.getColSpan(row, cell - 1); |
1354 |
|
- |
formatter.setColSpan(row, cell - 1, colSpan + 1); |
1355 |
|
- |
headerAdded = true; |
1356 |
|
- |
break; |
1357 |
|
- |
} |
1358 |
|
- |
prevRow += prevInfo.getRowSpan(); |
1359 |
|
- |
} |
1360 |
|
- |
|
1361 |
|
- |
if (headerAdded) { |
1362 |
|
- |
row += rowSpan; |
1363 |
|
- |
continue; |
1364 |
|
- |
} |
1365 |
|
- |
} |
1366 |
|
- |
|
1367 |
|
- |
// Set the new header |
1368 |
|
- |
Object header = info.getHeader(); |
1369 |
|
- |
if (header instanceof Widget) { |
1370 |
|
- |
table.setWidget(row, cell, (Widget) header); |
1371 |
|
- |
} else { |
1372 |
|
- |
table.setHTML(row, cell, header.toString()); |
1373 |
|
- |
} |
1374 |
|
- |
|
1375 |
|
- |
// Update the rowSpan |
1376 |
|
- |
if (rowSpan > 1) { |
1377 |
|
- |
formatter.setRowSpan(row, cell, rowSpan); |
1378 |
|
- |
} |
1379 |
|
- |
|
1380 |
|
- |
// Increment the row |
1381 |
|
- |
row += rowSpan; |
1382 |
|
- |
} |
1383 |
|
- |
|
1384 |
|
- |
// Increment the previous info |
1385 |
|
- |
prevInfos = infos; |
1386 |
|
- |
} |
1387 |
|
- |
|
1388 |
|
- |
// Insert the checkbox column |
1389 |
|
- |
SelectionPolicy selectionPolicy = getDataTable().getSelectionPolicy(); |
1390 |
|
- |
if (selectionPolicy.hasInputColumn()) { |
1391 |
|
- |
// Get the select all box |
1392 |
|
- |
Widget box = null; |
1393 |
|
- |
if (isHeader |
1394 |
|
- |
&& getDataTable().getSelectionPolicy() == SelectionPolicy.CHECKBOX) { |
1395 |
|
- |
box = getSelectAllWidget(); |
1396 |
|
- |
} |
1397 |
|
- |
|
1398 |
|
- |
// Add the offset column |
1399 |
|
- |
table.insertCell(0, 0); |
1400 |
|
- |
if (box != null) { |
1401 |
|
- |
table.setWidget(0, 0, box); |
1402 |
|
- |
} else { |
1403 |
|
- |
table.setHTML(0, 0, " "); |
1404 |
|
- |
} |
1405 |
|
- |
formatter.setRowSpan(0, 0, table.getRowCount()); |
1406 |
|
- |
formatter.setHorizontalAlignment(0, 0, |
1407 |
|
- |
HasHorizontalAlignment.ALIGN_CENTER); |
1408 |
|
- |
table.setColumnWidth(0, getDataTable().getInputColumnWidth()); |
1409 |
|
- |
} |
1410 |
|
- |
} |
1411 |
|
- |
|
1412 |
|
- |
/** |
1413 |
|
- |
* Refresh a single row in the table. |
1414 |
|
- |
* |
1415 |
|
- |
* @param rowIndex the index of the row |
1416 |
|
- |
*/ |
1417 |
|
- |
private void refreshRow(int rowIndex) { |
1418 |
|
- |
final RowType rowValue = getRowValue(rowIndex); |
1419 |
|
- |
Iterator<RowType> singleIterator = new Iterator<RowType>() { |
1420 |
|
- |
private boolean nextCalled = false; |
1421 |
|
- |
|
1422 |
|
- |
public boolean hasNext() { |
1423 |
|
- |
return !nextCalled; |
1424 |
|
- |
} |
1425 |
|
- |
|
1426 |
|
- |
public RowType next() { |
1427 |
|
- |
if (!hasNext()) { |
1428 |
|
- |
throw new NoSuchElementException(); |
1429 |
|
- |
} |
1430 |
|
- |
nextCalled = true; |
1431 |
|
- |
return rowValue; |
1432 |
|
- |
} |
1433 |
|
- |
|
1434 |
|
- |
public void remove() { |
1435 |
|
- |
throw new UnsupportedOperationException(); |
1436 |
|
- |
} |
1437 |
|
- |
}; |
1438 |
|
- |
tableDefinition.renderRows(rowIndex, singleIterator, rowView); |
1439 |
|
- |
} |
|
1022 |
+ |
} |
|
1023 |
+ |
CellEditor cellEditor = colDef.getCellEditor(); |
|
1024 |
+ |
if ( cellEditor == null ) |
|
1025 |
+ |
{ |
|
1026 |
+ |
return; |
|
1027 |
+ |
} |
|
1028 |
+ |
|
|
1029 |
+ |
// Forward the request to the cell editor |
|
1030 |
+ |
final RowType rowValue = getRowValue( row ); |
|
1031 |
+ |
CellEditInfo editInfo = new CellEditInfo( getDataTable(), row, column ); |
|
1032 |
+ |
cellEditor.editCell( editInfo, colDef.getCellValue( rowValue ), new CellEditor.Callback() |
|
1033 |
+ |
{ |
|
1034 |
+ |
public void onCancel( CellEditInfo cellEditInfo ) |
|
1035 |
+ |
{ |
|
1036 |
+ |
} |
|
1037 |
+ |
|
|
1038 |
+ |
public void onComplete( CellEditInfo cellEditInfo, Object cellValue ) |
|
1039 |
+ |
{ |
|
1040 |
+ |
colDef.setCellValue( rowValue, cellValue ); |
|
1041 |
+ |
if ( tableModel instanceof MutableTableModel ) |
|
1042 |
+ |
{ |
|
1043 |
+ |
int row = getAbsoluteFirstRowIndex() + cellEditInfo.getRowIndex(); |
|
1044 |
+ |
((MutableTableModel<RowType>) tableModel).setRowValue( row, rowValue ); |
|
1045 |
+ |
} |
|
1046 |
+ |
else |
|
1047 |
+ |
{ |
|
1048 |
+ |
refreshRow( cellEditInfo.getRowIndex() ); |
|
1049 |
+ |
} |
|
1050 |
+ |
} |
|
1051 |
+ |
} ); |
|
1052 |
+ |
} |
|
1053 |
+ |
|
|
1054 |
+ |
/** |
|
1055 |
+ |
* Get the {@link ColumnDefinition} currently associated with a column. |
|
1056 |
+ |
* |
|
1057 |
+ |
* @param colIndex the index of the column |
|
1058 |
+ |
* |
|
1059 |
+ |
* @return the {@link ColumnDefinition} associated with the column, or null |
|
1060 |
+ |
*/ |
|
1061 |
+ |
protected ColumnDefinition<RowType, ?> getColumnDefinition( int colIndex ) |
|
1062 |
+ |
{ |
|
1063 |
+ |
if ( colIndex < visibleColumns.size() ) |
|
1064 |
+ |
{ |
|
1065 |
+ |
return visibleColumns.get( colIndex ); |
|
1066 |
+ |
} |
|
1067 |
+ |
return null; |
|
1068 |
+ |
} |
|
1069 |
+ |
|
|
1070 |
+ |
/** |
|
1071 |
+ |
* @return the index of the first visible row |
|
1072 |
+ |
* |
|
1073 |
+ |
* @deprecated use {@link #getAbsoluteFirstRowIndex()} instead |
|
1074 |
+ |
*/ |
|
1075 |
+ |
@Deprecated |
|
1076 |
+ |
protected int getFirstRow() |
|
1077 |
+ |
{ |
|
1078 |
+ |
return getAbsoluteFirstRowIndex(); |
|
1079 |
+ |
} |
|
1080 |
+ |
|
|
1081 |
+ |
/** |
|
1082 |
+ |
* @return the index of the last visible row |
|
1083 |
+ |
* |
|
1084 |
+ |
* @deprecated use {@link #getAbsoluteLastRowIndex()} instead |
|
1085 |
+ |
*/ |
|
1086 |
+ |
@Deprecated |
|
1087 |
+ |
protected int getLastRow() |
|
1088 |
+ |
{ |
|
1089 |
+ |
return getAbsoluteLastRowIndex(); |
|
1090 |
+ |
} |
|
1091 |
+ |
|
|
1092 |
+ |
/** |
|
1093 |
+ |
* Get the list of row values associated with the table. |
|
1094 |
+ |
* |
|
1095 |
+ |
* @return the list of row value |
|
1096 |
+ |
*/ |
|
1097 |
+ |
protected List<RowType> getRowValues() |
|
1098 |
+ |
{ |
|
1099 |
+ |
return rowValues; |
|
1100 |
+ |
} |
|
1101 |
+ |
|
|
1102 |
+ |
/** |
|
1103 |
+ |
* @return the header widget used to select all rows |
|
1104 |
+ |
*/ |
|
1105 |
+ |
protected Widget getSelectAllWidget() |
|
1106 |
+ |
{ |
|
1107 |
+ |
if ( selectAllWidget == null ) |
|
1108 |
+ |
{ |
|
1109 |
+ |
final CheckBox box = new CheckBox(); |
|
1110 |
+ |
selectAllWidget = box; |
|
1111 |
+ |
box.addClickHandler( new ClickHandler() |
|
1112 |
+ |
{ |
|
1113 |
+ |
public void onClick( ClickEvent event ) |
|
1114 |
+ |
{ |
|
1115 |
+ |
if ( box.getValue() ) |
|
1116 |
+ |
{ |
|
1117 |
+ |
getDataTable().selectAllRows(); |
|
1118 |
+ |
} |
|
1119 |
+ |
else |
|
1120 |
+ |
{ |
|
1121 |
+ |
getDataTable().deselectAllRows(); |
|
1122 |
+ |
} |
|
1123 |
+ |
} |
|
1124 |
+ |
} ); |
|
1125 |
+ |
} |
|
1126 |
+ |
return selectAllWidget; |
|
1127 |
+ |
} |
|
1128 |
+ |
|
|
1129 |
+ |
/** |
|
1130 |
+ |
* @return the list of current visible column definitions |
|
1131 |
+ |
*/ |
|
1132 |
+ |
protected List<ColumnDefinition<RowType, ?>> getVisibleColumnDefinitions() |
|
1133 |
+ |
{ |
|
1134 |
+ |
return visibleColumns; |
|
1135 |
+ |
} |
|
1136 |
+ |
|
|
1137 |
+ |
/** |
|
1138 |
+ |
* Insert a row into the table relative to the total number of rows. |
|
1139 |
+ |
* |
|
1140 |
+ |
* @param beforeRow the row index |
|
1141 |
+ |
*/ |
|
1142 |
+ |
protected void insertAbsoluteRow( int beforeRow ) |
|
1143 |
+ |
{ |
|
1144 |
+ |
// Physically insert the row |
|
1145 |
+ |
int lastRow = getAbsoluteLastRowIndex() + 1; |
|
1146 |
+ |
if ( beforeRow <= lastRow ) |
|
1147 |
+ |
{ |
|
1148 |
+ |
int firstRow = getAbsoluteFirstRowIndex(); |
|
1149 |
+ |
if ( beforeRow >= firstRow ) |
|
1150 |
+ |
{ |
|
1151 |
+ |
// Insert row in the middle of the page |
|
1152 |
+ |
getDataTable().insertRow( beforeRow - firstRow ); |
|
1153 |
+ |
} |
|
1154 |
+ |
else |
|
1155 |
+ |
{ |
|
1156 |
+ |
// Insert zero row because row is before this page |
|
1157 |
+ |
getDataTable().insertRow( 0 ); |
|
1158 |
+ |
} |
|
1159 |
+ |
if ( getDataTable().getRowCount() > pageSize ) |
|
1160 |
+ |
{ |
|
1161 |
+ |
getDataTable().removeRow( pageSize ); |
|
1162 |
+ |
} |
|
1163 |
+ |
} |
|
1164 |
+ |
} |
|
1165 |
+ |
|
|
1166 |
+ |
/** |
|
1167 |
+ |
* Called when the data table has finished rendering. |
|
1168 |
+ |
*/ |
|
1169 |
+ |
protected void onDataTableRendered() |
|
1170 |
+ |
{ |
|
1171 |
+ |
// Refresh the headers if needed |
|
1172 |
+ |
if ( headersObsolete ) |
|
1173 |
+ |
{ |
|
1174 |
+ |
refreshHeaderTable(); |
|
1175 |
+ |
refreshFooterTable(); |
|
1176 |
+ |
headersObsolete = false; |
|
1177 |
+ |
} |
|
1178 |
+ |
|
|
1179 |
+ |
// Select rows |
|
1180 |
+ |
FixedWidthGrid dataTable = getDataTable(); |
|
1181 |
+ |
int rowCount = dataTable.getRowCount(); |
|
1182 |
+ |
for ( int i = 0; i < rowCount; i++ ) |
|
1183 |
+ |
{ |
|
1184 |
+ |
if ( selectedRowValues.contains( getRowValue( i ) ) ) |
|
1185 |
+ |
{ |
|
1186 |
+ |
dataTable.selectRow( i, false ); |
|
1187 |
+ |
} |
|
1188 |
+ |
} |
|
1189 |
+ |
|
|
1190 |
+ |
// Update the UI of the table |
|
1191 |
+ |
dataTable.clearIdealWidths(); |
|
1192 |
+ |
redraw(); |
|
1193 |
+ |
isPageLoading = false; |
|
1194 |
+ |
fireEvent( new PageLoadEvent( currentPage ) ); |
|
1195 |
+ |
} |
|
1196 |
+ |
|
|
1197 |
+ |
/** |
|
1198 |
+ |
* Update the footer table based on the new {@link ColumnDefinition}. |
|
1199 |
+ |
*/ |
|
1200 |
+ |
protected void refreshFooterTable() |
|
1201 |
+ |
{ |
|
1202 |
+ |
if ( !isFooterGenerated ) |
|
1203 |
+ |
{ |
|
1204 |
+ |
return; |
|
1205 |
+ |
} |
|
1206 |
+ |
|
|
1207 |
+ |
// Generate the list of lists of ColumnHeaderInfo. |
|
1208 |
+ |
List<List<ColumnHeaderInfo>> allInfos = new ArrayList<List<ColumnHeaderInfo>>(); |
|
1209 |
+ |
int columnCount = visibleColumns.size(); |
|
1210 |
+ |
int footerCounts[] = new int[columnCount]; |
|
1211 |
+ |
int maxFooterCount = 0; |
|
1212 |
+ |
for ( int col = 0; col < columnCount; col++ ) |
|
1213 |
+ |
{ |
|
1214 |
+ |
// Get the header property. |
|
1215 |
+ |
ColumnDefinition<RowType, ?> colDef = visibleColumns.get( col ); |
|
1216 |
+ |
FooterProperty prop = colDef.getColumnProperty( FooterProperty.TYPE ); |
|
1217 |
+ |
int footerCount = prop.getFooterCount(); |
|
1218 |
+ |
footerCounts[col] = footerCount; |
|
1219 |
+ |
maxFooterCount = Math.max( maxFooterCount, footerCount ); |
|
1220 |
+ |
|
|
1221 |
+ |
// Add each ColumnHeaderInfo |
|
1222 |
+ |
List<ColumnHeaderInfo> infos = new ArrayList<ColumnHeaderInfo>(); |
|
1223 |
+ |
ColumnHeaderInfo prev = null; |
|
1224 |
+ |
for ( int row = 0; row < footerCount; row++ ) |
|
1225 |
+ |
{ |
|
1226 |
+ |
Object footer = prop.getFooter( row, col ); |
|
1227 |
+ |
if ( prev != null && prev.header.equals( footer ) ) |
|
1228 |
+ |
{ |
|
1229 |
+ |
prev.incrementRowSpan(); |
|
1230 |
+ |
} |
|
1231 |
+ |
else |
|
1232 |
+ |
{ |
|
1233 |
+ |
prev = new ColumnHeaderInfo( footer ); |
|
1234 |
+ |
infos.add( prev ); |
|
1235 |
+ |
} |
|
1236 |
+ |
} |
|
1237 |
+ |
allInfos.add( infos ); |
|
1238 |
+ |
} |
|
1239 |
+ |
|
|
1240 |
+ |
// Return early if there is no footer |
|
1241 |
+ |
if ( maxFooterCount == 0 ) |
|
1242 |
+ |
{ |
|
1243 |
+ |
return; |
|
1244 |
+ |
} |
|
1245 |
+ |
|
|
1246 |
+ |
// Fill in missing rows |
|
1247 |
+ |
for ( int col = 0; col < columnCount; col++ ) |
|
1248 |
+ |
{ |
|
1249 |
+ |
int footerCount = footerCounts[col]; |
|
1250 |
+ |
if ( footerCount < maxFooterCount ) |
|
1251 |
+ |
{ |
|
1252 |
+ |
allInfos.get( col ).add( new ColumnHeaderInfo( null, maxFooterCount - footerCount ) ); |
|
1253 |
+ |
} |
|
1254 |
+ |
} |
|
1255 |
+ |
|
|
1256 |
+ |
// Ensure that we have a footer table |
|
1257 |
+ |
if ( getFooterTable() == null ) |
|
1258 |
+ |
{ |
|
1259 |
+ |
setFooterTable( new FixedWidthFlexTable() ); |
|
1260 |
+ |
} |
|
1261 |
+ |
|
|
1262 |
+ |
// Refresh the table |
|
1263 |
+ |
refreshHeaderTable( getFooterTable(), allInfos, false ); |
|
1264 |
+ |
} |
|
1265 |
+ |
|
|
1266 |
+ |
/** |
|
1267 |
+ |
* Update the header table based on the new {@link ColumnDefinition}. |
|
1268 |
+ |
*/ |
|
1269 |
+ |
protected void refreshHeaderTable() |
|
1270 |
+ |
{ |
|
1271 |
+ |
if ( !isHeaderGenerated ) |
|
1272 |
+ |
{ |
|
1273 |
+ |
return; |
|
1274 |
+ |
} |
|
1275 |
+ |
|
|
1276 |
+ |
// Generate the list of lists of ColumnHeaderInfo. |
|
1277 |
+ |
List<List<ColumnHeaderInfo>> allInfos = new ArrayList<List<ColumnHeaderInfo>>(); |
|
1278 |
+ |
int columnCount = visibleColumns.size(); |
|
1279 |
+ |
int headerCounts[] = new int[columnCount]; |
|
1280 |
+ |
int maxHeaderCount = 0; |
|
1281 |
+ |
for ( int col = 0; col < columnCount; col++ ) |
|
1282 |
+ |
{ |
|
1283 |
+ |
// Get the header property. |
|
1284 |
+ |
ColumnDefinition<RowType, ?> colDef = visibleColumns.get( col ); |
|
1285 |
+ |
HeaderProperty prop = colDef.getColumnProperty( HeaderProperty.TYPE ); |
|
1286 |
+ |
int headerCount = prop.getHeaderCount(); |
|
1287 |
+ |
headerCounts[col] = headerCount; |
|
1288 |
+ |
maxHeaderCount = Math.max( maxHeaderCount, headerCount ); |
|
1289 |
+ |
|
|
1290 |
+ |
// Add each ColumnHeaderInfo |
|
1291 |
+ |
List<ColumnHeaderInfo> infos = new ArrayList<ColumnHeaderInfo>(); |
|
1292 |
+ |
ColumnHeaderInfo prev = null; |
|
1293 |
+ |
for ( int row = 0; row < headerCount; row++ ) |
|
1294 |
+ |
{ |
|
1295 |
+ |
Object header = prop.getHeader( row, col ); |
|
1296 |
+ |
if ( prev != null && prev.header.equals( header ) ) |
|
1297 |
+ |
{ |
|
1298 |
+ |
prev.incrementRowSpan(); |
|
1299 |
+ |
} |
|
1300 |
+ |
else |
|
1301 |
+ |
{ |
|
1302 |
+ |
prev = new ColumnHeaderInfo( header ); |
|
1303 |
+ |
infos.add( 0, prev ); |
|
1304 |
+ |
} |
|
1305 |
+ |
} |
|
1306 |
+ |
allInfos.add( infos ); |
|
1307 |
+ |
} |
|
1308 |
+ |
|
|
1309 |
+ |
// Return early if there is no header |
|
1310 |
+ |
if ( maxHeaderCount == 0 ) |
|
1311 |
+ |
{ |
|
1312 |
+ |
return; |
|
1313 |
+ |
} |
|
1314 |
+ |
|
|
1315 |
+ |
// Fill in missing rows |
|
1316 |
+ |
for ( int col = 0; col < columnCount; col++ ) |
|
1317 |
+ |
{ |
|
1318 |
+ |
int headerCount = headerCounts[col]; |
|
1319 |
+ |
if ( headerCount < maxHeaderCount ) |
|
1320 |
+ |
{ |
|
1321 |
+ |
allInfos.get( col ).add( 0, new ColumnHeaderInfo( null, maxHeaderCount - headerCount ) ); |
|
1322 |
+ |
} |
|
1323 |
+ |
} |
|
1324 |
+ |
|
|
1325 |
+ |
// Refresh the table |
|
1326 |
+ |
refreshHeaderTable( getHeaderTable(), allInfos, true ); |
|
1327 |
+ |
} |
|
1328 |
+ |
|
|
1329 |
+ |
/** |
|
1330 |
+ |
* Refresh the list of the currently visible column definitions based on the |
|
1331 |
+ |
* {@link TableDefinition}. |
|
1332 |
+ |
*/ |
|
1333 |
+ |
protected void refreshVisibleColumnDefinitions() |
|
1334 |
+ |
{ |
|
1335 |
+ |
List<ColumnDefinition<RowType, ?>> colDefs = new ArrayList<ColumnDefinition<RowType, ?>>( tableDefinition.getVisibleColumnDefinitions() ); |
|
1336 |
+ |
if ( !colDefs.equals( visibleColumns ) ) |
|
1337 |
+ |
{ |
|
1338 |
+ |
visibleColumns = colDefs; |
|
1339 |
+ |
headersObsolete = true; |
|
1340 |
+ |
} |
|
1341 |
+ |
else |
|
1342 |
+ |
{ |
|
1343 |
+ |
// Check if any of the headers are dynamic |
|
1344 |
+ |
for ( ColumnDefinition<RowType, ?> colDef : colDefs ) |
|
1345 |
+ |
{ |
|
1346 |
+ |
if ( colDef.getColumnProperty( HeaderProperty.TYPE ).isDynamic() || colDef.getColumnProperty( FooterProperty.TYPE ).isDynamic() ) |
|
1347 |
+ |
{ |
|
1348 |
+ |
headersObsolete = true; |
|
1349 |
+ |
return; |
|
1350 |
+ |
} |
|
1351 |
+ |
} |
|
1352 |
+ |
} |
|
1353 |
+ |
} |
|
1354 |
+ |
|
|
1355 |
+ |
/** |
|
1356 |
+ |
* Remove a row from the table relative to the total number of rows. |
|
1357 |
+ |
* |
|
1358 |
+ |
* @param row the row index |
|
1359 |
+ |
*/ |
|
1360 |
+ |
protected void removeAbsoluteRow( int row ) |
|
1361 |
+ |
{ |
|
1362 |
+ |
// Physically remove the row if it is in the middle of the data table |
|
1363 |
+ |
int firstRow = getAbsoluteFirstRowIndex(); |
|
1364 |
+ |
int lastRow = getAbsoluteLastRowIndex(); |
|
1365 |
+ |
if ( row <= lastRow && row >= firstRow ) |
|
1366 |
+ |
{ |
|
1367 |
+ |
FixedWidthGrid dataTable = getDataTable(); |
|
1368 |
+ |
int relativeRow = row - firstRow; |
|
1369 |
+ |
if ( relativeRow < dataTable.getRowCount() ) |
|
1370 |
+ |
{ |
|
1371 |
+ |
dataTable.removeRow( relativeRow ); |
|
1372 |
+ |
} |
|
1373 |
+ |
} |
|
1374 |
+ |
} |
|
1375 |
+ |
|
|
1376 |
+ |
/** |
|
1377 |
+ |
* Set a block of data. This method is used when responding to data requests. |
|
1378 |
+ |
* <p/> |
|
1379 |
+ |
* This method takes an iterator of iterators, where each iterator represents |
|
1380 |
+ |
* one row of data starting with the first row. |
|
1381 |
+ |
* |
|
1382 |
+ |
* @param firstRow the row index that the rows iterator starts with |
|
1383 |
+ |
* @param rows the values associated with each row |
|
1384 |
+ |
*/ |
|
1385 |
+ |
protected void setData( int firstRow, Iterator<RowType> rows ) |
|
1386 |
+ |
{ |
|
1387 |
+ |
getDataTable().deselectAllRows(); |
|
1388 |
+ |
rowValues = new ArrayList<RowType>(); |
|
1389 |
+ |
if ( rows != null && rows.hasNext() ) |
|
1390 |
+ |
{ |
|
1391 |
+ |
setEmptyTableWidgetVisible( false ); |
|
1392 |
+ |
|
|
1393 |
+ |
// Get an iterator over the visible rows |
|
1394 |
+ |
int firstVisibleRow = getAbsoluteFirstRowIndex(); |
|
1395 |
+ |
int lastVisibleRow = getAbsoluteLastRowIndex(); |
|
1396 |
+ |
Iterator<RowType> visibleIter = new VisibleRowsIterator( rows, firstRow, firstVisibleRow, lastVisibleRow ); |
|
1397 |
+ |
|
|
1398 |
+ |
// Set the row values |
|
1399 |
+ |
while ( visibleIter.hasNext() ) |
|
1400 |
+ |
{ |
|
1401 |
+ |
rowValues.add( visibleIter.next() ); |
|
1402 |
+ |
} |
|
1403 |
+ |
|
|
1404 |
+ |
// Copy the visible column definitions |
|
1405 |
+ |
refreshVisibleColumnDefinitions(); |
|
1406 |
+ |
|
|
1407 |
+ |
// Render using the bulk renderer |
|
1408 |
+ |
if ( bulkRenderer != null ) |
|
1409 |
+ |
{ |
|
1410 |
+ |
bulkRenderer.renderRows( rowValues.iterator(), tableRendererCallback ); |
|
1411 |
+ |
return; |
|
1412 |
+ |
} |
|
1413 |
+ |
|
|
1414 |
+ |
// Get rid of unneeded rows and columns |
|
1415 |
+ |
int rowCount = rowValues.size(); |
|
1416 |
+ |
int colCount = visibleColumns.size(); |
|
1417 |
+ |
getDataTable().resize( rowCount, colCount ); |
|
1418 |
+ |
|
|
1419 |
+ |
// Render the rows |
|
1420 |
+ |
tableDefinition.renderRows( 0, rowValues.iterator(), rowView ); |
|
1421 |
+ |
} |
|
1422 |
+ |
else |
|
1423 |
+ |
{ |
|
1424 |
+ |
setEmptyTableWidgetVisible( true ); |
|
1425 |
+ |
} |
|
1426 |
+ |
|
|
1427 |
+ |
// Fire page loaded event |
|
1428 |
+ |
onDataTableRendered(); |
|
1429 |
+ |
} |
|
1430 |
+ |
|
|
1431 |
+ |
/** |
|
1432 |
+ |
* Set whether or not the empty table widget is visible. |
|
1433 |
+ |
* |
|
1434 |
+ |
* @param visible true to show the empty table widget |
|
1435 |
+ |
*/ |
|
1436 |
+ |
protected void setEmptyTableWidgetVisible( boolean visible ) |
|
1437 |
+ |
{ |
|
1438 |
+ |
emptyTableWidgetWrapper.setVisible( visible ); |
|
1439 |
+ |
if ( visible ) |
|
1440 |
+ |
{ |
|
1441 |
+ |
getDataWrapper().getStyle().setProperty( "display", "none" ); |
|
1442 |
+ |
} |
|
1443 |
+ |
else |
|
1444 |
+ |
{ |
|
1445 |
+ |
getDataWrapper().getStyle().setProperty( "display", "" ); |
|
1446 |
+ |
} |
|
1447 |
+ |
} |
|
1448 |
+ |
|
|
1449 |
+ |
/** |
|
1450 |
+ |
* Update the header or footer tables based on the new |
|
1451 |
+ |
* {@link ColumnDefinition}. |
|
1452 |
+ |
* |
|
1453 |
+ |
* @param table the header or footer table |
|
1454 |
+ |
* @param allInfos the header info |
|
1455 |
+ |
* @param isHeader false if refreshing the footer table |
|
1456 |
+ |
*/ |
|
1457 |
+ |
private void refreshHeaderTable( FixedWidthFlexTable table, List<List<ColumnHeaderInfo>> allInfos, boolean isHeader ) |
|
1458 |
+ |
{ |
|
1459 |
+ |
// Return if we have no column definitions. |
|
1460 |
+ |
if ( visibleColumns == null ) |
|
1461 |
+ |
{ |
|
1462 |
+ |
return; |
|
1463 |
+ |
} |
|
1464 |
+ |
|
|
1465 |
+ |
// Reset the header table. |
|
1466 |
+ |
int rowCount = table.getRowCount(); |
|
1467 |
+ |
for ( int i = 0; i < rowCount; i++ ) |
|
1468 |
+ |
{ |
|
1469 |
+ |
table.removeRow( 0 ); |
|
1470 |
+ |
} |
|
1471 |
+ |
|
|
1472 |
+ |
// Generate the header table |
|
1473 |
+ |
int columnCount = allInfos.size(); |
|
1474 |
+ |
FlexCellFormatter formatter = table.getFlexCellFormatter(); |
|
1475 |
+ |
List<ColumnHeaderInfo> prevInfos = null; |
|
1476 |
+ |
for ( int col = 0; col < columnCount; col++ ) |
|
1477 |
+ |
{ |
|
1478 |
+ |
List<ColumnHeaderInfo> infos = allInfos.get( col ); |
|
1479 |
+ |
int row = 0; |
|
1480 |
+ |
for ( ColumnHeaderInfo info : infos ) |
|
1481 |
+ |
{ |
|
1482 |
+ |
// Get the actual row and cell index |
|
1483 |
+ |
int rowSpan = info.getRowSpan(); |
|
1484 |
+ |
int cell = 0; |
|
1485 |
+ |
if ( table.getRowCount() > row ) |
|
1486 |
+ |
{ |
|
1487 |
+ |
cell = table.getCellCount( row ); |
|
1488 |
+ |
} |
|
1489 |
+ |
|
|
1490 |
+ |
// Compare to the cell in the previous column |
|
1491 |
+ |
if ( prevInfos != null ) |
|
1492 |
+ |
{ |
|
1493 |
+ |
boolean headerAdded = false; |
|
1494 |
+ |
int prevRow = 0; |
|
1495 |
+ |
for ( ColumnHeaderInfo prevInfo : prevInfos ) |
|
1496 |
+ |
{ |
|
1497 |
+ |
// Increase the colSpan of the previous cell |
|
1498 |
+ |
if ( prevRow == row && info.equals( prevInfo ) ) |
|
1499 |
+ |
{ |
|
1500 |
+ |
int colSpan = formatter.getColSpan( row, cell - 1 ); |
|
1501 |
+ |
formatter.setColSpan( row, cell - 1, colSpan + 1 ); |
|
1502 |
+ |
headerAdded = true; |
|
1503 |
+ |
break; |
|
1504 |
+ |
} |
|
1505 |
+ |
prevRow += prevInfo.getRowSpan(); |
|
1506 |
+ |
} |
|
1507 |
+ |
|
|
1508 |
+ |
if ( headerAdded ) |
|
1509 |
+ |
{ |
|
1510 |
+ |
row += rowSpan; |
|
1511 |
+ |
continue; |
|
1512 |
+ |
} |
|
1513 |
+ |
} |
|
1514 |
+ |
|
|
1515 |
+ |
// Set the new header |
|
1516 |
+ |
Object header = info.getHeader(); |
|
1517 |
+ |
if ( header instanceof Widget ) |
|
1518 |
+ |
{ |
|
1519 |
+ |
table.setWidget( row, cell, (Widget) header ); |
|
1520 |
+ |
} |
|
1521 |
+ |
else |
|
1522 |
+ |
{ |
|
1523 |
+ |
table.setHTML( row, cell, header.toString() ); |
|
1524 |
+ |
} |
|
1525 |
+ |
|
|
1526 |
+ |
// Update the rowSpan |
|
1527 |
+ |
if ( rowSpan > 1 ) |
|
1528 |
+ |
{ |
|
1529 |
+ |
formatter.setRowSpan( row, cell, rowSpan ); |
|
1530 |
+ |
} |
|
1531 |
+ |
|
|
1532 |
+ |
// Increment the row |
|
1533 |
+ |
row += rowSpan; |
|
1534 |
+ |
} |
|
1535 |
+ |
|
|
1536 |
+ |
// Increment the previous info |
|
1537 |
+ |
prevInfos = infos; |
|
1538 |
+ |
} |
|
1539 |
+ |
|
|
1540 |
+ |
// Insert the checkbox column |
|
1541 |
+ |
SelectionPolicy selectionPolicy = getDataTable().getSelectionPolicy(); |
|
1542 |
+ |
if ( selectionPolicy.hasInputColumn() ) |
|
1543 |
+ |
{ |
|
1544 |
+ |
// Get the select all box |
|
1545 |
+ |
Widget box = null; |
|
1546 |
+ |
if ( isHeader && getDataTable().getSelectionPolicy() == SelectionPolicy.CHECKBOX ) |
|
1547 |
+ |
{ |
|
1548 |
+ |
box = getSelectAllWidget(); |
|
1549 |
+ |
} |
|
1550 |
+ |
|
|
1551 |
+ |
// Add the offset column |
|
1552 |
+ |
table.insertCell( 0, 0 ); |
|
1553 |
+ |
if ( box != null ) |
|
1554 |
+ |
{ |
|
1555 |
+ |
table.setWidget( 0, 0, box ); |
|
1556 |
+ |
} |
|
1557 |
+ |
else |
|
1558 |
+ |
{ |
|
1559 |
+ |
table.setHTML( 0, 0, " " ); |
|
1560 |
+ |
} |
|
1561 |
+ |
formatter.setRowSpan( 0, 0, table.getRowCount() ); |
|
1562 |
+ |
formatter.setHorizontalAlignment( 0, 0, HasHorizontalAlignment.ALIGN_CENTER ); |
|
1563 |
+ |
table.setColumnWidth( 0, getDataTable().getInputColumnWidth() ); |
|
1564 |
+ |
} |
|
1565 |
+ |
} |
|
1566 |
+ |
|
|
1567 |
+ |
/** |
|
1568 |
+ |
* Refresh a single row in the table. |
|
1569 |
+ |
* |
|
1570 |
+ |
* @param rowIndex the index of the row |
|
1571 |
+ |
*/ |
|
1572 |
+ |
private void refreshRow( int rowIndex ) |
|
1573 |
+ |
{ |
|
1574 |
+ |
final RowType rowValue = getRowValue( rowIndex ); |
|
1575 |
+ |
Iterator<RowType> singleIterator = new Iterator<RowType>() |
|
1576 |
+ |
{ |
|
1577 |
+ |
private boolean nextCalled = false; |
|
1578 |
+ |
|
|
1579 |
+ |
public boolean hasNext() |
|
1580 |
+ |
{ |
|
1581 |
+ |
return !nextCalled; |
|
1582 |
+ |
} |
|
1583 |
+ |
|
|
1584 |
+ |
public RowType next() |
|
1585 |
+ |
{ |
|
1586 |
+ |
if ( !hasNext() ) |
|
1587 |
+ |
{ |
|
1588 |
+ |
throw new NoSuchElementException(); |
|
1589 |
+ |
} |
|
1590 |
+ |
nextCalled = true; |
|
1591 |
+ |
return rowValue; |
|
1592 |
+ |
} |
|
1593 |
+ |
|
|
1594 |
+ |
public void remove() |
|
1595 |
+ |
{ |
|
1596 |
+ |
throw new UnsupportedOperationException(); |
|
1597 |
+ |
} |
|
1598 |
+ |
}; |
|
1599 |
+ |
tableDefinition.renderRows( rowIndex, singleIterator, rowView ); |
|
1600 |
+ |
} |
1440 |
1601 |
|
} |