1 /***
2 * Licensed under the Artistic License; you may not use this file
3 * except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://displaytag.sourceforge.net/license.html
7 *
8 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12 package org.displaytag.model;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17
18 import org.apache.commons.lang.builder.ToStringBuilder;
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.displaytag.decorator.TableDecorator;
22 import org.displaytag.properties.TableProperties;
23 import org.displaytag.util.ShortToStringStyle;
24
25
26 /***
27 * Table Model. Holds table data for presentation.
28 * @author Fabrizio Giustina
29 * @version $Revision: 1.17 $ ($Author: fgiust $)
30 */
31 public class TableModel
32 {
33
34 /***
35 * logger.
36 */
37 private static Log log = LogFactory.getLog(TableModel.class);
38
39 /***
40 * list of HeaderCell.
41 */
42 private List headerCellList;
43
44 /***
45 * full list (contains Row objects).
46 */
47 private List rowListFull;
48
49 /***
50 * list of data to be displayed in page.
51 */
52 private List rowListPage;
53
54 /***
55 * sort order = ascending?
56 */
57 private boolean sortOrderAscending = true;
58
59 /***
60 * sort full List? (false sort only displayed page).
61 */
62 private boolean sortFullTable = true;
63
64 /***
65 * index of the sorted column (-1 if the table is not sorted).
66 */
67 private int sortedColumn = -1;
68
69 /***
70 * Table decorator.
71 */
72 private TableDecorator tableDecorator;
73
74 /***
75 * id inherited from the TableTag (needed only for logging).
76 */
77 private String id;
78
79 /***
80 * configurable table properties.
81 */
82 private TableProperties properties;
83
84 /***
85 * Starting offset for elements in the viewable list.
86 */
87 private int pageOffset;
88
89 /***
90 * Response encoding.
91 */
92 private String encoding;
93
94 /***
95 * Constructor for TableModel.
96 * @param tableProperties table properties
97 * @param charEncoding response encoding
98 */
99 public TableModel(TableProperties tableProperties, String charEncoding)
100 {
101 this.rowListFull = new ArrayList(20);
102 this.headerCellList = new ArrayList(20);
103 this.properties = tableProperties;
104 this.encoding = charEncoding;
105 }
106
107 /***
108 * Sets the starting offset for elements in the viewable list.
109 * @param offset The page offset to set.
110 */
111 public void setPageOffset(int offset)
112 {
113 this.pageOffset = offset;
114 }
115
116 /***
117 * Setter for the tablemodel id.
118 * @param tableId same id of table tag, needed for logging
119 */
120 public void setId(String tableId)
121 {
122 this.id = tableId;
123 }
124
125 /***
126 * get the full list.
127 * @return the full list containing Row objects
128 */
129 public List getRowListFull()
130 {
131 return this.rowListFull;
132 }
133
134 /***
135 * gets the partial (paginated) list.
136 * @return the partial list to display in page (contains Row objects)
137 */
138 public List getRowListPage()
139 {
140 return this.rowListPage;
141 }
142
143 /***
144 * adds a Row object to the table.
145 * @param row Row
146 */
147 public void addRow(Row row)
148 {
149 row.setParentTable(this);
150
151 if (log.isDebugEnabled())
152 {
153 log.debug("[" + this.id + "] adding row " + row);
154 }
155 this.rowListFull.add(row);
156 }
157
158 /***
159 * sets the sort full table property. If true the full list is sorted, if false sorting is applied only to the
160 * displayed sublist.
161 * @param sortFull boolean
162 */
163 public void setSortFullTable(boolean sortFull)
164 {
165 this.sortFullTable = sortFull;
166 }
167
168 /***
169 * return the sort full table property.
170 * @return boolean true if sorting is applied to the full list
171 */
172 public boolean isSortFullTable()
173 {
174 return this.sortFullTable;
175 }
176
177 /***
178 * return the sort order of the page.
179 * @return true if sort order is ascending
180 */
181 public boolean isSortOrderAscending()
182 {
183 return this.sortOrderAscending;
184
185 }
186
187 /***
188 * set the sort order of the list.
189 * @param isSortOrderAscending true to sort in ascending order
190 */
191 public void setSortOrderAscending(boolean isSortOrderAscending)
192 {
193 this.sortOrderAscending = isSortOrderAscending;
194 }
195
196 /***
197 * @param rowList - the new value for this.rowListPage
198 */
199 public void setRowListPage(List rowList)
200 {
201 this.rowListPage = rowList;
202 }
203
204 /***
205 * getter for the Table Decorator.
206 * @return TableDecorator
207 */
208 public TableDecorator getTableDecorator()
209 {
210 return this.tableDecorator;
211 }
212
213 /***
214 * setter for the table decorator.
215 * @param decorator - the TableDecorator object
216 */
217 public void setTableDecorator(TableDecorator decorator)
218 {
219 this.tableDecorator = decorator;
220 }
221
222 /***
223 * returns true if the table is sorted.
224 * @return boolean true if the table is sorted
225 */
226 public boolean isSorted()
227 {
228 return this.sortedColumn != -1;
229 }
230
231 /***
232 * returns the HeaderCell for the sorted column.
233 * @return HeaderCell
234 */
235 public HeaderCell getSortedColumnHeader()
236 {
237 if (this.sortedColumn < 0 || (this.sortedColumn > (this.headerCellList.size() - 1)))
238 {
239 return null;
240 }
241 return (HeaderCell) this.headerCellList.get(this.sortedColumn);
242 }
243
244 /***
245 * return the number of columns in the table.
246 * @return int number of columns
247 */
248 public int getNumberOfColumns()
249 {
250 return this.headerCellList.size();
251 }
252
253 /***
254 * return true is the table has no columns.
255 * @return boolean
256 */
257 public boolean isEmpty()
258 {
259 return this.headerCellList.size() == 0;
260 }
261
262 /***
263 * return the index of the sorted column.
264 * @return index of the sorted column or -1 if the table is not sorted
265 */
266 public int getSortedColumnNumber()
267 {
268 return this.sortedColumn;
269 }
270
271 /***
272 * set the sorted column index.
273 * @param sortIndex - the index of the sorted column
274 */
275 public void setSortedColumnNumber(int sortIndex)
276 {
277 this.sortedColumn = sortIndex;
278 }
279
280 /***
281 * Adds a column header (HeaderCell object).
282 * @param headerCell HeaderCell
283 */
284 public void addColumnHeader(HeaderCell headerCell)
285 {
286 if (this.sortedColumn == this.headerCellList.size())
287 {
288 headerCell.setAlreadySorted();
289 }
290 headerCell.setColumnNumber(this.headerCellList.size());
291
292 this.headerCellList.add(headerCell);
293 }
294
295 /***
296 * List containing headerCell objects.
297 * @return List containing headerCell objects
298 */
299 public List getHeaderCellList()
300 {
301 return this.headerCellList;
302 }
303
304 /***
305 * returns a RowIterator on the requested (full|page) list.
306 * @return RowIterator
307 * @param full if <code>true</code> returns an iterator on te full list, if <code>false</code> only on the
308 * viewable part.
309 * @see org.displaytag.model.RowIterator
310 */
311 public RowIterator getRowIterator(boolean full)
312 {
313 RowIterator iterator = new RowIterator(
314 full ? this.rowListFull : this.rowListPage,
315 this.headerCellList,
316 this.tableDecorator,
317 this.pageOffset);
318
319 iterator.setId(this.id);
320 return iterator;
321 }
322
323 /***
324 * sorts the given list of Rows. The method is called internally by sortFullList() and sortPageList().
325 * @param list List
326 */
327 private void sortRowList(List list)
328 {
329 if (isSorted())
330 {
331 HeaderCell sortedHeaderCell = getSortedColumnHeader();
332
333 if (sortedHeaderCell != null)
334 {
335
336 if (sortedHeaderCell.getBeanPropertyName() != null
337 || (this.sortedColumn != -1 && this.sortedColumn < this.headerCellList.size()))
338 {
339 if (sortedHeaderCell.getSortProperty() != null)
340 {
341 Collections.sort(list, new RowSorter(
342 this.sortedColumn,
343 sortedHeaderCell.getSortProperty(),
344 getTableDecorator(),
345 this.sortOrderAscending));
346 }
347 else
348 {
349 Collections.sort(list, new RowSorter(
350 this.sortedColumn,
351 sortedHeaderCell.getBeanPropertyName(),
352 getTableDecorator(),
353 this.sortOrderAscending));
354 }
355 }
356 }
357
358 }
359
360 }
361
362 /***
363 * sort the list displayed in page.
364 */
365 public void sortPageList()
366 {
367 if (log.isDebugEnabled())
368 {
369 log.debug("[" + this.id + "] sorting page list");
370 }
371 sortRowList(this.rowListPage);
372
373 }
374
375 /***
376 * sort the full list of data.
377 */
378 public void sortFullList()
379 {
380 if (log.isDebugEnabled())
381 {
382 log.debug("[" + this.id + "] sorting full data");
383 }
384 sortRowList(this.rowListFull);
385 }
386
387 /***
388 * Returns the table properties.
389 * @return the configured table properties.
390 */
391 public TableProperties getProperties()
392 {
393 return this.properties;
394 }
395
396 /***
397 * Getter for character encoding.
398 * @return Returns the encoding used for response.
399 */
400 public String getEncoding()
401 {
402 return encoding;
403 }
404
405 /***
406 * @see java.lang.Object#toString()
407 */
408 public String toString()
409 {
410 return new ToStringBuilder(this, ShortToStringStyle.SHORT_STYLE)
411 .append("rowListFull", this.rowListFull)
412 .append("rowListPage", this.rowListPage)
413 .append("properties", this.properties)
414 .append("empty", this.isEmpty())
415 .append("encoding", this.encoding)
416 .append("numberOfColumns", this.getNumberOfColumns())
417 .append("headerCellList", this.headerCellList)
418 .append("sortFullTable", this.sortFullTable)
419 .append("sortedColumnNumber", this.getSortedColumnNumber())
420 .append("sortOrderAscending", this.sortOrderAscending)
421 .append("sortedColumnHeader", this.getSortedColumnHeader())
422 .append("sorted", this.isSorted())
423 .append("tableDecorator", this.tableDecorator)
424 .toString();
425 }
426 }