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