View Javadoc

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 javax.servlet.jsp.PageContext;
19  
20  import org.apache.commons.lang.builder.ToStringBuilder;
21  import org.apache.commons.lang.builder.ToStringStyle;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.displaytag.decorator.TableDecorator;
25  import org.displaytag.properties.MediaTypeEnum;
26  import org.displaytag.properties.TableProperties;
27  
28  
29  /**
30   * Table Model. Holds table data for presentation.
31   * @author Fabrizio Giustina
32   * @version $Revision: 1081 $ ($Author: fgiust $)
33   */
34  public class TableModel
35  {
36  
37      /**
38       * logger.
39       */
40      private static Log log = LogFactory.getLog(TableModel.class);
41  
42      /**
43       * list of HeaderCell.
44       */
45      private List headerCellList;
46  
47      /**
48       * full list (contains Row objects).
49       */
50      private List rowListFull;
51  
52      /**
53       * list of data to be displayed in page.
54       */
55      private List rowListPage;
56  
57      /**
58       * Name of the column currently sorted (only used when sort=external).
59       */
60      private String sortedColumnName;
61  
62      /**
63       * sort order = ascending?
64       */
65      private boolean sortOrderAscending = true;
66  
67      /**
68       * sort full List? (false sort only displayed page).
69       */
70      private boolean sortFullTable = true;
71  
72      /**
73       * index of the sorted column (-1 if the table is not sorted).
74       */
75      private int sortedColumn = -1;
76  
77      /**
78       * Table decorator.
79       */
80      private TableDecorator tableDecorator;
81  
82      /**
83       * id inherited from the TableTag (needed only for logging).
84       */
85      private String id;
86  
87      /**
88       * configurable table properties.
89       */
90      private TableProperties properties;
91  
92      /**
93       * Starting offset for elements in the viewable list.
94       */
95      private int pageOffset;
96  
97      /**
98       * Response encoding.
99       */
100     private String encoding;
101 
102     /**
103      * Are we sorting locally? (Default True)
104      */
105     private boolean localSort = true;
106 
107     /**
108      * Table caption.
109      */
110     private String caption;
111 
112     /**
113      * Table footer.
114      */
115     private String footer;
116 
117     /**
118      * Jsp page context.
119      */
120     private PageContext pageContext;
121 
122     /**
123      * Current media.
124      */
125     private MediaTypeEnum media;
126 
127     /**
128      * Constructor for TableModel.
129      * @param tableProperties table properties
130      * @param charEncoding response encoding
131      */
132     public TableModel(TableProperties tableProperties, String charEncoding, PageContext pageContext)
133     {
134         this.rowListFull = new ArrayList(20);
135         this.headerCellList = new ArrayList(20);
136         this.properties = tableProperties;
137         this.encoding = charEncoding;
138         this.pageContext = pageContext;
139     }
140 
141     /**
142      * Returns the jsp page context.
143      * @return page context
144      */
145     protected PageContext getPageContext()
146     {
147         return this.pageContext;
148     }
149 
150     /**
151      * Gets the current media type.
152      * @return current media (html, pdf ...)
153      */
154     public MediaTypeEnum getMedia()
155     {
156         return this.media;
157     }
158 
159     /**
160      * sets the current media type.
161      * @param media current media (html, pdf ...)
162      */
163     public void setMedia(MediaTypeEnum media)
164     {
165         this.media = media;
166     }
167 
168     /**
169      * Sets whether the table performs local in memory sorting of the data.
170      * @param localSort
171      */
172     public void setLocalSort(boolean localSort)
173     {
174         this.localSort = localSort;
175     }
176 
177     /**
178      * @return sorting in local memory
179      */
180     public boolean isLocalSort()
181     {
182         return localSort;
183     }
184 
185     /**
186      * Sets the starting offset for elements in the viewable list.
187      * @param offset The page offset to set.
188      */
189     public void setPageOffset(int offset)
190     {
191         this.pageOffset = offset;
192     }
193 
194     /**
195      * Setter for the tablemodel id.
196      * @param tableId same id of table tag, needed for logging
197      */
198     public void setId(String tableId)
199     {
200         this.id = tableId;
201     }
202 
203     /**
204      * get the table id.
205      * @return table id
206      */
207     public String getId()
208     {
209         return this.id;
210     }
211 
212     /**
213      * get the full list.
214      * @return the full list containing Row objects
215      */
216     public List getRowListFull()
217     {
218         return this.rowListFull;
219     }
220 
221     /**
222      * gets the partial (paginated) list.
223      * @return the partial list to display in page (contains Row objects)
224      */
225     public List getRowListPage()
226     {
227         return this.rowListPage;
228     }
229 
230     /**
231      * adds a Row object to the table.
232      * @param row Row
233      */
234     public void addRow(Row row)
235     {
236         row.setParentTable(this);
237 
238         if (log.isDebugEnabled())
239         {
240             log.debug("[" + this.id + "] adding row " + row);
241         }
242         this.rowListFull.add(row);
243     }
244 
245     /**
246      * sets the name of the currently sorted column
247      * @param sortedColumnName
248      */
249     public void setSortedColumnName(String sortedColumnName)
250     {
251         this.sortedColumnName = sortedColumnName;
252     }
253 
254     /**
255      * sets the sort full table property. If true the full list is sorted, if false sorting is applied only to the
256      * displayed sublist.
257      * @param sortFull boolean
258      */
259     public void setSortFullTable(boolean sortFull)
260     {
261         this.sortFullTable = sortFull;
262     }
263 
264     /**
265      * return the sort full table property.
266      * @return boolean true if sorting is applied to the full list
267      */
268     public boolean isSortFullTable()
269     {
270         return this.sortFullTable;
271     }
272 
273     /**
274      * return the sort order of the page.
275      * @return true if sort order is ascending
276      */
277     public boolean isSortOrderAscending()
278     {
279         return this.sortOrderAscending;
280 
281     }
282 
283     /**
284      * set the sort order of the list.
285      * @param isSortOrderAscending true to sort in ascending order
286      */
287     public void setSortOrderAscending(boolean isSortOrderAscending)
288     {
289         this.sortOrderAscending = isSortOrderAscending;
290     }
291 
292     /**
293      * @param rowList - the new value for this.rowListPage
294      */
295     public void setRowListPage(List rowList)
296     {
297         this.rowListPage = rowList;
298     }
299 
300     /**
301      * getter for the Table Decorator.
302      * @return TableDecorator
303      */
304     public TableDecorator getTableDecorator()
305     {
306         return this.tableDecorator;
307     }
308 
309     /**
310      * setter for the table decorator.
311      * @param decorator - the TableDecorator object
312      */
313     public void setTableDecorator(TableDecorator decorator)
314     {
315         this.tableDecorator = decorator;
316     }
317 
318     /**
319      * returns true if the table is sorted.
320      * @return boolean true if the table is sorted
321      */
322     public boolean isSorted()
323     {
324         return this.sortedColumn != -1;
325     }
326 
327     /**
328      * returns the HeaderCell for the sorted column.
329      * @return HeaderCell
330      */
331     public HeaderCell getSortedColumnHeader()
332     {
333         if (this.sortedColumn < 0 || (this.sortedColumn > (this.headerCellList.size() - 1)))
334         {
335             return null;
336         }
337         return (HeaderCell) this.headerCellList.get(this.sortedColumn);
338     }
339 
340     /**
341      * return the number of columns in the table.
342      * @return int number of columns
343      */
344     public int getNumberOfColumns()
345     {
346         return this.headerCellList.size();
347     }
348 
349     /**
350      * return true is the table has no columns.
351      * @return boolean
352      */
353     public boolean isEmpty()
354     {
355         return this.headerCellList.size() == 0;
356     }
357 
358     /**
359      * return the index of the sorted column.
360      * @return index of the sorted column or -1 if the table is not sorted
361      */
362     public int getSortedColumnNumber()
363     {
364         return this.sortedColumn;
365     }
366 
367     /**
368      * set the sorted column index.
369      * @param sortIndex - the index of the sorted column
370      */
371     public void setSortedColumnNumber(int sortIndex)
372     {
373         this.sortedColumn = sortIndex;
374     }
375 
376     /**
377      * Adds a column header (HeaderCell object).
378      * @param headerCell HeaderCell
379      */
380     public void addColumnHeader(HeaderCell headerCell)
381     {
382         if (this.sortedColumnName == null)
383         {
384             if (this.sortedColumn == this.headerCellList.size())
385             {
386                 headerCell.setAlreadySorted();
387             }
388         }
389         else
390         {
391             // the sorted parameter was a string so try and find that column name and set it as sorted
392             if (this.sortedColumnName.equals(headerCell.getSortName()))
393             {
394                 headerCell.setAlreadySorted();
395             }
396         }
397         headerCell.setColumnNumber(this.headerCellList.size());
398 
399         this.headerCellList.add(headerCell);
400     }
401 
402     /**
403      * List containing headerCell objects.
404      * @return List containing headerCell objects
405      */
406     public List getHeaderCellList()
407     {
408         return this.headerCellList;
409     }
410 
411     /**
412      * returns a RowIterator on the requested (full|page) list.
413      * @return RowIterator
414      * @param full if <code>true</code> returns an iterator on te full list, if <code>false</code> only on the
415      * viewable part.
416      * @see org.displaytag.model.RowIterator
417      */
418     public RowIterator getRowIterator(boolean full)
419     {
420         RowIterator iterator = new RowIterator(
421             full ? this.rowListFull : this.rowListPage,
422             this.headerCellList,
423             this.tableDecorator,
424             this.pageOffset);
425         // copy id for logging
426         iterator.setId(this.id);
427         return iterator;
428     }
429 
430     /**
431      * sorts the given list of Rows. The method is called internally by sortFullList() and sortPageList().
432      * @param list List
433      */
434     private void sortRowList(List list)
435     {
436         if (isSorted())
437         {
438             HeaderCell sortedHeaderCell = getSortedColumnHeader();
439 
440             if (sortedHeaderCell != null)
441             {
442                 // If it is an explicit value, then sort by that, otherwise sort by the property...
443                 if (sortedHeaderCell.getBeanPropertyName() != null
444                     || (this.sortedColumn != -1 && this.sortedColumn < this.headerCellList.size()))
445                 {
446 
447                     String sorted = (sortedHeaderCell.getSortProperty() != null)
448                         ? sortedHeaderCell.getSortProperty()
449                         : sortedHeaderCell.getBeanPropertyName();
450 
451                     Collections.sort(list, new RowSorter(
452                         this.sortedColumn,
453                         sorted,
454                         getTableDecorator(),
455                         this.sortOrderAscending,
456                         sortedHeaderCell.getComparator()));
457                 }
458             }
459 
460         }
461 
462     }
463 
464     /**
465      * sort the list displayed in page.
466      */
467     public void sortPageList()
468     {
469         if (log.isDebugEnabled())
470         {
471             log.debug("[" + this.id + "] sorting page list");
472         }
473         sortRowList(this.rowListPage);
474 
475     }
476 
477     /**
478      * sort the full list of data.
479      */
480     public void sortFullList()
481     {
482         if (log.isDebugEnabled())
483         {
484             log.debug("[" + this.id + "] sorting full data");
485         }
486         sortRowList(this.rowListFull);
487     }
488 
489     /**
490      * Returns the table properties.
491      * @return the configured table properties.
492      */
493     public TableProperties getProperties()
494     {
495         return this.properties;
496     }
497 
498     /**
499      * Getter for character encoding.
500      * @return Returns the encoding used for response.
501      */
502     public String getEncoding()
503     {
504         return encoding;
505     }
506 
507     /**
508      * Obtain this table's caption.
509      * @return This table's caption.
510      */
511     public String getCaption()
512     {
513         return this.caption;
514     }
515 
516     /**
517      * Set this table's caption.
518      * @param caption This table's caption.
519      */
520     public void setCaption(String caption)
521     {
522         this.caption = caption;
523     }
524 
525     /**
526      * Obtain this table's footer.
527      * @return This table's footer.
528      */
529     public String getFooter()
530     {
531         return this.footer;
532     }
533 
534     /**
535      * Set this table's footer.
536      * @param footer This table's footer.
537      */
538     public void setFooter(String footer)
539     {
540         this.footer = footer;
541     }
542 
543     /**
544      * @see java.lang.Object#toString()
545      */
546     public String toString()
547     {
548         return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) //
549             .append("rowListFull", this.rowListFull) //$NON-NLS-1$
550             .append("rowListPage", this.rowListPage) //$NON-NLS-1$
551             .append("properties", this.properties) //$NON-NLS-1$
552             .append("empty", this.isEmpty()) //$NON-NLS-1$
553             .append("encoding", this.encoding) //$NON-NLS-1$
554             .append("numberOfColumns", this.getNumberOfColumns()) //$NON-NLS-1$
555             .append("headerCellList", this.headerCellList) //$NON-NLS-1$
556             .append("sortFullTable", this.sortFullTable) //$NON-NLS-1$
557             .append("sortedColumnNumber", this.getSortedColumnNumber()) //$NON-NLS-1$
558             .append("sortOrderAscending", this.sortOrderAscending) //$NON-NLS-1$
559             .append("sortedColumnHeader", this.getSortedColumnHeader()) //$NON-NLS-1$
560             .append("sorted", this.isSorted()) //$NON-NLS-1$
561             .append("tableDecorator", this.tableDecorator) //$NON-NLS-1$
562             .append("caption", this.caption) //$NON-NLS-1
563             .append("footer", this.footer) //$NON-NLS-1
564             .append("media", this.media) //$NON-NLS-1
565             .toString();
566     }
567 
568 }