001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.workplace.list; 029 030import org.opencms.i18n.CmsMessageContainer; 031import org.opencms.i18n.CmsMessages; 032import org.opencms.main.CmsIllegalArgumentException; 033import org.opencms.main.CmsIllegalStateException; 034import org.opencms.util.CmsStringUtil; 035import org.opencms.workplace.CmsWorkplace; 036import org.opencms.workplace.commons.CmsProgressThread; 037import org.opencms.workplace.tools.A_CmsHtmlIconButton; 038import org.opencms.workplace.tools.CmsHtmlIconButtonStyleEnum; 039 040import java.util.ArrayList; 041import java.util.Collection; 042import java.util.Collections; 043import java.util.Iterator; 044import java.util.List; 045import java.util.Locale; 046 047/** 048 * The main class of the html list widget.<p> 049 * 050 * @since 6.0.0 051 */ 052public class CmsHtmlList { 053 054 /** Standard list button location. */ 055 public static final String ICON_LEFT = "list/leftarrow.png"; 056 057 /** Standard list button location. */ 058 public static final String ICON_RIGHT = "list/rightarrow.png"; 059 060 /** Constant for item separator char used for coding/encoding multiselection. */ 061 public static final String ITEM_SEPARATOR = "|"; 062 063 /** Constant name for error message if no item has been selected. */ 064 public static final String NO_SELECTION_HELP_VAR = "noSelHelp"; 065 066 /** Constant name for error message if number of selected items does not match. */ 067 public static final String NO_SELECTION_MATCH_HELP_VAR = "noSelMatchHelp"; 068 069 /** Current displayed page number. */ 070 protected int m_currentPage; 071 072 /** Current sort order. */ 073 protected CmsListOrderEnum m_currentSortOrder; 074 075 /** Filtered list of items or <code>null</code> if no filter is set and not sorted. */ 076 protected List<CmsListItem> m_filteredItems; 077 078 /** Dhtml id. */ 079 protected final String m_id; 080 081 /** If this flag is set the list will be surrounded by a box. */ 082 protected boolean m_isBoxed = true; 083 084 /** Maximum number of items per page. */ 085 protected int m_maxItemsPerPage = 20; 086 087 /** Metadata for building the list. */ 088 protected CmsListMetadata m_metadata; 089 090 /** Display Name of the list. */ 091 protected CmsMessageContainer m_name; 092 093 /** Really content of the list. */ 094 protected List<CmsListItem> m_originalItems = new ArrayList<CmsListItem>(); 095 096 /** printable flag. */ 097 protected boolean m_printable; 098 099 /** Search filter text. */ 100 protected String m_searchFilter = ""; 101 102 /** Show the title of the list. */ 103 protected boolean m_showTitle; 104 105 /** The filtered content size, only used if data self managed. */ 106 protected int m_size; 107 108 /** Column name to be sorted. */ 109 protected String m_sortedColumn; 110 111 /** The total size, only used is data self managed. */ 112 protected int m_totalSize; 113 114 /** Items currently displayed. */ 115 protected List<CmsListItem> m_visibleItems; 116 117 /** The related workplace dialog object. */ 118 protected transient A_CmsListDialog m_wp; 119 120 /** 121 * Default Constructor.<p> 122 * 123 * @param id unique id of the list, is used as name for controls and js functions and vars 124 * @param name the display name 125 * @param metadata the list's metadata 126 */ 127 public CmsHtmlList(String id, CmsMessageContainer name, CmsListMetadata metadata) { 128 129 m_id = id; 130 m_name = name; 131 m_metadata = metadata; 132 m_currentPage = 1; 133 m_showTitle = true; 134 } 135 136 /** 137 * Generates the list of html option elements for a html select control to select a page of a list.<p> 138 * 139 * @param nrPages the total number of pages 140 * @param itemsPage the maximum number of items per page 141 * @param nrItems the total number of items 142 * @param curPage the current page 143 * @param locale the locale 144 * 145 * @return html code 146 */ 147 public static String htmlPageSelector(int nrPages, int itemsPage, int nrItems, int curPage, Locale locale) { 148 149 StringBuffer html = new StringBuffer(256); 150 for (int i = 0; i < nrPages; i++) { 151 int displayedFrom = (i * itemsPage) + 1; 152 int displayedTo = ((i + 1) * itemsPage) < nrItems ? (i + 1) * itemsPage : nrItems; 153 html.append("\t\t\t\t<option value='"); 154 html.append(i + 1); 155 html.append("'"); 156 html.append((i + 1) == curPage ? " selected" : ""); 157 html.append(">"); 158 html.append( 159 Messages.get().getBundle(locale).key( 160 Messages.GUI_LIST_PAGE_ENTRY_3, 161 Integer.valueOf(i + 1), 162 Integer.valueOf(displayedFrom), 163 Integer.valueOf(displayedTo))); 164 html.append("</option>\n"); 165 } 166 return html.toString(); 167 } 168 169 /** 170 * This method resets the content of the list (no the metadata).<p> 171 */ 172 public void clear() { 173 174 if (m_originalItems != null) { 175 m_originalItems.clear(); 176 } 177 m_filteredItems = null; 178 synchronized (this) { 179 if (m_visibleItems != null) { 180 m_visibleItems.clear(); 181 } 182 } 183 setSearchFilter(""); 184 m_sortedColumn = null; 185 } 186 187 /** 188 * Returns all list items in the list, may be not visible and sorted.<p> 189 * 190 * @return all list items 191 */ 192 public List<CmsListItem> getAllContent() { 193 194 if (m_metadata.isSelfManaged()) { 195 if (m_filteredItems != null) { 196 return Collections.unmodifiableList(m_filteredItems); 197 } else { 198 return Collections.emptyList(); 199 } 200 } else { 201 if (m_originalItems != null) { 202 return Collections.unmodifiableList(m_originalItems); 203 } else { 204 return Collections.emptyList(); 205 } 206 } 207 } 208 209 /** 210 * Returns the filtered list of list items.<p> 211 * 212 * Equals to <code>{@link #getAllContent()}</code> if no filter is set.<p> 213 * 214 * @return the filtered list of list items 215 */ 216 public List<CmsListItem> getContent() { 217 218 if (m_filteredItems == null) { 219 return getAllContent(); 220 } else { 221 return Collections.unmodifiableList(m_filteredItems); 222 } 223 } 224 225 /** 226 * returns the number of the current page.<p> 227 * 228 * @return the number of the current page 229 */ 230 public int getCurrentPage() { 231 232 return m_currentPage; 233 } 234 235 /** 236 * Returns all items of the current page.<p> 237 * 238 * @return all items of the current page, a list of {@link CmsListItem} objects 239 */ 240 public List<CmsListItem> getCurrentPageItems() { 241 242 if (getSize() == 0) { 243 return Collections.emptyList(); 244 } 245 if (m_metadata.isSelfManaged()) { 246 return getContent(); 247 } 248 return Collections.unmodifiableList(getContent().subList(displayedFrom() - 1, displayedTo())); 249 } 250 251 /** 252 * Returns the current used sort order.<p> 253 * 254 * @return the current used sort order 255 */ 256 public CmsListOrderEnum getCurrentSortOrder() { 257 258 return m_currentSortOrder; 259 } 260 261 /** 262 * Returns the id.<p> 263 * 264 * @return the id 265 */ 266 public String getId() { 267 268 return m_id; 269 } 270 271 /** 272 * This method returns the item identified by the parameter id.<p> 273 * 274 * Only current visible item can be retrieved using this method.<p> 275 * 276 * @param id the id of the item to look for 277 * 278 * @return the requested item or <code>null</code> if not found 279 */ 280 public CmsListItem getItem(String id) { 281 282 Iterator<CmsListItem> it = getAllContent().iterator(); 283 while (it.hasNext()) { 284 CmsListItem item = it.next(); 285 if (item.getId().equals(id)) { 286 return item; 287 } 288 } 289 return null; 290 } 291 292 /** 293 * Returns the maximum number of items per page.<p> 294 * 295 * @return the maximum number of items per page 296 */ 297 public int getMaxItemsPerPage() { 298 299 return m_maxItemsPerPage; 300 } 301 302 /** 303 * Returns the metadata.<p> 304 * 305 * @return the metadata 306 */ 307 public CmsListMetadata getMetadata() { 308 309 return m_metadata; 310 } 311 312 /** 313 * Returns the name of the list.<p> 314 * 315 * @return the list's name 316 */ 317 public CmsMessageContainer getName() { 318 319 return m_name; 320 } 321 322 /** 323 * Returns the filtered number of pages.<p> 324 * 325 * Equals to <code>{@link #getTotalNumberOfPages()}</code> if no filter is set.<p> 326 * 327 * @return the filtered of pages 328 */ 329 public int getNumberOfPages() { 330 331 return (int)Math.ceil((double)getSize() / getMaxItemsPerPage()); 332 } 333 334 /** 335 * Returns the search filter.<p> 336 * 337 * @return the search filter 338 */ 339 public String getSearchFilter() { 340 341 return m_searchFilter; 342 } 343 344 /** 345 * Return the filtered number of items.<p> 346 * 347 * Equals to <code>{@link #getTotalSize()}</code> if no filter is set.<p> 348 * 349 * @return the filtered number of items 350 */ 351 public int getSize() { 352 353 if (m_metadata.isSelfManaged() && (m_size != 0)) { 354 return m_size; 355 } 356 return getContent().size(); 357 } 358 359 /** 360 * Returns the sorted column's name.<p> 361 * 362 * @return the sorted column's name 363 */ 364 public String getSortedColumn() { 365 366 return m_sortedColumn; 367 } 368 369 /** 370 * Returns a filled list state.<p> 371 * 372 * @return the state of the list 373 */ 374 public CmsListState getState() { 375 376 return new CmsListState(this); 377 } 378 379 /** 380 * Returns the total number of pages.<p> 381 * 382 * @return the total number of pages 383 */ 384 public int getTotalNumberOfPages() { 385 386 return (int)Math.ceil((double)getTotalSize() / getMaxItemsPerPage()); 387 } 388 389 /** 390 * Return the total number of items.<p> 391 * 392 * @return the total number of items 393 */ 394 public int getTotalSize() { 395 396 if (m_metadata.isSelfManaged() && (m_totalSize != 0)) { 397 return m_totalSize; 398 } 399 return getAllContent().size(); 400 } 401 402 /** 403 * Returns the workplace dialog object.<p> 404 * 405 * @return the workplace dialog object 406 */ 407 public A_CmsListDialog getWp() { 408 409 return m_wp; 410 } 411 412 /** 413 * Returns the isBoxed flag.<p> 414 * 415 * If this flag is set the list will be surrounded by a box.<p> 416 * 417 * @return the isBoxed flag 418 */ 419 public boolean isBoxed() { 420 421 return m_isBoxed; 422 } 423 424 /** 425 * Returns the printable flag.<p> 426 * 427 * @return the printable flag 428 */ 429 public boolean isPrintable() { 430 431 return m_printable; 432 } 433 434 /** 435 * Returns if the list title is shown.<p> 436 * 437 * @return true if the list title is shown, otherwise false 438 */ 439 public boolean isShowTitle() { 440 441 return m_showTitle; 442 } 443 444 /** 445 * Generates the csv output for the list.<p> 446 * 447 * @return csv output 448 */ 449 public String listCsv() { 450 451 StringBuffer csv = new StringBuffer(5120); 452 csv.append(m_metadata.csvHeader()); 453 if (getContent().isEmpty()) { 454 csv.append(m_metadata.csvEmptyList()); 455 } else { 456 Iterator<CmsListItem> itItems = getContent().iterator(); 457 while (itItems.hasNext()) { 458 CmsListItem item = itItems.next(); 459 csv.append(m_metadata.csvItem(item)); 460 } 461 } 462 return getWp().resolveMacros(csv.toString()); 463 } 464 465 /** 466 * Generates the html code for the list.<p> 467 * 468 * @return html code 469 */ 470 public synchronized String listHtml() { 471 472 // check if progress should be set in the thread 473 CmsProgressThread thread = null; 474 int progressOffset = 0; 475 if (Thread.currentThread() instanceof CmsProgressThread) { 476 thread = (CmsProgressThread)Thread.currentThread(); 477 progressOffset = thread.getProgress(); 478 } 479 480 // this block has to be executed before calling htmlBegin() 481 if (isPrintable()) { 482 m_visibleItems = new ArrayList<CmsListItem>(getContent()); 483 } else { 484 m_visibleItems = new ArrayList<CmsListItem>(getCurrentPageItems()); 485 } 486 487 StringBuffer html = new StringBuffer(5120); 488 html.append(htmlBegin()); 489 if (!isPrintable()) { 490 html.append(htmlTitle()); 491 html.append(htmlToolBar()); 492 } else { 493 html.append("<style type='text/css'>\n"); 494 html.append("td.listdetailitem, \n"); 495 html.append(".linkdisabled {\n"); 496 html.append("\tcolor: black;\n"); 497 html.append("}\n"); 498 html.append(".list th {\n"); 499 html.append("\tborder: 1px solid black;\n"); 500 html.append("}\n"); 501 html.append(".list {\n"); 502 html.append("\tborder: 1px solid black;\n"); 503 html.append("}\n"); 504 html.append("</style>"); 505 } 506 // avoiding the layout problem where, if some table cells contain a lot of text, 507 // the right side of the table is cut off and can not be reached using the scroll bar. 508 html.append("<!--[if IE 7]>"); 509 html.append("<style type='text/css'>"); 510 html.append("table.list * { word-wrap: break-word !important; white-space: normal !important; }"); 511 html.append("table.list { table-layout: fixed; }"); 512 html.append("</style>"); 513 html.append("<![endif]-->"); 514 515 html.append("<table width='100%' cellpadding='1' cellspacing='0' class='list'>\n"); 516 html.append(m_metadata.htmlHeader(this)); 517 if (m_visibleItems.isEmpty()) { 518 html.append(m_metadata.htmlEmptyTable()); 519 } else { 520 Iterator<CmsListItem> itItems = m_visibleItems.iterator(); 521 boolean odd = true; 522 int count = 0; 523 while (itItems.hasNext()) { 524 525 // set progress in thread 526 count++; 527 if (thread != null) { 528 529 if (thread.isInterrupted()) { 530 throw new CmsIllegalStateException( 531 org.opencms.workplace.commons.Messages.get().container( 532 org.opencms.workplace.commons.Messages.ERR_PROGRESS_INTERRUPTED_0)); 533 } 534 thread.setProgress(((count * (100 - progressOffset)) / m_visibleItems.size()) + progressOffset); 535 thread.setDescription( 536 org.opencms.workplace.commons.Messages.get().getBundle(thread.getLocale()).key( 537 org.opencms.workplace.commons.Messages.GUI_PROGRESS_PUBLISH_STEP4_2, 538 Integer.valueOf(count), 539 Integer.valueOf(m_visibleItems.size()))); 540 } 541 542 CmsListItem item = itItems.next(); 543 html.append(m_metadata.htmlItem(item, odd, isPrintable())); 544 odd = !odd; 545 } 546 } 547 548 html.append("</table>\n"); 549 if (!isPrintable()) { 550 html.append(htmlPagingBar()); 551 } 552 html.append(htmlEnd()); 553 return getWp().resolveMacros(html.toString()); 554 } 555 556 /** 557 * Generate the need js code for the list.<p> 558 * 559 * @return js code 560 */ 561 public String listJs() { 562 563 StringBuffer js = new StringBuffer(1024); 564 CmsMessages messages = Messages.get().getBundle(getWp().getLocale()); 565 js.append("<script src='"); 566 js.append(CmsWorkplace.getSkinUri()); 567 js.append("jquery/unpacked/jquery.js'></script>\n"); 568 js.append("<script src='"); 569 js.append(CmsWorkplace.getSkinUri()); 570 js.append("jquery/unpacked/jquery.hint.js'></script>\n"); 571 js.append("<script src='"); 572 js.append(CmsWorkplace.getSkinUri()); 573 js.append("admin/javascript/list.js'></script>\n"); 574 if (!m_metadata.getMultiActions().isEmpty()) { 575 js.append("<script >\n"); 576 js.append("\tvar "); 577 js.append(NO_SELECTION_HELP_VAR); 578 js.append(" = '"); 579 js.append(CmsStringUtil.escapeJavaScript(messages.key(Messages.GUI_LIST_ACTION_NO_SELECTION_0))); 580 js.append("';\n"); 581 Iterator<CmsListMultiAction> it = m_metadata.getMultiActions().iterator(); 582 while (it.hasNext()) { 583 CmsListMultiAction action = it.next(); 584 if (action instanceof CmsListRadioMultiAction) { 585 CmsListRadioMultiAction rAction = (CmsListRadioMultiAction)action; 586 js.append("\tvar "); 587 js.append(NO_SELECTION_MATCH_HELP_VAR); 588 js.append(rAction.getId()); 589 js.append(" = '"); 590 js.append( 591 CmsStringUtil.escapeJavaScript( 592 messages.key( 593 Messages.GUI_LIST_ACTION_NO_SELECTION_MATCH_1, 594 Integer.valueOf(rAction.getSelections())))); 595 js.append("';\n"); 596 } 597 } 598 js.append("</script>\n"); 599 } 600 return js.toString(); 601 } 602 603 /** 604 * Returns a new list item for this list.<p> 605 * 606 * @param id the id of the item has to be unique 607 * @return a new list item 608 */ 609 public CmsListItem newItem(String id) { 610 611 return new CmsListItem(getMetadata(), id); 612 } 613 614 /** 615 * Returns html code for printing the list.<p> 616 * 617 * @return html code 618 */ 619 public String printableHtml() { 620 621 m_printable = true; 622 String html = listHtml(); 623 m_printable = false; 624 return html; 625 } 626 627 /** 628 * Removes an item from the list.<p> 629 * 630 * Keeping care of all the state like sorted column, sorting order, displayed page and search filter.<p> 631 * 632 * Try to use it instead of <code>{@link A_CmsListDialog#refreshList()}</code>.<p> 633 * 634 * @param id the id of the item to remove 635 * 636 * @return the removed list item 637 */ 638 public CmsListItem removeItem(String id) { 639 640 CmsListItem item = getItem(id); 641 if (item == null) { 642 return null; 643 } 644 CmsListState state = null; 645 if ((m_filteredItems != null) || (m_visibleItems != null)) { 646 state = getState(); 647 } 648 m_originalItems.remove(item); 649 if (m_filteredItems != null) { 650 m_filteredItems.remove(item); 651 } 652 if (m_visibleItems != null) { 653 m_visibleItems.remove(item); 654 } 655 if (state != null) { 656 setState(state); 657 } 658 return item; 659 } 660 661 /** 662 * Sets the isBoxed flag.<p> 663 * 664 * If this flag is set, the list will be surrounded by a box.<p> 665 * 666 * @param isBoxed the isBoxed flag to set 667 */ 668 public void setBoxed(boolean isBoxed) { 669 670 m_isBoxed = isBoxed; 671 } 672 673 /** 674 * Sets the list item to display in the list.<p> 675 * 676 * @param listItems a collection of {@link CmsListItem} objects 677 */ 678 public void setContent(Collection<CmsListItem> listItems) { 679 680 if (m_metadata.isSelfManaged()) { 681 m_filteredItems = new ArrayList<CmsListItem>(listItems); 682 m_originalItems = null; 683 } else { 684 m_filteredItems = null; 685 m_originalItems = new ArrayList<CmsListItem>(listItems); 686 } 687 } 688 689 /** 690 * Sets the current page.<p> 691 * 692 * @param currentPage the current page to set 693 * 694 * @throws CmsIllegalArgumentException if the argument is invalid 695 */ 696 public void setCurrentPage(int currentPage) throws CmsIllegalArgumentException { 697 698 if (getSize() != 0) { 699 if ((currentPage < 1) || (currentPage > getNumberOfPages())) { 700 throw new CmsIllegalArgumentException( 701 Messages.get().container(Messages.ERR_LIST_INVALID_PAGE_1, Integer.valueOf(currentPage))); 702 } 703 } 704 m_currentPage = currentPage; 705 } 706 707 /** 708 * Sets the maximum number of items per page.<p> 709 * 710 * @param maxItemsPerPage the maximum number of items per page to set 711 */ 712 public void setMaxItemsPerPage(int maxItemsPerPage) { 713 714 m_maxItemsPerPage = maxItemsPerPage; 715 } 716 717 /** 718 * Sets the name of the list.<p> 719 * 720 * @param name the name of the list 721 */ 722 public void setName(CmsMessageContainer name) { 723 724 m_name = name; 725 } 726 727 /** 728 * Sets the search filter.<p> 729 * 730 * @param searchFilter the search filter to set 731 */ 732 public void setSearchFilter(String searchFilter) { 733 734 if (!m_metadata.isSearchable()) { 735 return; 736 } 737 if (searchFilter == null) { 738 searchFilter = ""; 739 } 740 m_searchFilter = searchFilter; 741 boolean showAll = CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_searchFilter); 742 getMetadata().getSearchAction().getShowAllAction().setVisible(showAll); 743 if (!m_metadata.isSelfManaged()) { 744 if (CmsStringUtil.isEmptyOrWhitespaceOnly(searchFilter)) { 745 746 // reset content if filter is empty 747 m_filteredItems = null; 748 } else { 749 m_filteredItems = getMetadata().getSearchAction().filter(getAllContent(), m_searchFilter); 750 } 751 } 752 String sCol = m_sortedColumn; 753 m_sortedColumn = ""; 754 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(sCol)) { 755 CmsListOrderEnum order = getCurrentSortOrder(); 756 setSortedColumn(sCol); 757 if (order == CmsListOrderEnum.ORDER_DESCENDING) { 758 setSortedColumn(sCol); 759 } 760 } 761 setCurrentPage(1); 762 } 763 764 /** 765 * Sets if the list title is shown.<p> 766 * 767 * @param showTitle true if the list title is shown, otherwise false 768 */ 769 public void setShowTitle(boolean showTitle) { 770 771 m_showTitle = showTitle; 772 } 773 774 /** 775 * Sets the current filtered size, only used if data self managed.<p> 776 * 777 * @param size the size to set 778 */ 779 public void setSize(int size) { 780 781 m_size = size; 782 } 783 784 /** 785 * Sets the sorted column.<p> 786 * 787 * @param sortedColumn the sorted column to set 788 * 789 * @throws CmsIllegalArgumentException if the <code>sortedColumn</code> argument is invalid 790 */ 791 public void setSortedColumn(String sortedColumn) throws CmsIllegalArgumentException { 792 793 // check if the parameter is valid 794 if ((getMetadata().getColumnDefinition(sortedColumn) == null) 795 || !getMetadata().getColumnDefinition(sortedColumn).isSorteable()) { 796 return; 797 } 798 // reset view 799 setCurrentPage(1); 800 // only reverse order if the column to sort is already sorted 801 if (sortedColumn.equals(m_sortedColumn)) { 802 if (m_currentSortOrder == CmsListOrderEnum.ORDER_ASCENDING) { 803 m_currentSortOrder = CmsListOrderEnum.ORDER_DESCENDING; 804 } else { 805 m_currentSortOrder = CmsListOrderEnum.ORDER_ASCENDING; 806 } 807 if (!m_metadata.isSelfManaged()) { 808 if (m_filteredItems == null) { 809 m_filteredItems = new ArrayList<CmsListItem>(getAllContent()); 810 } 811 Collections.reverse(m_filteredItems); 812 } 813 return; 814 } 815 // sort new column 816 m_sortedColumn = sortedColumn; 817 m_currentSortOrder = CmsListOrderEnum.ORDER_ASCENDING; 818 if (!m_metadata.isSelfManaged()) { 819 if (m_filteredItems == null) { 820 m_filteredItems = new ArrayList<CmsListItem>(getAllContent()); 821 } 822 I_CmsListItemComparator c = getMetadata().getColumnDefinition(sortedColumn).getListItemComparator(); 823 Collections.sort(m_filteredItems, c.getComparator(sortedColumn, getWp().getLocale())); 824 } 825 } 826 827 /** 828 * Sets the list state.<p> 829 * 830 * This may involve sorting, filtering and paging.<p> 831 * 832 * @param listState the state to be set 833 */ 834 public void setState(CmsListState listState) { 835 836 if (!m_metadata.isSelfManaged()) { 837 m_filteredItems = null; 838 } 839 synchronized (this) { 840 if (m_visibleItems != null) { 841 m_visibleItems.clear(); 842 } 843 } 844 setSearchFilter(listState.getFilter()); 845 setSortedColumn(listState.getColumn()); 846 if (listState.getOrder() == CmsListOrderEnum.ORDER_DESCENDING) { 847 setSortedColumn(listState.getColumn()); 848 } 849 if (listState.getPage() > 0) { 850 if (listState.getPage() <= getNumberOfPages()) { 851 setCurrentPage(listState.getPage()); 852 } else { 853 setCurrentPage(1); 854 } 855 } 856 } 857 858 /** 859 * Sets the total Size, only used if data self managed.<p> 860 * 861 * @param totalSize the total Size to set 862 */ 863 public void setTotalSize(int totalSize) { 864 865 m_totalSize = totalSize; 866 } 867 868 /** 869 * Sets the workplace dialog object.<p> 870 * 871 * @param wp the workplace dialog object to set 872 */ 873 public void setWp(A_CmsListDialog wp) { 874 875 m_wp = wp; 876 m_metadata.setWp(wp); 877 } 878 879 /** 880 * Returns the number (from 1) of the first displayed item.<p> 881 * 882 * @return the number (from 1) of the first displayed item, or zero if the list is empty 883 */ 884 protected int displayedFrom() { 885 886 if (getSize() != 0) { 887 if (isPrintable()) { 888 return 1; 889 } else { 890 return ((getCurrentPage() - 1) * getMaxItemsPerPage()) + 1; 891 } 892 } 893 return 0; 894 } 895 896 /** 897 * Returns the number (from 1) of the last displayed item.<p> 898 * 899 * @return the number (from 1) of the last displayed item, or zero if the list is empty 900 */ 901 protected int displayedTo() { 902 903 if (getSize() != 0) { 904 if (!isPrintable()) { 905 if ((getCurrentPage() * getMaxItemsPerPage()) < getSize()) { 906 return getCurrentPage() * getMaxItemsPerPage(); 907 } 908 } 909 } 910 return getSize(); 911 } 912 913 /** 914 * Generates the initial html code.<p> 915 * 916 * @return html code 917 */ 918 protected String htmlBegin() { 919 920 StringBuffer html = new StringBuffer(512); 921 // help & confirmation text for actions if needed 922 if (!isPrintable() && (m_visibleItems != null) && !m_visibleItems.isEmpty()) { 923 Iterator<CmsListColumnDefinition> cols = getMetadata().getColumnDefinitions().iterator(); 924 while (cols.hasNext()) { 925 CmsListColumnDefinition col = cols.next(); 926 Iterator<I_CmsListDirectAction> actions = col.getDirectActions().iterator(); 927 while (actions.hasNext()) { 928 I_CmsListDirectAction action = actions.next(); 929 action.setItem(m_visibleItems.get(0)); 930 html.append(action.helpTextHtml()); 931 html.append(action.confirmationTextHtml()); 932 } 933 Iterator<CmsListDefaultAction> defActions = col.getDefaultActions().iterator(); 934 while (defActions.hasNext()) { 935 I_CmsListDirectAction action = defActions.next(); 936 action.setItem(m_visibleItems.get(0)); 937 html.append(action.helpTextHtml()); 938 html.append(action.confirmationTextHtml()); 939 } 940 } 941 } 942 // start list code 943 html.append("<div class='listArea'>\n"); 944 if (isBoxed()) { 945 html.append(getWp().dialogBlock(CmsWorkplace.HTML_START, m_name.key(getWp().getLocale()), false)); 946 } 947 html.append("\t\t<table width='100%' cellspacing='0' cellpadding='0' border='0'>\n"); 948 html.append("\t\t\t<tr><td>\n"); 949 return html.toString(); 950 } 951 952 /** 953 * Generates the need html code for ending a list.<p> 954 * 955 * @return html code 956 */ 957 protected String htmlEnd() { 958 959 StringBuffer html = new StringBuffer(512); 960 html.append("\t\t\t</td></tr>\n"); 961 html.append("\t\t</table>\n"); 962 if (isBoxed()) { 963 html.append(getWp().dialogBlock(CmsWorkplace.HTML_END, m_name.key(getWp().getLocale()), false)); 964 } 965 html.append("</div>\n"); 966 return html.toString(); 967 } 968 969 /** 970 * Generates the needed html code for the paging bar.<p> 971 * 972 * @return html code 973 */ 974 protected String htmlPagingBar() { 975 976 if (getNumberOfPages() < 2) { 977 return ""; 978 } 979 StringBuffer html = new StringBuffer(1024); 980 CmsMessages messages = Messages.get().getBundle(getWp().getLocale()); 981 html.append("<table width='100%' cellspacing='0' style='margin-top: 5px;'>\n"); 982 html.append("\t<tr>\n"); 983 html.append("\t\t<td class='main'>\n"); 984 // prev button 985 String id = "listPrev"; 986 String name = messages.key(Messages.GUI_LIST_PAGING_PREVIOUS_NAME_0); 987 String iconPath = ICON_LEFT; 988 boolean enabled = getCurrentPage() > 1; 989 String helpText = messages.key(Messages.GUI_LIST_PAGING_PREVIOUS_HELP_0); 990 if (!enabled) { 991 helpText = messages.key(Messages.GUI_LIST_PAGING_PREVIOUS_HELPDIS_0); 992 } 993 String onClic = "listSetPage('" + getId() + "', " + (getCurrentPage() - 1) + ")"; 994 html.append(A_CmsHtmlIconButton.defaultButtonHtml( 995 CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT, 996 id, 997 name, 998 helpText, 999 enabled, 1000 iconPath, 1001 null, 1002 onClic)); 1003 html.append("\n"); 1004 // next button 1005 id = "listNext"; 1006 name = messages.key(Messages.GUI_LIST_PAGING_NEXT_NAME_0); 1007 iconPath = ICON_RIGHT; 1008 enabled = getCurrentPage() < getNumberOfPages(); 1009 helpText = messages.key(Messages.GUI_LIST_PAGING_NEXT_HELP_0); 1010 if (!enabled) { 1011 helpText = messages.key(Messages.GUI_LIST_PAGING_NEXT_HELPDIS_0); 1012 } 1013 onClic = "listSetPage('" + getId() + "', " + (getCurrentPage() + 1) + ")"; 1014 html.append(A_CmsHtmlIconButton.defaultButtonHtml( 1015 CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT, 1016 id, 1017 name, 1018 helpText, 1019 enabled, 1020 iconPath, 1021 null, 1022 onClic)); 1023 html.append("\n"); 1024 // page selection list 1025 html.append("\t\t\t "); 1026 html.append("\t\t\t<select name='listPageSet' id='id-page_set' onChange =\"listSetPage('"); 1027 html.append(getId()); 1028 html.append("', this.value);\" style='vertical-align: bottom;'>\n"); 1029 html.append( 1030 htmlPageSelector( 1031 getNumberOfPages(), 1032 getMaxItemsPerPage(), 1033 getSize(), 1034 getCurrentPage(), 1035 getWp().getLocale())); 1036 html.append("\t\t\t</select>\n"); 1037 html.append("\t\t\t "); 1038 boolean isNotSearching = true; 1039 if (getMetadata().isSearchable()) { 1040 isNotSearching = CmsStringUtil.isEmptyOrWhitespaceOnly(m_searchFilter); 1041 } 1042 if (isNotSearching) { 1043 html.append( 1044 messages.key( 1045 Messages.GUI_LIST_PAGING_TEXT_2, 1046 new Object[] {m_name.key(getWp().getLocale()), Integer.valueOf(getTotalSize())})); 1047 } else { 1048 html.append(messages.key( 1049 Messages.GUI_LIST_PAGING_FILTER_TEXT_3, 1050 new Object[] {m_name.key(getWp().getLocale()), Integer.valueOf(getSize()), Integer.valueOf(getTotalSize())})); 1051 } 1052 html.append("\t\t</td>\n"); 1053 html.append("\t</tr>\n"); 1054 html.append("</table>\n"); 1055 return html.toString(); 1056 } 1057 1058 /** 1059 * Returns the html for the title of the list.<p> 1060 * 1061 * @return html code 1062 */ 1063 protected String htmlTitle() { 1064 1065 boolean showTitle = isShowTitle(); 1066 Iterator<I_CmsListAction> itIndepActions = getMetadata().getIndependentActions().iterator(); 1067 while (!showTitle && itIndepActions.hasNext()) { 1068 I_CmsListAction indepAction = itIndepActions.next(); 1069 showTitle = showTitle || indepAction.isVisible(); 1070 } 1071 Iterator<CmsListItemDetails> itItemDetails = getMetadata().getItemDetailDefinitions().iterator(); 1072 while (!showTitle && itItemDetails.hasNext()) { 1073 CmsListItemDetails itemDetail = itItemDetails.next(); 1074 showTitle = showTitle || itemDetail.getAction().isVisible(); 1075 } 1076 if (!showTitle) { 1077 // prevent empty table if there is nothing to display 1078 return ""; 1079 } 1080 StringBuffer html = new StringBuffer(512); 1081 CmsMessages messages = Messages.get().getBundle(getWp().getLocale()); 1082 html.append("<table width='100%' cellspacing='0'>"); 1083 html.append("\t<tr>\n"); 1084 if (isShowTitle()) { 1085 html.append("\t\t<td align='left'>\n"); 1086 html.append("\t\t\t"); 1087 boolean isNotSearching = true; 1088 if (getMetadata().isSearchable()) { 1089 isNotSearching = CmsStringUtil.isEmptyOrWhitespaceOnly(m_searchFilter); 1090 } 1091 if (getTotalNumberOfPages() > 1) { 1092 if (isNotSearching) { 1093 html.append(messages.key( 1094 Messages.GUI_LIST_TITLE_TEXT_4, 1095 new Object[] { 1096 m_name.key(getWp().getLocale()), 1097 Integer.valueOf(displayedFrom()), 1098 Integer.valueOf(displayedTo()), 1099 Integer.valueOf(getTotalSize())})); 1100 } else { 1101 html.append(messages.key( 1102 Messages.GUI_LIST_TITLE_FILTERED_TEXT_5, 1103 new Object[] { 1104 m_name.key(getWp().getLocale()), 1105 Integer.valueOf(displayedFrom()), 1106 Integer.valueOf(displayedTo()), 1107 Integer.valueOf(getSize()), 1108 Integer.valueOf(getTotalSize())})); 1109 } 1110 } else { 1111 if (isNotSearching) { 1112 html.append(messages.key( 1113 Messages.GUI_LIST_SINGLE_TITLE_TEXT_2, 1114 new Object[] {m_name.key(getWp().getLocale()), Integer.valueOf(getTotalSize())})); 1115 } else { 1116 html.append(messages.key( 1117 Messages.GUI_LIST_SINGLE_TITLE_FILTERED_TEXT_3, 1118 new Object[] { 1119 m_name.key(getWp().getLocale()), 1120 Integer.valueOf(getSize()), 1121 Integer.valueOf(getTotalSize())})); 1122 } 1123 } 1124 html.append("\n"); 1125 html.append("\t\t</td>\n\t\t"); 1126 } 1127 html.append(getMetadata().htmlActionBar()); 1128 html.append("\n\t</tr>\n"); 1129 html.append("</table>\n"); 1130 return html.toString(); 1131 } 1132 1133 /** 1134 * Returns the html code for the toolbar (search bar + multiactions bar).<p> 1135 * 1136 * @return html code 1137 */ 1138 protected String htmlToolBar() { 1139 1140 boolean showToolBar = getMetadata().isSearchable(); 1141 Iterator<CmsListMultiAction> itMultiActions = getMetadata().getMultiActions().iterator(); 1142 while (!showToolBar && itMultiActions.hasNext()) { 1143 CmsListMultiAction multiAction = itMultiActions.next(); 1144 showToolBar = showToolBar || multiAction.isVisible(); 1145 } 1146 if (!showToolBar) { 1147 // prevent empty table if there is nothing to display 1148 return ""; 1149 } 1150 StringBuffer html = new StringBuffer(512); 1151 html.append("<table width='100%' cellspacing='0' style='margin-bottom: 5px'>\n"); 1152 html.append("\t<tr>\n"); 1153 html.append(m_metadata.htmlSearchBar()); 1154 html.append(m_metadata.htmlMultiActionBar()); 1155 html.append("\t</tr>\n"); 1156 html.append("</table>\n"); 1157 return html.toString(); 1158 } 1159 1160 /** 1161 * Sets the metadata for this list.<p> 1162 * 1163 * Should only be used by the <code>{@link A_CmsListDialog}</code> class 1164 * for temporally removing the metadata object while the list is saved in the 1165 * <code>{@link org.opencms.workplace.CmsWorkplaceSettings}</code>.<p> 1166 * 1167 * @param metadata the list metadata 1168 */ 1169 protected void setMetadata(CmsListMetadata metadata) { 1170 1171 m_metadata = metadata; 1172 } 1173}