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: 1125 $ ($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      * Uses post for links.
129      */
130     private String form;
131 
132     /**
133      * Constructor for TableModel.
134      * @param tableProperties table properties
135      * @param charEncoding response encoding
136      */
137     public TableModel(TableProperties tableProperties, String charEncoding, PageContext pageContext)
138     {
139         this.rowListFull = new ArrayList(20);
140         this.headerCellList = new ArrayList(20);
141         this.properties = tableProperties;
142         this.encoding = charEncoding;
143         this.pageContext = pageContext;
144     }
145 
146     /**
147      * Returns the jsp page context.
148      * @return page context
149      */
150     protected PageContext getPageContext()
151     {
152         return this.pageContext;
153     }
154 
155     /**
156      * Gets the current media type.
157      * @return current media (html, pdf ...)
158      */
159     public MediaTypeEnum getMedia()
160     {
161         return this.media;
162     }
163 
164     /**
165      * sets the current media type.
166      * @param media current media (html, pdf ...)
167      */
168     public void setMedia(MediaTypeEnum media)
169     {
170         this.media = media;
171     }
172 
173     /**
174      * Sets whether the table performs local in memory sorting of the data.
175      * @param localSort
176      */
177     public void setLocalSort(boolean localSort)
178     {
179         this.localSort = localSort;
180     }
181 
182     /**
183      * @return sorting in local memory
184      */
185     public boolean isLocalSort()
186     {
187         return localSort;
188     }
189 
190     /**
191      * Getter for <code>form</code>.
192      * @return Returns the form.
193      */
194     public String getForm()
195     {
196         return this.form;
197     }
198 
199     /**
200      * Setter for <code>form</code>.
201      * @param form The form to set.
202      */
203     public void setForm(String form)
204     {
205         this.form = form;
206     }
207 
208     /**
209      * Sets the starting offset for elements in the viewable list.
210      * @param offset The page offset to set.
211      */
212     public void setPageOffset(int offset)
213     {
214         this.pageOffset = offset;
215     }
216 
217     /**
218      * Setter for the tablemodel id.
219      * @param tableId same id of table tag, needed for logging
220      */
221     public void setId(String tableId)
222     {
223         this.id = tableId;
224     }
225 
226     /**
227      * get the table id.
228      * @return table id
229      */
230     public String getId()
231     {
232         return this.id;
233     }
234 
235     /**
236      * get the full list.
237      * @return the full list containing Row objects
238      */
239     public List getRowListFull()
240     {
241         return this.rowListFull;
242     }
243 
244     /**
245      * gets the partial (paginated) list.
246      * @return the partial list to display in page (contains Row objects)
247      */
248     public List getRowListPage()
249     {
250         return this.rowListPage;
251     }
252 
253     /**
254      * adds a Row object to the table.
255      * @param row Row
256      */
257     public void addRow(Row row)
258     {
259         row.setParentTable(this);
260 
261         if (log.isDebugEnabled())
262         {
263             log.debug("[" + this.id + "] adding row " + row);
264         }
265         this.rowListFull.add(row);
266     }
267 
268     /**
269      * sets the name of the currently sorted column
270      * @param sortedColumnName
271      */
272     public void setSortedColumnName(String sortedColumnName)
273     {
274         this.sortedColumnName = sortedColumnName;
275     }
276 
277     /**
278      * sets the sort full table property. If true the full list is sorted, if false sorting is applied only to the
279      * displayed sublist.
280      * @param sortFull boolean
281      */
282     public void setSortFullTable(boolean sortFull)
283     {
284         this.sortFullTable = sortFull;
285     }
286 
287     /**
288      * return the sort full table property.
289      * @return boolean true if sorting is applied to the full list
290      */
291     public boolean isSortFullTable()
292     {
293         return this.sortFullTable;
294     }
295 
296     /**
297      * return the sort order of the page.
298      * @return true if sort order is ascending
299      */
300     public boolean isSortOrderAscending()
301     {
302         return this.sortOrderAscending;
303 
304     }
305 
306     /**
307      * set the sort order of the list.
308      * @param isSortOrderAscending true to sort in ascending order
309      */
310     public void setSortOrderAscending(boolean isSortOrderAscending)
311     {
312         this.sortOrderAscending = isSortOrderAscending;
313     }
314 
315     /**
316      * @param rowList - the new value for this.rowListPage
317      */
318     public void setRowListPage(List rowList)
319     {
320         this.rowListPage = rowList;
321     }
322 
323     /**
324      * getter for the Table Decorator.
325      * @return TableDecorator
326      */
327     public TableDecorator getTableDecorator()
328     {
329         return this.tableDecorator;
330     }
331 
332     /**
333      * setter for the table decorator.
334      * @param decorator - the TableDecorator object
335      */
336     public void setTableDecorator(TableDecorator decorator)
337     {
338         this.tableDecorator = decorator;
339     }
340 
341     /**
342      * returns true if the table is sorted.
343      * @return boolean true if the table is sorted
344      */
345     public boolean isSorted()
346     {
347         return this.sortedColumn != -1;
348     }
349 
350     /**
351      * returns the HeaderCell for the sorted column.
352      * @return HeaderCell
353      */
354     public HeaderCell getSortedColumnHeader()
355     {
356         if (this.sortedColumn < 0 || (this.sortedColumn > (this.headerCellList.size() - 1)))
357         {
358             return null;
359         }
360         return (HeaderCell) this.headerCellList.get(this.sortedColumn);
361     }
362 
363     /**
364      * return the number of columns in the table.
365      * @return int number of columns
366      */
367     public int getNumberOfColumns()
368     {
369         return this.headerCellList.size();
370     }
371 
372     /**
373      * return true is the table has no columns.
374      * @return boolean
375      */
376     public boolean isEmpty()
377     {
378         return this.headerCellList.size() == 0;
379     }
380 
381     /**
382      * return the index of the sorted column.
383      * @return index of the sorted column or -1 if the table is not sorted
384      */
385     public int getSortedColumnNumber()
386     {
387         return this.sortedColumn;
388     }
389 
390     /**
391      * set the sorted column index.
392      * @param sortIndex - the index of the sorted column
393      */
394     public void setSortedColumnNumber(int sortIndex)
395     {
396         this.sortedColumn = sortIndex;
397     }
398 
399     /**
400      * Adds a column header (HeaderCell object).
401      * @param headerCell HeaderCell
402      */
403     public void addColumnHeader(HeaderCell headerCell)
404     {
405         if (this.sortedColumnName == null)
406         {
407             if (this.sortedColumn == this.headerCellList.size())
408             {
409                 headerCell.setAlreadySorted();
410             }
411         }
412         else
413         {
414             // the sorted parameter was a string so try and find that column name and set it as sorted
415             if (this.sortedColumnName.equals(headerCell.getSortName()))
416             {
417                 headerCell.setAlreadySorted();
418             }
419         }
420         headerCell.setColumnNumber(this.headerCellList.size());
421 
422         this.headerCellList.add(headerCell);
423     }
424 
425     /**
426      * List containing headerCell objects.
427      * @return List containing headerCell objects
428      */
429     public List getHeaderCellList()
430     {
431         return this.headerCellList;
432     }
433 
434     /**
435      * returns a RowIterator on the requested (full|page) list.
436      * @return RowIterator
437      * @param full if <code>true</code> returns an iterator on te full list, if <code>false</code> only on the
438      * viewable part.
439      * @see org.displaytag.model.RowIterator
440      */
441     public RowIterator getRowIterator(boolean full)
442     {
443         RowIterator iterator = new RowIterator(
444             full ? this.rowListFull : this.rowListPage,
445             this.headerCellList,
446             this.tableDecorator,
447             this.pageOffset);
448         // copy id for logging
449         iterator.setId(this.id);
450         return iterator;
451     }
452 
453     /**
454      * sorts the given list of Rows. The method is called internally by sortFullList() and sortPageList().
455      * @param list List
456      */
457     private void sortRowList(List list)
458     {
459         if (isSorted())
460         {
461             HeaderCell sortedHeaderCell = getSortedColumnHeader();
462 
463             if (sortedHeaderCell != null)
464             {
465                 // If it is an explicit value, then sort by that, otherwise sort by the property...
466                 if (sortedHeaderCell.getBeanPropertyName() != null
467                     || (this.sortedColumn != -1 && this.sortedColumn < this.headerCellList.size()))
468                 {
469 
470                     String sorted = (sortedHeaderCell.getSortProperty() != null)
471                         ? sortedHeaderCell.getSortProperty()
472                         : sortedHeaderCell.getBeanPropertyName();
473 
474                     Collections.sort(list, new RowSorter(
475                         this.sortedColumn,
476                         sorted,
477                         getTableDecorator(),
478                         this.sortOrderAscending,
479                         sortedHeaderCell.getComparator()));
480                 }
481             }
482 
483         }
484 
485     }
486 
487     /**
488      * sort the list displayed in page.
489      */
490     public void sortPageList()
491     {
492         if (log.isDebugEnabled())
493         {
494             log.debug("[" + this.id + "] sorting page list");
495         }
496         sortRowList(this.rowListPage);
497 
498     }
499 
500     /**
501      * sort the full list of data.
502      */
503     public void sortFullList()
504     {
505         if (log.isDebugEnabled())
506         {
507             log.debug("[" + this.id + "] sorting full data");
508         }
509         sortRowList(this.rowListFull);
510     }
511 
512     /**
513      * Returns the table properties.
514      * @return the configured table properties.
515      */
516     public TableProperties getProperties()
517     {
518         return this.properties;
519     }
520 
521     /**
522      * Getter for character encoding.
523      * @return Returns the encoding used for response.
524      */
525     public String getEncoding()
526     {
527         return encoding;
528     }
529 
530     /**
531      * Obtain this table's caption.
532      * @return This table's caption.
533      */
534     public String getCaption()
535     {
536         return this.caption;
537     }
538 
539     /**
540      * Set this table's caption.
541      * @param caption This table's caption.
542      */
543     public void setCaption(String caption)
544     {
545         this.caption = caption;
546     }
547 
548     /**
549      * Obtain this table's footer.
550      * @return This table's footer.
551      */
552     public String getFooter()
553     {
554         return this.footer;
555     }
556 
557     /**
558      * Set this table's footer.
559      * @param footer This table's footer.
560      */
561     public void setFooter(String footer)
562     {
563         this.footer = footer;
564     }
565 
566     /**
567      * @see java.lang.Object#toString()
568      */
569     public String toString()
570     {
571         return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) //
572             .append("rowListFull", this.rowListFull) //$NON-NLS-1$
573             .append("rowListPage", this.rowListPage) //$NON-NLS-1$
574             .append("properties", this.properties) //$NON-NLS-1$
575             .append("empty", this.isEmpty()) //$NON-NLS-1$
576             .append("encoding", this.encoding) //$NON-NLS-1$
577             .append("numberOfColumns", this.getNumberOfColumns()) //$NON-NLS-1$
578             .append("headerCellList", this.headerCellList) //$NON-NLS-1$
579             .append("sortFullTable", this.sortFullTable) //$NON-NLS-1$
580             .append("sortedColumnNumber", this.getSortedColumnNumber()) //$NON-NLS-1$
581             .append("sortOrderAscending", this.sortOrderAscending) //$NON-NLS-1$
582             .append("sortedColumnHeader", this.getSortedColumnHeader()) //$NON-NLS-1$
583             .append("sorted", this.isSorted()) //$NON-NLS-1$
584             .append("tableDecorator", this.tableDecorator) //$NON-NLS-1$
585             .append("caption", this.caption) //$NON-NLS-1
586             .append("footer", this.footer) //$NON-NLS-1
587             .append("media", this.media) //$NON-NLS-1
588             .toString();
589     }
590 
591 }