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 }