001/* 002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Anahide Tchertchian 016 */ 017package org.nuxeo.ecm.platform.contentview.jsf; 018 019import static org.apache.commons.lang.StringUtils.isBlank; 020 021import java.util.ArrayList; 022import java.util.List; 023import java.util.Map; 024 025import javax.faces.context.ExternalContext; 026import javax.faces.context.FacesContext; 027 028import org.apache.commons.lang.StringUtils; 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.jboss.seam.core.Events; 032import org.nuxeo.ecm.core.api.DocumentModel; 033import org.nuxeo.ecm.core.api.DocumentModelFactory; 034import org.nuxeo.ecm.core.api.PropertyException; 035import org.nuxeo.ecm.core.api.SortInfo; 036import org.nuxeo.ecm.core.api.model.impl.MapProperty; 037import org.nuxeo.ecm.platform.query.api.Aggregate; 038import org.nuxeo.ecm.platform.query.api.PageProvider; 039import org.nuxeo.ecm.platform.query.api.PageProviderChangedListener; 040import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils; 041import org.nuxeo.runtime.api.Framework; 042 043import com.google.common.base.Function; 044 045/** 046 * Default implementation for the content view object. 047 * <p> 048 * Provides simple getters for attributes defined in the XMap descriptor, except cache key which is computed from 049 * currrent {@link FacesContext} instance if cache key is an EL expression. 050 * <p> 051 * The page provider is initialized calling {@link ContentViewService#getPageProvider}. 052 * 053 * @author Anahide Tchertchian 054 * @since 5.4 055 */ 056public class ContentViewImpl implements ContentView, PageProviderChangedListener { 057 058 private static final long serialVersionUID = 1L; 059 060 private static final Log log = LogFactory.getLog(ContentViewImpl.class); 061 062 protected String name; 063 064 protected PageProvider<?> pageProvider; 065 066 protected String title; 067 068 protected boolean translateTitle; 069 070 protected String emptySentence; 071 072 protected boolean translateEmptySentence; 073 074 protected String iconPath; 075 076 protected boolean showTitle; 077 078 protected String selectionList; 079 080 protected String pagination; 081 082 protected List<String> actionCategories; 083 084 protected ContentViewLayout searchLayout; 085 086 protected List<ContentViewLayout> resultLayouts; 087 088 protected List<String> flags; 089 090 protected boolean currentResultLayoutSet = false; 091 092 protected ContentViewLayout currentResultLayout; 093 094 protected List<String> currentResultLayoutColumns; 095 096 protected String cacheKey; 097 098 protected Integer cacheSize; 099 100 protected List<String> refreshEventNames; 101 102 protected List<String> resetEventNames; 103 104 protected boolean useGlobalPageSize; 105 106 protected boolean showPageSizeSelector; 107 108 protected boolean showRefreshCommand; 109 110 protected boolean showFilterForm; 111 112 protected Long currentPageSize; 113 114 protected String[] queryParameters; 115 116 protected DocumentModel searchDocumentModel; 117 118 protected String searchDocumentModelBinding; 119 120 protected String searchDocumentModelType; 121 122 protected String resultColumnsBinding; 123 124 protected String resultLayoutBinding; 125 126 protected String pageSizeBinding; 127 128 protected String sortInfosBinding; 129 130 protected boolean waitForExecution = false; 131 132 protected String waitForExecutionSentence; 133 134 protected boolean executed = false; 135 136 public ContentViewImpl(String name, String title, boolean translateTitle, String iconPath, String selectionList, 137 String pagination, List<String> actionCategories, ContentViewLayout searchLayout, 138 List<ContentViewLayout> resultLayouts, List<String> flags, String cacheKey, Integer cacheSize, 139 List<String> refreshEventNames, List<String> resetEventNames, boolean useGlobalPageSize, 140 String[] queryParameters, String searchDocumentModelBinding, String searchDocumentModelType, 141 String resultColumnsBinding, String resultLayoutBinding, String sortInfosBinding, String pageSizeBinding, 142 boolean showTitle, boolean showPageSizeSelector, boolean showRefreshCommand, boolean showFilterForm, 143 String emptySentence, boolean translateEmptySentence) { 144 this.name = name; 145 this.title = title; 146 this.translateTitle = translateTitle; 147 this.iconPath = iconPath; 148 this.selectionList = selectionList; 149 this.pagination = pagination; 150 this.actionCategories = actionCategories; 151 this.searchLayout = searchLayout; 152 this.resultLayouts = resultLayouts; 153 this.flags = flags; 154 this.cacheKey = cacheKey; 155 this.cacheSize = cacheSize; 156 if (cacheSize != null && cacheSize.intValue() <= 0) { 157 // force a static cache key 158 this.cacheKey = "static_key_no_cache"; 159 } 160 this.refreshEventNames = refreshEventNames; 161 this.resetEventNames = resetEventNames; 162 this.useGlobalPageSize = useGlobalPageSize; 163 this.queryParameters = queryParameters; 164 this.searchDocumentModelBinding = searchDocumentModelBinding; 165 this.searchDocumentModelType = searchDocumentModelType; 166 this.resultColumnsBinding = resultColumnsBinding; 167 this.resultLayoutBinding = resultLayoutBinding; 168 this.pageSizeBinding = pageSizeBinding; 169 this.sortInfosBinding = sortInfosBinding; 170 this.showTitle = showTitle; 171 this.showPageSizeSelector = showPageSizeSelector; 172 this.showRefreshCommand = showRefreshCommand; 173 this.showFilterForm = showFilterForm; 174 this.emptySentence = emptySentence; 175 this.translateEmptySentence = translateEmptySentence; 176 } 177 178 @Override 179 public String getName() { 180 return name; 181 } 182 183 @Override 184 public String getTitle() { 185 return title; 186 } 187 188 @Override 189 public boolean getTranslateTitle() { 190 return translateTitle; 191 } 192 193 @Override 194 public String getIconPath() { 195 return iconPath; 196 } 197 198 @Override 199 public String getSelectionListName() { 200 return selectionList; 201 } 202 203 @Override 204 public String getPagination() { 205 return pagination; 206 } 207 208 @Override 209 public List<String> getActionsCategories() { 210 return actionCategories; 211 } 212 213 @Override 214 public ContentViewLayout getSearchLayout() { 215 return searchLayout; 216 } 217 218 @Override 219 public List<ContentViewLayout> getResultLayouts() { 220 return resultLayouts; 221 } 222 223 @Override 224 public ContentViewLayout getCurrentResultLayout() { 225 // resolve binding if it is set 226 if (!currentResultLayoutSet && !StringUtils.isBlank(resultLayoutBinding)) { 227 Object res = resolveWithSearchDocument(new Function<FacesContext, Object>() { 228 @Override 229 public Object apply(FacesContext ctx) { 230 return ComponentTagUtils.resolveElExpression(ctx, resultLayoutBinding); 231 } 232 }); 233 if (res != null && res instanceof String) { 234 setCurrentResultLayout((String) res); 235 currentResultLayoutSet = true; 236 } 237 } 238 if (currentResultLayout == null && resultLayouts != null && !resultLayouts.isEmpty()) { 239 // resolve first current result layout 240 return resultLayouts.get(0); 241 } 242 return currentResultLayout; 243 } 244 245 @Override 246 public void setCurrentResultLayout(final ContentViewLayout layout) { 247 setCurrentResultLayout(layout, true); 248 } 249 250 public void setCurrentResultLayout(final ContentViewLayout layout, boolean resetLayoutColumn) { 251 if (!isBlank(resultLayoutBinding) && ComponentTagUtils.isStrictValueReference(resultLayoutBinding)) { 252 resolveWithSearchDocument(new Function<FacesContext, Object>() { 253 @Override 254 public Object apply(FacesContext ctx) { 255 ComponentTagUtils.applyValueExpression(ctx, resultLayoutBinding, 256 layout == null ? null : layout.getName()); 257 return null; 258 } 259 }); 260 } 261 // still set current result layout value 262 currentResultLayoutSet = true; 263 currentResultLayout = layout; 264 265 if (resetLayoutColumn) { 266 // reset corresponding columns 267 setCurrentResultLayoutColumns(null); 268 } 269 } 270 271 protected Object resolveWithSearchDocument(Function<FacesContext, Object> func) { 272 FacesContext ctx = FacesContext.getCurrentInstance(); 273 if (getSearchDocumentModel() == null) { 274 return func.apply(ctx); 275 } else { 276 Object previousSearchDocValue = addSearchDocumentToELContext(ctx); 277 try { 278 return func.apply(ctx); 279 } finally { 280 removeSearchDocumentFromELContext(ctx, previousSearchDocValue); 281 } 282 } 283 } 284 285 @Override 286 public void setCurrentResultLayout(String resultLayoutName) { 287 if (resultLayoutName != null) { 288 for (ContentViewLayout layout : resultLayouts) { 289 if (resultLayoutName.equals(layout.getName())) { 290 setCurrentResultLayout(layout, false); 291 } 292 } 293 } 294 } 295 296 @Override 297 public boolean hasResultLayoutBinding() { 298 return !isBlank(resultLayoutBinding); 299 } 300 301 /** 302 * Returns cached page provider if it exists or build a new one if parameters have changed. 303 * <p> 304 * The search document, current page and page size are set on the page provider anyway. Sort infos are not set again 305 * if page provider was not built again (e.g if parameters did not change) to avoid erasing sort infos already held 306 * by it. 307 */ 308 @Override 309 public PageProvider<?> getPageProvider(DocumentModel searchDocument, List<SortInfo> sortInfos, Long pageSize, 310 Long currentPage, Object... params) { 311 // do not return any page provider if filter has not been done yet 312 if (isWaitForExecution() && !isExecuted()) { 313 return null; 314 } 315 316 // resolve search doc so that it can be used in EL expressions defined 317 // in XML configuration 318 boolean setSearchDoc = false; 319 DocumentModel finalSearchDocument = null; 320 if (searchDocument != null) { 321 setSearchDoc = true; 322 finalSearchDocument = searchDocument; 323 } else if (searchDocumentModel == null) { 324 setSearchDoc = true; 325 if (pageProvider != null) { 326 // try to retrieve it on current page provider 327 finalSearchDocument = pageProvider.getSearchDocumentModel(); 328 } 329 if (finalSearchDocument == null) { 330 // initialize it and set it => do not need to set it again 331 finalSearchDocument = getSearchDocumentModel(); 332 setSearchDoc = false; 333 } 334 } else { 335 finalSearchDocument = searchDocumentModel; 336 } 337 if (setSearchDoc) { 338 // set it on content view so that it can be used when resolving EL 339 // expressions 340 setSearchDocumentModel(finalSearchDocument); 341 } 342 343 // fallback on local parameters if defined in the XML configuration 344 if (params == null) { 345 params = getQueryParameters(); 346 } 347 if (sortInfos == null) { 348 sortInfos = resolveSortInfos(); 349 } 350 // allow to pass negative integers instead of null: EL transforms 351 // numbers into value 0 for numbers 352 if (pageSize != null && pageSize.longValue() < 0) { 353 pageSize = null; 354 } 355 if (currentPage != null && currentPage.longValue() < 0) { 356 currentPage = null; 357 } 358 if (pageSize == null) { 359 if (currentPageSize != null && currentPageSize.longValue() >= 0) { 360 pageSize = currentPageSize; 361 } 362 if (pageSize == null) { 363 pageSize = resolvePageSize(); 364 } 365 } 366 367 // parameters changed => reset provider. 368 // do not force setting of sort infos as they can be set directly on 369 // the page provider and this method will be called after so they could 370 // be lost. 371 if (pageProvider == null || pageProvider.hasChangedParameters(params)) { 372 // make the service build the provider 373 ContentViewService service = Framework.getLocalService(ContentViewService.class); 374 pageProvider = service.getPageProvider(getName(), sortInfos, pageSize, currentPage, finalSearchDocument, 375 params); 376 } else { 377 if (pageSize != null) { 378 pageProvider.setPageSize(pageSize.longValue()); 379 } 380 if (currentPage != null) { 381 pageProvider.setCurrentPage(currentPage.longValue()); 382 } 383 } 384 385 // Register listener to be notified when the page has changed on the 386 // page provider 387 pageProvider.setPageProviderChangedListener(this); 388 return pageProvider; 389 } 390 391 @Override 392 public PageProvider<?> getPageProviderWithParams(Object... params) { 393 return getPageProvider(null, null, null, null, params); 394 } 395 396 @Override 397 public PageProvider<?> getPageProvider() { 398 return getPageProviderWithParams((Object[]) null); 399 } 400 401 @Override 402 public PageProvider<?> getCurrentPageProvider() { 403 return pageProvider; 404 } 405 406 @Override 407 public void resetPageProvider() { 408 pageProvider = null; 409 } 410 411 @Override 412 public void refreshPageProvider() { 413 if (pageProvider != null) { 414 pageProvider.refresh(); 415 } 416 setExecuted(true); 417 } 418 419 @Override 420 public void refreshAndRewindPageProvider() { 421 if (pageProvider != null) { 422 pageProvider.refresh(); 423 pageProvider.firstPage(); 424 } 425 setExecuted(true); 426 } 427 428 @Override 429 public String getCacheKey() { 430 FacesContext context = FacesContext.getCurrentInstance(); 431 Object value = ComponentTagUtils.resolveElExpression(context, cacheKey); 432 if (value != null && !(value instanceof String)) { 433 log.error(String.format("Error processing expression '%s', " + "result is not a String: %s", cacheKey, 434 value)); 435 } 436 return (String) value; 437 } 438 439 @Override 440 public Integer getCacheSize() { 441 return cacheSize; 442 } 443 444 @Override 445 public Object[] getQueryParameters() { 446 if (queryParameters == null) { 447 return null; 448 } 449 FacesContext context = FacesContext.getCurrentInstance(); 450 Object previousSearchDocValue = addSearchDocumentToELContext(context); 451 try { 452 Object[] res = new Object[queryParameters.length]; 453 for (int i = 0; i < queryParameters.length; i++) { 454 res[i] = ComponentTagUtils.resolveElExpression(context, queryParameters[i]); 455 } 456 return res; 457 } finally { 458 removeSearchDocumentFromELContext(context, previousSearchDocValue); 459 } 460 } 461 462 @Override 463 public List<String> getRefreshEventNames() { 464 return refreshEventNames; 465 } 466 467 @Override 468 public List<String> getResetEventNames() { 469 return resetEventNames; 470 } 471 472 @Override 473 public boolean getUseGlobalPageSize() { 474 return useGlobalPageSize; 475 } 476 477 @Override 478 public Long getCurrentPageSize() { 479 // take actual value on page provider first in case it's reached its 480 // max page size 481 if (pageProvider != null) { 482 long pageSize = pageProvider.getPageSize(); 483 long maxPageSize = pageProvider.getMaxPageSize(); 484 if (pageSize > 0 && maxPageSize > 0 && maxPageSize < pageSize) { 485 return Long.valueOf(maxPageSize); 486 } 487 return Long.valueOf(pageSize); 488 } 489 if (currentPageSize != null && currentPageSize.longValue() >= 0) { 490 return currentPageSize; 491 } 492 return null; 493 } 494 495 @Override 496 public void setCurrentPageSize(Long pageSize) { 497 currentPageSize = pageSize; 498 raiseEvent(CONTENT_VIEW_PAGE_SIZE_CHANGED_EVENT); 499 } 500 501 @Override 502 public DocumentModel getSearchDocumentModel() { 503 if (searchDocumentModel == null) { 504 if (searchDocumentModelBinding != null) { 505 // initialize from binding 506 FacesContext context = FacesContext.getCurrentInstance(); 507 Object value = ComponentTagUtils.resolveElExpression(context, searchDocumentModelBinding); 508 if (value != null && !(value instanceof DocumentModel)) { 509 log.error(String.format("Error processing expression '%s', " + "result is not a DocumentModel: %s", 510 searchDocumentModelBinding, value)); 511 } else { 512 setSearchDocumentModel((DocumentModel) value); 513 } 514 } 515 if (searchDocumentModel == null) { 516 // generate a bare document model of given type 517 String docType = getSearchDocumentModelType(); 518 if (docType != null) { 519 DocumentModel bareDoc = DocumentModelFactory.createDocumentModel(docType); 520 setSearchDocumentModel(bareDoc); 521 } 522 } 523 } 524 return searchDocumentModel; 525 } 526 527 @Override 528 public void setSearchDocumentModel(DocumentModel searchDocumentModel) { 529 this.searchDocumentModel = searchDocumentModel; 530 if (pageProvider != null) { 531 pageProvider.setSearchDocumentModel(searchDocumentModel); 532 } 533 } 534 535 @Override 536 public void resetSearchDocumentModel() { 537 searchDocumentModel = null; 538 if (pageProvider != null) { 539 pageProvider.setSearchDocumentModel(null); 540 } 541 } 542 543 @Override 544 public String getSearchDocumentModelType() { 545 return searchDocumentModelType; 546 } 547 548 @Override 549 public List<String> getFlags() { 550 return flags; 551 } 552 553 @Override 554 public List<String> getResultLayoutColumns() { 555 return getCurrentResultLayoutColumns(); 556 } 557 558 @Override 559 @SuppressWarnings({ "unchecked", "rawtypes" }) 560 public List<String> getCurrentResultLayoutColumns() { 561 // always resolve binding if it is set 562 if (!StringUtils.isBlank(resultColumnsBinding)) { 563 Object res = resolveWithSearchDocument(new Function<FacesContext, Object>() { 564 @Override 565 public Object apply(FacesContext ctx) { 566 Object value = ComponentTagUtils.resolveElExpression(ctx, resultColumnsBinding); 567 if (value != null && !(value instanceof List)) { 568 log.error(String.format("Error processing expression '%s', " + "result is not a List: %s", 569 resultColumnsBinding, value)); 570 } 571 return value; 572 } 573 }); 574 if (res != null && res instanceof List) { 575 return ((List) res).isEmpty() ? null : (List) res; 576 } 577 } 578 return currentResultLayoutColumns; 579 } 580 581 @Override 582 public void setCurrentResultLayoutColumns(final List<String> resultColumns) { 583 if (isBlank(resultColumnsBinding) || !ComponentTagUtils.isStrictValueReference(resultColumnsBinding)) { 584 // set local values 585 currentResultLayoutColumns = resultColumns; 586 } else { 587 resolveWithSearchDocument(new Function<FacesContext, Object>() { 588 @Override 589 public Object apply(FacesContext ctx) { 590 ComponentTagUtils.applyValueExpression(ctx, resultColumnsBinding, resultColumns); 591 return null; 592 } 593 }); 594 } 595 } 596 597 @Override 598 public boolean hasResultLayoutColumnsBinding() { 599 return !isBlank(resultColumnsBinding); 600 } 601 602 @SuppressWarnings({ "unchecked", "rawtypes" }) 603 protected List<SortInfo> resolveSortInfos() { 604 if (sortInfosBinding == null) { 605 return null; 606 } 607 FacesContext context = FacesContext.getCurrentInstance(); 608 Object previousSearchDocValue = addSearchDocumentToELContext(context); 609 try { 610 Object value = ComponentTagUtils.resolveElExpression(context, sortInfosBinding); 611 if (value != null && !(value instanceof List)) { 612 log.error(String.format("Error processing expression '%s', " + "result is not a List: %s", 613 sortInfosBinding, value)); 614 } 615 if (value == null) { 616 return null; 617 } 618 List<SortInfo> res = new ArrayList<SortInfo>(); 619 List listValue = (List) value; 620 for (Object listItem : listValue) { 621 if (listItem instanceof SortInfo) { 622 res.add((SortInfo) listItem); 623 } else if (listItem instanceof Map) { 624 // XXX: MapProperty does not implement containsKey, so 625 // resolve 626 // value instead 627 if (listItem instanceof MapProperty) { 628 try { 629 listItem = ((MapProperty) listItem).getValue(); 630 } catch (ClassCastException | PropertyException e) { 631 log.error("Cannot resolve sort info item: " + listItem, e); 632 } 633 } 634 Map map = (Map) listItem; 635 SortInfo sortInfo = SortInfo.asSortInfo(map); 636 if (sortInfo != null) { 637 res.add(sortInfo); 638 } else { 639 log.error("Cannot resolve sort info item: " + listItem); 640 } 641 } else { 642 log.error("Cannot resolve sort info item: " + listItem); 643 } 644 } 645 if (res.isEmpty()) { 646 return null; 647 } 648 return res; 649 } finally { 650 removeSearchDocumentFromELContext(context, previousSearchDocValue); 651 } 652 } 653 654 protected Long resolvePageSize() { 655 if (pageSizeBinding == null) { 656 return null; 657 } 658 FacesContext context = FacesContext.getCurrentInstance(); 659 Object previousSearchDocValue = addSearchDocumentToELContext(context); 660 try { 661 Object value = ComponentTagUtils.resolveElExpression(context, pageSizeBinding); 662 if (value == null) { 663 return null; 664 } 665 if (value instanceof String) { 666 try { 667 return Long.valueOf((String) value); 668 } catch (NumberFormatException e) { 669 log.error(String.format("Error processing expression '%s', " + "result is not a Long: %s", 670 pageSizeBinding, value)); 671 } 672 } else if (value instanceof Number) { 673 return Long.valueOf(((Number) value).longValue()); 674 } 675 return null; 676 } finally { 677 removeSearchDocumentFromELContext(context, previousSearchDocValue); 678 } 679 } 680 681 protected Object addSearchDocumentToELContext(FacesContext facesContext) { 682 if (facesContext == null) { 683 log.error(String.format("Faces context is null: cannot expose variable '%s' " + "for content view '%s'", 684 SEARCH_DOCUMENT_EL_VARIABLE, getName())); 685 return null; 686 } 687 ExternalContext econtext = facesContext.getExternalContext(); 688 if (econtext != null) { 689 Map<String, Object> requestMap = econtext.getRequestMap(); 690 Object previousValue = requestMap.get(SEARCH_DOCUMENT_EL_VARIABLE); 691 requestMap.put(SEARCH_DOCUMENT_EL_VARIABLE, searchDocumentModel); 692 return previousValue; 693 } else { 694 log.error(String.format("External context is null: cannot expose variable '%s' " + "for content view '%s'", 695 SEARCH_DOCUMENT_EL_VARIABLE, getName())); 696 return null; 697 } 698 } 699 700 protected void removeSearchDocumentFromELContext(FacesContext facesContext, Object previousValue) { 701 if (facesContext == null) { 702 // ignore 703 return; 704 } 705 ExternalContext econtext = facesContext.getExternalContext(); 706 if (econtext != null) { 707 Map<String, Object> requestMap = econtext.getRequestMap(); 708 requestMap.remove(SEARCH_DOCUMENT_EL_VARIABLE); 709 if (previousValue != null) { 710 requestMap.put(SEARCH_DOCUMENT_EL_VARIABLE, previousValue); 711 } 712 } else { 713 log.error(String.format( 714 "External context is null: cannot dispose variable '%s' " + "for content view '%s'", 715 SEARCH_DOCUMENT_EL_VARIABLE, getName())); 716 } 717 } 718 719 @Override 720 public boolean getShowPageSizeSelector() { 721 return showPageSizeSelector; 722 } 723 724 @Override 725 public boolean getShowRefreshCommand() { 726 return showRefreshCommand; 727 } 728 729 @Override 730 public boolean getShowFilterForm() { 731 return showFilterForm; 732 } 733 734 @Override 735 public boolean getShowTitle() { 736 return showTitle; 737 } 738 739 @Override 740 public String getEmptySentence() { 741 return emptySentence; 742 } 743 744 @Override 745 public boolean getTranslateEmptySentence() { 746 return translateEmptySentence; 747 } 748 749 @Override 750 public String toString() { 751 return String.format("ContentViewImpl [name=%s, title=%s, " + "translateTitle=%s, iconPath=%s, " 752 + "selectionList=%s, pagination=%s, " + "actionCategories=%s, searchLayout=%s, " 753 + "resultLayouts=%s, currentResultLayout=%s, " 754 + "flags=%s, cacheKey=%s, cacheSize=%s, currentPageSize=%s" 755 + "refreshEventNames=%s, resetEventNames=%s," + "useGlobalPageSize=%s, searchDocumentModel=%s]", name, 756 title, Boolean.valueOf(translateTitle), iconPath, selectionList, pagination, actionCategories, 757 searchLayout, resultLayouts, currentResultLayout, flags, cacheKey, cacheSize, currentPageSize, 758 refreshEventNames, resetEventNames, Boolean.valueOf(useGlobalPageSize), searchDocumentModel); 759 } 760 761 /* 762 * ----- PageProviderChangedListener ----- 763 */ 764 765 protected void raiseEvent(String eventName, Object... params) { 766 if (Events.exists()) { 767 Events.instance().raiseEvent(eventName, params); 768 } 769 } 770 771 protected void raiseEvent(String eventName) { 772 raiseEvent(eventName, name); 773 } 774 775 @Override 776 public void pageChanged(PageProvider<?> pageProvider) { 777 raiseEvent(CONTENT_VIEW_PAGE_CHANGED_EVENT); 778 } 779 780 @Override 781 public void refreshed(PageProvider<?> pageProvider) { 782 raiseEvent(CONTENT_VIEW_REFRESH_EVENT); 783 } 784 785 @SuppressWarnings("rawtypes") 786 @Override 787 public void resetPageProviderAggregates() { 788 if (pageProvider != null && pageProvider.hasAggregateSupport()) { 789 Map<String, ? extends Aggregate> aggs = pageProvider.getAggregates(); 790 for (Aggregate agg : aggs.values()) { 791 agg.resetSelection(); 792 } 793 } 794 } 795 796 @Override 797 public String getWaitForExecutionSentence() { 798 return waitForExecutionSentence; 799 } 800 801 /** 802 * @since 7.4 803 */ 804 public void setWaitForExecutionSentence(String waitForExecutionSentence) { 805 this.waitForExecutionSentence = waitForExecutionSentence; 806 } 807 808 @Override 809 public boolean isWaitForExecution() { 810 return waitForExecution; 811 } 812 813 /** 814 * @since 7.4 815 */ 816 public void setWaitForExecution(boolean waitForExecution) { 817 this.waitForExecution = waitForExecution; 818 } 819 820 @Override 821 public boolean isExecuted() { 822 return executed; 823 } 824 825 @Override 826 public void setExecuted(boolean executed) { 827 this.executed = executed; 828 } 829 830}