001 /** 002 * Copyright 2005-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php 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 package org.kuali.rice.krad.uif.view; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.kuali.rice.krad.datadictionary.DataDictionary; 020 import org.kuali.rice.krad.datadictionary.parse.BeanTag; 021 import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 022 import org.kuali.rice.krad.datadictionary.parse.BeanTags; 023 import org.kuali.rice.krad.datadictionary.state.StateMapping; 024 import org.kuali.rice.krad.datadictionary.validator.ValidationTrace; 025 import org.kuali.rice.krad.datadictionary.validator.Validator; 026 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 027 import org.kuali.rice.krad.uif.UifConstants; 028 import org.kuali.rice.krad.uif.UifConstants.ViewStatus; 029 import org.kuali.rice.krad.uif.UifConstants.ViewType; 030 import org.kuali.rice.krad.uif.component.Component; 031 import org.kuali.rice.krad.uif.component.ReferenceCopy; 032 import org.kuali.rice.krad.uif.component.RequestParameter; 033 import org.kuali.rice.krad.uif.container.Container; 034 import org.kuali.rice.krad.uif.container.ContainerBase; 035 import org.kuali.rice.krad.uif.container.Group; 036 import org.kuali.rice.krad.uif.container.NavigationGroup; 037 import org.kuali.rice.krad.uif.container.PageGroup; 038 import org.kuali.rice.krad.uif.element.Header; 039 import org.kuali.rice.krad.uif.element.Link; 040 import org.kuali.rice.krad.uif.layout.LayoutManager; 041 import org.kuali.rice.krad.uif.service.ViewHelperService; 042 import org.kuali.rice.krad.uif.util.BooleanMap; 043 import org.kuali.rice.krad.uif.util.ClientValidationUtils; 044 import org.kuali.rice.krad.uif.widget.BlockUI; 045 import org.kuali.rice.krad.uif.widget.BreadCrumbs; 046 import org.kuali.rice.krad.uif.widget.Growls; 047 import org.kuali.rice.krad.util.ObjectUtils; 048 import org.kuali.rice.krad.web.form.UifFormBase; 049 050 import java.util.ArrayList; 051 import java.util.HashMap; 052 import java.util.HashSet; 053 import java.util.List; 054 import java.util.Map; 055 import java.util.Set; 056 057 /** 058 * Root of the component tree which encompasses a set of related 059 * <code>GroupContainer</code> instances tied together with a common page layout 060 * and navigation. 061 * 062 * <p> 063 * The <code>View</code> component ties together all the components and 064 * configuration of the User Interface for a piece of functionality. In Rice 065 * applications the view is typically associated with a <code>Document</code> 066 * instance. 067 * </p> 068 * 069 * <p> 070 * The view template lays out the common header, footer, and navigation for the 071 * related pages. In addition the view renders the HTML head element bringing in 072 * common script files and style sheets, along with optionally rendering a form 073 * element for pages that need to post data back to the server. 074 * </p> 075 * 076 * <p> 077 * Configuration of UIF features such as model validation is also done through 078 * the <code>View</code> 079 * </p> 080 * 081 * @author Kuali Rice Team (rice.collab@kuali.org) 082 */ 083 @BeanTags({@BeanTag(name = "view-bean", parent = "Uif-View"), @BeanTag(name = "view-knsTheme-bean", parent = "Uif-View-KnsTheme") 084 }) 085 public class View extends ContainerBase { 086 private static final long serialVersionUID = -1220009725554576953L; 087 088 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(View.class); 089 090 private String namespaceCode; 091 private String viewName; 092 private ViewTheme theme; 093 094 private int idSequence; 095 096 private String stateObjectBindingPath; 097 private StateMapping stateMapping; 098 099 // application 100 private Header applicationHeader; 101 private Group applicationFooter; 102 103 // Breadcrumbs 104 private BreadCrumbs breadcrumbs; 105 private String breadcrumbTitlePropertyName; 106 private String breadcrumbTitleDisplayOption; 107 108 private boolean renderBreadcrumbsInView; 109 110 // Growls support 111 private Growls growls; 112 private boolean growlMessagingEnabled; 113 114 private BlockUI refreshBlockUI; 115 private BlockUI navigationBlockUI; 116 117 private String entryPageId; 118 119 @RequestParameter 120 private String currentPageId; 121 122 private Group navigation; 123 124 private Class<?> formClass; 125 private String defaultBindingObjectPath; 126 private Map<String, Class<?>> objectPathToConcreteClassMapping; 127 128 private List<String> additionalScriptFiles; 129 private List<String> additionalCssFiles; 130 131 private ViewType viewTypeName; 132 133 private String viewStatus; 134 private ViewIndex viewIndex; 135 private Map<String, String> viewRequestParameters; 136 137 private boolean persistFormToSession; 138 139 private ViewPresentationController presentationController; 140 private ViewAuthorizer authorizer; 141 142 private BooleanMap actionFlags; 143 private BooleanMap editModes; 144 145 private Map<String, String> expressionVariables; 146 147 private boolean singlePageView; 148 private boolean mergeWithPageItems; 149 private PageGroup page; 150 151 private List<? extends Group> items; 152 private List<? extends Group> dialogs; 153 154 private Link viewMenuLink; 155 private String viewMenuGroupName; 156 157 private boolean applyDirtyCheck; 158 private boolean translateCodesOnReadOnlyDisplay; 159 private boolean supportsRequestOverrideOfReadOnlyFields; 160 161 private String preLoadScript; 162 163 private int preloadPoolSize; 164 165 private List<String> viewTemplates; 166 167 private Class<? extends ViewHelperService> viewHelperServiceClass; 168 169 @ReferenceCopy 170 private ViewHelperService viewHelperService; 171 172 public View() { 173 singlePageView = false; 174 mergeWithPageItems = true; 175 translateCodesOnReadOnlyDisplay = false; 176 viewTypeName = ViewType.DEFAULT; 177 viewStatus = UifConstants.ViewStatus.CREATED; 178 formClass = UifFormBase.class; 179 renderBreadcrumbsInView = true; 180 supportsRequestOverrideOfReadOnlyFields = true; 181 persistFormToSession = true; 182 183 idSequence = 0; 184 this.viewIndex = new ViewIndex(); 185 preloadPoolSize = 0; 186 187 additionalScriptFiles = new ArrayList<String>(); 188 additionalCssFiles = new ArrayList<String>(); 189 items = new ArrayList<Group>(); 190 objectPathToConcreteClassMapping = new HashMap<String, Class<?>>(); 191 viewRequestParameters = new HashMap<String, String>(); 192 expressionVariables = new HashMap<String, String>(); 193 194 dialogs = new ArrayList<Group>(); 195 viewTemplates = new ArrayList<String>(); 196 } 197 198 /** 199 * The following initialization is performed: 200 * 201 * <ul> 202 * <li>If a single paged view, set items in page group and put the page in 203 * the items list</li> 204 * </ul> 205 * 206 * @see org.kuali.rice.krad.uif.container.ContainerBase#performInitialization(View, java.lang.Object) 207 */ 208 @SuppressWarnings("unchecked") 209 @Override 210 public void performInitialization(View view, Object model) { 211 super.performInitialization(view, model); 212 213 // populate items on page for single paged view 214 if (singlePageView) { 215 if (page != null) { 216 // remove default sections of page when requested 217 if (!mergeWithPageItems) { 218 page.setItems(new ArrayList<Group>()); 219 } 220 221 view.assignComponentIds(page); 222 223 // add the items configured on the view to the page items, and set as the 224 // new page items 225 List<Component> newItems = (List<Component>) page.getItems(); 226 newItems.addAll(items); 227 page.setItems(newItems); 228 229 // reset the items list to include the one page 230 items = new ArrayList<Group>(); 231 ((List<Group>) items).add(page); 232 } else { 233 throw new RuntimeException("For single paged views the page Group must be set."); 234 } 235 } 236 237 // make sure all the pages have ids before selecting the current page 238 for (Group group : this.getItems()) { 239 if (StringUtils.isBlank(group.getId())) { 240 group.setId(view.getNextId()); 241 } 242 } 243 } 244 245 /** 246 * The following updates are done here: 247 * 248 * <ul> 249 * <li>Invoke expression evaluation on view theme</li> 250 * </ul> 251 */ 252 public void performApplyModel(View view, Object model, Component parent) { 253 super.performApplyModel(view, model, parent); 254 255 if (theme != null) { 256 KRADServiceLocatorWeb.getExpressionEvaluatorService().evaluateExpressionsOnConfigurable(view, theme, model, 257 getContext()); 258 } 259 } 260 261 /** 262 * The following is performed: 263 * 264 * <ul> 265 * <li>Adds to its document ready script the setupValidator js function for setting 266 * up the validator for this view</li> 267 * </ul> 268 * 269 * @see org.kuali.rice.krad.uif.container.ContainerBase#performFinalize(View, 270 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 271 */ 272 @Override 273 public void performFinalize(View view, Object model, Component parent) { 274 super.performFinalize(view, model, parent); 275 276 String preLoadScript = ""; 277 if (this.getPreLoadScript() != null) { 278 preLoadScript = this.getPreLoadScript(); 279 } 280 281 // Retrieve Growl and BlockUI settings 282 Growls gw = view.getGrowls(); 283 if (!gw.getTemplateOptions().isEmpty()) { 284 preLoadScript += "setGrowlDefaults(" + gw.getTemplateOptionsJSString() + ");"; 285 } 286 287 BlockUI navBlockUI = view.getNavigationBlockUI(); 288 if (!navBlockUI.getTemplateOptions().isEmpty()) { 289 preLoadScript += "setBlockUIDefaults(" 290 + navBlockUI.getTemplateOptionsJSString() 291 + ", '" 292 + UifConstants.BLOCKUI_NAVOPTS 293 + "');"; 294 } 295 296 BlockUI refBlockUI = view.getRefreshBlockUI(); 297 if (!refBlockUI.getTemplateOptions().isEmpty()) { 298 preLoadScript += "setBlockUIDefaults(" 299 + refBlockUI.getTemplateOptionsJSString() 300 + ", '" 301 + UifConstants.BLOCKUI_REFRESHOPTS 302 + "');"; 303 } 304 305 this.setPreLoadScript(preLoadScript); 306 307 String onReadyScript = ""; 308 if (this.getOnDocumentReadyScript() != null) { 309 onReadyScript = this.getOnDocumentReadyScript(); 310 } 311 312 this.setOnDocumentReadyScript(onReadyScript + "jQuery.extend(jQuery.validator.messages, " + 313 ClientValidationUtils.generateValidatorMessagesOption() + ");"); 314 } 315 316 /** 317 * Assigns an id to the component if one was not configured 318 * 319 * @param component - component instance to assign id to 320 */ 321 public void assignComponentIds(Component component) { 322 if (component == null) { 323 return; 324 } 325 326 Integer currentSequenceVal = idSequence; 327 328 // assign ID if necessary 329 if (StringUtils.isBlank(component.getId())) { 330 component.setId(UifConstants.COMPONENT_ID_PREFIX + getNextId()); 331 } 332 333 // capture current sequence value for component refreshes 334 getViewIndex().addSequenceValueToSnapshot(component.getId(), currentSequenceVal); 335 336 if (component instanceof Container) { 337 LayoutManager layoutManager = ((Container) component).getLayoutManager(); 338 if (layoutManager != null) { 339 if (StringUtils.isBlank(layoutManager.getId())) { 340 layoutManager.setId(UifConstants.COMPONENT_ID_PREFIX + getNextId()); 341 } 342 } 343 } 344 345 // assign id to nested components 346 List<Component> allNested = new ArrayList<Component>(component.getComponentsForLifecycle()); 347 allNested.addAll(component.getComponentPrototypes()); 348 for (Component nestedComponent : allNested) { 349 assignComponentIds(nestedComponent); 350 } 351 } 352 353 /** 354 * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle() 355 */ 356 @Override 357 public List<Component> getComponentsForLifecycle() { 358 List<Component> components = new ArrayList<Component>(); 359 360 components.add(applicationHeader); 361 components.add(applicationFooter); 362 components.add(navigation); 363 components.add(breadcrumbs); 364 components.add(growls); 365 components.addAll(dialogs); 366 components.add(viewMenuLink); 367 components.add(navigationBlockUI); 368 components.add(refreshBlockUI); 369 370 // Note super items should be added after navigation and other view components so 371 // conflicting ids between nav and page do not occur on page navigation via ajax 372 components.addAll(super.getComponentsForLifecycle()); 373 374 // remove all pages that are not the current page 375 if (!singlePageView) { 376 for (Group group : this.getItems()) { 377 if ((group instanceof PageGroup) && !StringUtils.equals(group.getId(), getCurrentPageId()) && components 378 .contains(group)) { 379 components.remove(group); 380 } 381 } 382 } 383 384 return components; 385 } 386 387 /** 388 * @see org.kuali.rice.krad.uif.container.Container#getSupportedComponents() 389 */ 390 @Override 391 public Set<Class<? extends Component>> getSupportedComponents() { 392 Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>(); 393 supportedComponents.add(Group.class); 394 395 return supportedComponents; 396 } 397 398 /** 399 * @see org.kuali.rice.krad.uif.component.Component#getComponentTypeName() 400 */ 401 @Override 402 public String getComponentTypeName() { 403 return "view"; 404 } 405 406 /** 407 * Iterates through the contained page items and returns the Page that 408 * matches the set current page id 409 * 410 * @return Page instance 411 */ 412 public PageGroup getCurrentPage() { 413 for (Group pageGroup : this.getItems()) { 414 if (StringUtils.equals(pageGroup.getId(), getCurrentPageId()) && pageGroup instanceof PageGroup) { 415 return (PageGroup) pageGroup; 416 } 417 } 418 419 return null; 420 } 421 422 /** 423 * Override sort method to prevent sorting in the case of a single page view, since the items 424 * will get pushed into the configured page and sorted through the page 425 */ 426 @Override 427 protected void sortItems(View view, Object model) { 428 if (!singlePageView) { 429 super.sortItems(view, model); 430 } 431 } 432 433 /** 434 * Namespace code the view should be associated with 435 * 436 * <p> 437 * The namespace code is used within the framework in such places as permission checks and parameter 438 * retrieval 439 * </p> 440 * 441 * @return String namespace code 442 */ 443 @BeanTagAttribute(name = "namespaceCode") 444 public String getNamespaceCode() { 445 return namespaceCode; 446 } 447 448 /** 449 * Setter for the view's namespace code 450 * 451 * @param namespaceCode 452 */ 453 public void setNamespaceCode(String namespaceCode) { 454 this.namespaceCode = namespaceCode; 455 } 456 457 /** 458 * View name provides an identifier for a view within a type. That is if a 459 * set of <code>View</code> instances have the same values for the 460 * properties that are used to retrieve them by their type, the name can be 461 * given to further qualify the view that should be retrieved. 462 * <p> 463 * A view type like the <code>LookupView</code> might have several views for 464 * the same object class, but one that is the 'default' lookup and another 465 * that is the 'advanced' lookup. Therefore the name on the first could be 466 * set to 'default', and likewise the name for the second 'advanced'. 467 * </p> 468 * 469 * @return String name of view 470 */ 471 @BeanTagAttribute(name = "viewName") 472 public String getViewName() { 473 return this.viewName; 474 } 475 476 /** 477 * Setter for the view's name 478 * 479 * @param viewName 480 */ 481 public void setViewName(String viewName) { 482 this.viewName = viewName; 483 } 484 485 /** 486 * Header for the application containing the view 487 * 488 * <p> 489 * When deploying outside a portal, the application header and footer property can be configured to 490 * display a consistent header/footer across all views. Here application logos, menus, login controls 491 * and so on can be rendered. 492 * </p> 493 * 494 * @return HeaderField application header 495 */ 496 @BeanTagAttribute(name = "applicationHeader", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 497 public Header getApplicationHeader() { 498 return applicationHeader; 499 } 500 501 /** 502 * Setter for the application header 503 * 504 * @param applicationHeader 505 */ 506 public void setApplicationHeader(Header applicationHeader) { 507 this.applicationHeader = applicationHeader; 508 } 509 510 /** 511 * Footer for the application containing the view 512 * 513 * <p> 514 * When deploying outside a portal, the application header and footer property can be configured to 515 * display a consistent header/footer across all views. Here such things as application links, copyrights 516 * and so on can be rendered. 517 * </p> 518 * 519 * @return Group application footer 520 */ 521 @BeanTagAttribute(name = "applicationFooter", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 522 public Group getApplicationFooter() { 523 return applicationFooter; 524 } 525 526 /** 527 * Setter for the application footer 528 * 529 * @param applicationFooter 530 */ 531 public void setApplicationFooter(Group applicationFooter) { 532 this.applicationFooter = applicationFooter; 533 } 534 535 /** 536 * Current sequence value for id assignment 537 * 538 * @return int id sequence 539 */ 540 public int getIdSequence() { 541 return idSequence; 542 } 543 544 /** 545 * Setter for the current id sequence value 546 * 547 * @param idSequence 548 */ 549 public void setIdSequence(int idSequence) { 550 this.idSequence = idSequence; 551 } 552 553 /** 554 * Returns the next unique id available for components within the view instance 555 * 556 * @return String next id available 557 */ 558 public String getNextId() { 559 idSequence += 1; 560 return Integer.toString(idSequence); 561 } 562 563 /** 564 * Specifies what page should be rendered by default. This is the page that 565 * will be rendered when the <code>View</code> is first rendered or when the 566 * current page is not set 567 * 568 * @return String id of the page to render by default 569 */ 570 @BeanTagAttribute(name = "entryPageId") 571 public String getEntryPageId() { 572 return this.entryPageId; 573 } 574 575 /** 576 * Setter for default Page id 577 * 578 * @param entryPageId 579 */ 580 public void setEntryPageId(String entryPageId) { 581 this.entryPageId = entryPageId; 582 } 583 584 /** 585 * The id for the page within the view that should be displayed in the UI. 586 * Other pages of the view will not be rendered 587 * 588 * <p> 589 * If current page id is not set, it is set to the configured entry page or first item in list id 590 * </p> 591 * 592 * @return String id of the page that should be displayed 593 */ 594 public String getCurrentPageId() { 595 // default current page if not set 596 if (StringUtils.isBlank(currentPageId)) { 597 if (StringUtils.isNotBlank(entryPageId)) { 598 currentPageId = entryPageId; 599 } else if ((getItems() != null) && !getItems().isEmpty()) { 600 Group firstPageGroup = getItems().get(0); 601 currentPageId = firstPageGroup.getId(); 602 } 603 } 604 605 return this.currentPageId; 606 } 607 608 /** 609 * Setter for the page id to display 610 * 611 * @param currentPageId 612 */ 613 public void setCurrentPageId(String currentPageId) { 614 this.currentPageId = currentPageId; 615 } 616 617 /** 618 * <code>NavigationGroup</code> instance for the <code>View</code> 619 * <p> 620 * Provides configuration necessary to render the navigation. This includes 621 * navigation items in addition to configuration for the navigation 622 * renderer. 623 * </p> 624 * 625 * @return NavigationGroup 626 */ 627 @BeanTagAttribute(name = "navigation", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 628 public Group getNavigation() { 629 return this.navigation; 630 } 631 632 /** 633 * Setter for the View's <code>NavigationGroup</code> 634 * 635 * @param navigation 636 */ 637 public void setNavigation(Group navigation) { 638 this.navigation = navigation; 639 } 640 641 /** 642 * Class of the Form that should be used with the <code>View</code> 643 * instance. The form is the top level object for all the view's data and is 644 * used to present and accept data in the user interface. All form classes 645 * should extend UifFormBase 646 * 647 * @return Class<?> class for the view's form 648 * @see org.kuali.rice.krad.web.form.UifFormBase 649 */ 650 @BeanTagAttribute(name = "formClass") 651 public Class<?> getFormClass() { 652 return this.formClass; 653 } 654 655 /** 656 * Setter for the form class 657 * 658 * @param formClass 659 */ 660 public void setFormClass(Class<?> formClass) { 661 this.formClass = formClass; 662 } 663 664 /** 665 * For <code>View</code> types that work primarily with one nested object of 666 * the form (for instance document, or bo) the default binding object path 667 * can be set for each of the views <code>DataBinding</code> components. If 668 * the component does not set its own binding object path it will inherit 669 * the default 670 * 671 * @return String binding path to the object from the form 672 */ 673 @BeanTagAttribute(name = "defaultObjectPath") 674 public String getDefaultBindingObjectPath() { 675 return this.defaultBindingObjectPath; 676 } 677 678 /** 679 * Setter for the default binding object path to use for the view 680 * 681 * @param defaultBindingObjectPath 682 */ 683 public void setDefaultBindingObjectPath(String defaultBindingObjectPath) { 684 this.defaultBindingObjectPath = defaultBindingObjectPath; 685 } 686 687 /** 688 * Configures the concrete classes that will be used for properties in the 689 * form object graph that have an abstract or interface type 690 * 691 * <p> 692 * For properties that have an abstract or interface type, it is not 693 * possible to perform operations like getting/settings property values and 694 * getting information from the dictionary. When these properties are 695 * encountered in the object graph, this <code>Map</code> will be consulted 696 * to determine the concrete type to use. 697 * </p> 698 * 699 * <p> 700 * e.g. Suppose we have a property document.accountingLine.accountNumber and 701 * the accountingLine property on the document instance has an interface 702 * type 'AccountingLine'. We can then put an entry into this map with key 703 * 'document.accountingLine', and value 704 * 'org.kuali.rice.sampleapp.TravelAccountingLine'. When getting the 705 * property type or an entry from the dictionary for accountNumber, the 706 * TravelAccountingLine class will be used. 707 * </p> 708 * 709 * @return Map<String, Class> of class implementations keyed by path 710 */ 711 @BeanTagAttribute(name = "objectPathConcreteClassMapping", type = BeanTagAttribute.AttributeType.MAPVALUE) 712 public Map<String, Class<?>> getObjectPathToConcreteClassMapping() { 713 return this.objectPathToConcreteClassMapping; 714 } 715 716 /** 717 * Setter for the Map of class implementations keyed by path 718 * 719 * @param objectPathToConcreteClassMapping 720 */ 721 public void setObjectPathToConcreteClassMapping(Map<String, Class<?>> objectPathToConcreteClassMapping) { 722 this.objectPathToConcreteClassMapping = objectPathToConcreteClassMapping; 723 } 724 725 /** 726 * Declares additional script files that should be included with the 727 * <code>View</code>. These files are brought into the HTML page along with 728 * common script files configured for the Rice application. Each entry 729 * contain the path to the CSS file, either a relative path, path from web 730 * root, or full URI 731 * <p> 732 * e.g. '/krad/scripts/myScript.js', '../scripts/myScript.js', 733 * 'http://my.edu/web/myScript.js' 734 * </p> 735 * 736 * @return List<String> script file locations 737 */ 738 @BeanTagAttribute(name = "additionalScriptFiles", type = BeanTagAttribute.AttributeType.LISTVALUE) 739 public List<String> getAdditionalScriptFiles() { 740 return this.additionalScriptFiles; 741 } 742 743 /** 744 * Setter for the List of additional script files to included with the 745 * <code>View</code> 746 * 747 * @param additionalScriptFiles 748 */ 749 public void setAdditionalScriptFiles(List<String> additionalScriptFiles) { 750 this.additionalScriptFiles = additionalScriptFiles; 751 } 752 753 /** 754 * Declares additional CSS files that should be included with the 755 * <code>View</code>. These files are brought into the HTML page along with 756 * common CSS files configured for the Rice application. Each entry should 757 * contain the path to the CSS file, either a relative path, path from web 758 * root, or full URI 759 * <p> 760 * e.g. '/krad/css/stacked-view.css', '../css/stacked-view.css', 761 * 'http://my.edu/web/stacked-view.css' 762 * </p> 763 * 764 * @return List<String> CSS file locations 765 */ 766 @BeanTagAttribute(name = "additionalCssFiles", type = BeanTagAttribute.AttributeType.LISTVALUE) 767 public List<String> getAdditionalCssFiles() { 768 return this.additionalCssFiles; 769 } 770 771 /** 772 * Setter for the List of additional CSS files to included with the 773 * <code>View</code> 774 * 775 * @param additionalCssFiles 776 */ 777 public void setAdditionalCssFiles(List<String> additionalCssFiles) { 778 this.additionalCssFiles = additionalCssFiles; 779 } 780 781 /** 782 * Specifies the size of the pool that will contain pre-loaded views 783 * 784 * <p> 785 * The spring loading of some views can take a few seconds which hurts performance. The framework supports 786 * pre-loading of view instances so they are available right away when a request is made. This property configures 787 * how many view instances will be pre-loaded. A value of 0 (the default) means no view instances will be 788 * pre-loaded 789 * </p> 790 * 791 * @return int number of view instances to pre-load 792 */ 793 @BeanTagAttribute(name = "preloadPoolSize") 794 public int getPreloadPoolSize() { 795 return preloadPoolSize; 796 } 797 798 /** 799 * Setter for the preloaded view pool size 800 * 801 * @param preloadPoolSize 802 */ 803 public void setPreloadPoolSize(int preloadPoolSize) { 804 this.preloadPoolSize = preloadPoolSize; 805 } 806 807 /** 808 * List of templates that are used to render the view 809 * 810 * <p> 811 * This list will be populated by unique template names as the components of the view are being processed. 812 * Additional templates can be added in the view configuration if desired. At the beginning of the the view 813 * rendering, each template in the list will then be included or processed by the template language 814 * </p> 815 * 816 * <p> 817 * Note the user of this depends on the template language being used for rendering. Some languages might require 818 * including the template for each component instance (for example JSP templates). While others might simply 819 * include markup that is then available for rendering each component instance (for example FreeMarker which has 820 * a macro for each component that the template defines) 821 * </p> 822 * 823 * @return List<String> list of template names that should be included for rendering the view 824 */ 825 public List<String> getViewTemplates() { 826 return viewTemplates; 827 } 828 829 /** 830 * Setter for the the list of template names that should be included to render the view 831 * 832 * @param viewTemplates 833 */ 834 public void setViewTemplates(List<String> viewTemplates) { 835 this.viewTemplates = viewTemplates; 836 } 837 838 /** 839 * View type name the view is associated with the view instance 840 * 841 * <p> 842 * Views that share common features and functionality can be grouped by the 843 * view type. Usually view types extend the <code>View</code> class to 844 * provide additional configuration and to set defaults. View types can also 845 * implement the <code>ViewTypeService</code> to add special indexing and 846 * retrieval of views. 847 * </p> 848 * 849 * @return String view type name for the view 850 */ 851 @BeanTagAttribute(name = "viewTypeName", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 852 public ViewType getViewTypeName() { 853 return this.viewTypeName; 854 } 855 856 /** 857 * Setter for the view's type name 858 * 859 * @param viewTypeName 860 */ 861 public void setViewTypeName(ViewType viewTypeName) { 862 this.viewTypeName = viewTypeName; 863 } 864 865 /** 866 * Class name of the <code>ViewHelperService</code> that handles the various 867 * phases of the Views lifecycle 868 * 869 * @return Class for the spring bean 870 * @see org.kuali.rice.krad.uif.service.ViewHelperService 871 */ 872 @BeanTagAttribute(name = "viewHelperServiceClass") 873 public Class<? extends ViewHelperService> getViewHelperServiceClass() { 874 return this.viewHelperServiceClass; 875 } 876 877 /** 878 * Setter for the <code>ViewHelperService</code> class name 879 * 880 * @param viewHelperServiceClass 881 */ 882 public void setViewHelperServiceClass(Class<? extends ViewHelperService> viewHelperServiceClass) { 883 this.viewHelperServiceClass = viewHelperServiceClass; 884 } 885 886 /** 887 * Creates the <code>ViewHelperService</code> associated with the View 888 * 889 * @return ViewHelperService instance 890 */ 891 @BeanTagAttribute(name = "viewHelperService", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 892 public ViewHelperService getViewHelperService() { 893 if ((this.viewHelperService == null) && (this.viewHelperServiceClass != null)) { 894 viewHelperService = ObjectUtils.newInstance(viewHelperServiceClass); 895 } 896 897 return viewHelperService; 898 } 899 900 /** 901 * Invoked to produce a ViewIndex of the current view's components 902 */ 903 public void index() { 904 if (this.viewIndex == null) { 905 this.viewIndex = new ViewIndex(); 906 } 907 this.viewIndex.index(this); 908 } 909 910 /** 911 * Holds field indexes of the <code>View</code> instance for retrieval 912 * 913 * @return ViewIndex instance 914 */ 915 @BeanTagAttribute(name = "viewIndex", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 916 public ViewIndex getViewIndex() { 917 return this.viewIndex; 918 } 919 920 /** 921 * Map of parameters from the request that set view options, used to rebuild 922 * the view on each post 923 * <p> 924 * Views can be configured by parameters. These might impact which parts of 925 * the view are rendered or how the view behaves. Generally these would get 926 * passed in when a new view is requested (by request parameters). These 927 * will be used to initially populate the view properties. In addition, on a 928 * post the view will be rebuilt and properties reset again by the allow 929 * request parameters. 930 * </p> 931 * <p> 932 * Example parameter would be for MaintenaceView whether a New, Edit, or 933 * Copy was requested (maintenance mode) 934 * </p> 935 * 936 * @return 937 */ 938 public Map<String, String> getViewRequestParameters() { 939 return this.viewRequestParameters; 940 } 941 942 /** 943 * Setter for the view's request parameters map 944 * 945 * @param viewRequestParameters 946 */ 947 public void setViewRequestParameters(Map<String, String> viewRequestParameters) { 948 this.viewRequestParameters = viewRequestParameters; 949 } 950 951 /** 952 * Indicates whether the form (model) associated with the view should be stored in the user session 953 * 954 * <p> 955 * The form class (or model) is used to hold the data that backs the view along with the built view object. Storing 956 * the form instance in session allows many things: 957 * 958 * <ul> 959 * <li>Data does not need to be rebuilt for each server request (for example a collection)</li> 960 * <li>Data that does not need to go to the user can remain on the form, reducing the size of the response and 961 * improving security</li> 962 * <li>Data can be keep around in a 'pre-save' state. When requested by the user changes can then be persisted to 963 * the database</li> 964 * <li>Certain information about the view that was rendered, such as input fields, collection paths, and refresh 965 * components can be kept on the form to support UI interaction</li> 966 * </ul> 967 * 968 * Setting this flag to false will prevent the form from being kept in session and as a result will limit what can 969 * be done by the framework. In almost all cases this is not recommended. 970 * </p> 971 * 972 * <p> 973 * Note all forms will be cleared when the user session expires (based on the rice configuration). In addition, the 974 * framework enables clear points on certain actions to remove the form when it is no longer needed 975 * </p> 976 * 977 * @return boolean true if the form should be stored in the user session, false if only request based 978 */ 979 @BeanTagAttribute(name = "persistFormToSession") 980 public boolean isPersistFormToSession() { 981 return persistFormToSession; 982 } 983 984 /** 985 * Setter for the persist form to session indicator 986 * 987 * @param persistFormToSession 988 */ 989 public void setPersistFormToSession(boolean persistFormToSession) { 990 this.persistFormToSession = persistFormToSession; 991 } 992 993 /** 994 * PresentationController that should be used for the <code>View</code> instance 995 * 996 * <p> 997 * The presentation controller is consulted to determine component (group, 998 * field) state such as required, read-only, and hidden. The presentation 999 * controller does not take into account user permissions. The presentation 1000 * controller can also output action flags and edit modes that will be set 1001 * onto the view instance and can be referred to by conditional expressions 1002 * </p> 1003 * 1004 * @return PresentationController 1005 */ 1006 @BeanTagAttribute(name = "presentationController", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1007 public ViewPresentationController getPresentationController() { 1008 return this.presentationController; 1009 } 1010 1011 /** 1012 * Setter for the view's presentation controller 1013 * 1014 * @param presentationController 1015 */ 1016 public void setPresentationController(ViewPresentationController presentationController) { 1017 this.presentationController = presentationController; 1018 } 1019 1020 /** 1021 * Setter for the view's presentation controller by class 1022 * 1023 * @param presentationControllerClass 1024 */ 1025 public void setPresentationControllerClass( 1026 Class<? extends ViewPresentationController> presentationControllerClass) { 1027 this.presentationController = ObjectUtils.newInstance(presentationControllerClass); 1028 } 1029 1030 /** 1031 * Authorizer that should be used for the <code>View</code> instance 1032 * 1033 * <p> 1034 * The authorizer class is consulted to determine component (group, field) 1035 * state such as required, read-only, and hidden based on the users 1036 * permissions. It typically communicates with the Kuali Identity Management 1037 * system to determine roles and permissions. It is used with the 1038 * presentation controller and dictionary conditional logic to determine the 1039 * final component state. The authorizer can also output action flags and 1040 * edit modes that will be set onto the view instance and can be referred to 1041 * by conditional expressions 1042 * </p> 1043 * 1044 * @return Authorizer 1045 */ 1046 @BeanTagAttribute(name = "authorizer", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1047 public ViewAuthorizer getAuthorizer() { 1048 return this.authorizer; 1049 } 1050 1051 /** 1052 * Setter for the view's authorizer 1053 * 1054 * @param authorizer 1055 */ 1056 public void setAuthorizer(ViewAuthorizer authorizer) { 1057 this.authorizer = authorizer; 1058 } 1059 1060 /** 1061 * Setter for the view's authorizer by class 1062 * 1063 * @param authorizerClass 1064 */ 1065 public void setAuthorizerClass(Class<? extends ViewAuthorizer> authorizerClass) { 1066 this.authorizer = ObjectUtils.newInstance(authorizerClass); 1067 } 1068 1069 /** 1070 * Map of strings that flag what actions can be taken in the UI 1071 * <p> 1072 * These can be used in conditional expressions in the dictionary or by 1073 * other UI logic 1074 * </p> 1075 * 1076 * @return BooleanMap action flags 1077 */ 1078 @BeanTagAttribute(name = "actionFlags", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1079 public BooleanMap getActionFlags() { 1080 return this.actionFlags; 1081 } 1082 1083 /** 1084 * Setter for the action flags Map 1085 * 1086 * @param actionFlags 1087 */ 1088 public void setActionFlags(BooleanMap actionFlags) { 1089 this.actionFlags = actionFlags; 1090 } 1091 1092 /** 1093 * Map of edit modes that enabled for the view 1094 * <p> 1095 * These can be used in conditional expressions in the dictionary or by 1096 * other UI logic 1097 * </p> 1098 * 1099 * @return BooleanMap edit modes 1100 */ 1101 @BeanTagAttribute(name = "editModes", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1102 public BooleanMap getEditModes() { 1103 return this.editModes; 1104 } 1105 1106 /** 1107 * Setter for the edit modes Map 1108 * 1109 * @param editModes 1110 */ 1111 public void setEditModes(BooleanMap editModes) { 1112 this.editModes = editModes; 1113 } 1114 1115 /** 1116 * Map that contains expressions to evaluate and make available as variables 1117 * for conditional expressions within the view 1118 * <p> 1119 * Each Map entry contains one expression variables, where the map key gives 1120 * the name for the variable, and the map value gives the variable 1121 * expression. The variables expressions will be evaluated before 1122 * conditional logic is run and made available as variables for other 1123 * conditional expressions. Variable expressions can be based on the model 1124 * and any object contained in the view's context 1125 * </p> 1126 * 1127 * @return Map<String, String> variable expressions 1128 */ 1129 @BeanTagAttribute(name = "expressionVariables", type = BeanTagAttribute.AttributeType.MAPVALUE) 1130 public Map<String, String> getExpressionVariables() { 1131 return this.expressionVariables; 1132 } 1133 1134 /** 1135 * Setter for the view's map of variable expressions 1136 * 1137 * @param expressionVariables 1138 */ 1139 public void setExpressionVariables(Map<String, String> expressionVariables) { 1140 this.expressionVariables = expressionVariables; 1141 } 1142 1143 /** 1144 * Indicates whether the <code>View</code> only has a single page 1145 * <code>Group</code> or contains multiple page <code>Group</code> 1146 * instances. In the case of a single page it is assumed the group's items 1147 * list contains the section groups for the page, and the page itself is 1148 * given by the page property ({@link #getPage()}. This is for convenience 1149 * of configuration and also can drive other configuration like styling. 1150 * 1151 * @return boolean true if the view only contains one page group, false if 1152 * it contains multple pages 1153 */ 1154 @BeanTagAttribute(name = "singlePageView") 1155 public boolean isSinglePageView() { 1156 return this.singlePageView; 1157 } 1158 1159 /** 1160 * Setter for the single page indicator 1161 * 1162 * @param singlePageView 1163 */ 1164 public void setSinglePageView(boolean singlePageView) { 1165 this.singlePageView = singlePageView; 1166 } 1167 1168 /** 1169 * Indicates whether the default sections specified in the page items list 1170 * should be included for this view. This only applies to single paged views. 1171 * 1172 * @return boolean true if the view should contain the default sections 1173 * specified in the page 1174 */ 1175 public boolean isMergeWithPageItems() { 1176 return mergeWithPageItems; 1177 } 1178 1179 /** 1180 * Setter for the include page default sections indicator 1181 * 1182 * @param mergeWithPageItems 1183 */ 1184 public void setMergeWithPageItems(boolean mergeWithPageItems) { 1185 this.mergeWithPageItems = mergeWithPageItems; 1186 } 1187 1188 /** 1189 * For single paged views ({@link #isSinglePageView()}, gives the page 1190 * <code>Group</code> the view should render. The actual items for the page 1191 * is taken from the group's items list ({@link #getItems()}, and set onto 1192 * the give page group. This is for convenience of configuration. 1193 * 1194 * @return Group page group for single page views 1195 */ 1196 @BeanTagAttribute(name = "page", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1197 public PageGroup getPage() { 1198 return this.page; 1199 } 1200 1201 /** 1202 * Setter for the page group for single page views 1203 * 1204 * @param page 1205 */ 1206 public void setPage(PageGroup page) { 1207 this.page = page; 1208 } 1209 1210 /** 1211 * @see org.kuali.rice.krad.uif.container.ContainerBase#getItems() 1212 */ 1213 @Override 1214 @BeanTagAttribute(name = "items", type = BeanTagAttribute.AttributeType.LISTBEAN) 1215 public List<? extends Group> getItems() { 1216 return this.items; 1217 } 1218 1219 /** 1220 * Setter for the view's <code>Group</code> instances 1221 * 1222 * @param items 1223 */ 1224 @Override 1225 public void setItems(List<? extends Component> items) { 1226 // TODO: fix this generic issue 1227 this.items = (List<? extends Group>) items; 1228 } 1229 1230 /** 1231 * Provide a list of dialog groups associated with this view 1232 * 1233 * @return List of dialog Groups 1234 */ 1235 @BeanTagAttribute(name = "dialogs", type = BeanTagAttribute.AttributeType.LISTBEAN) 1236 public List<? extends Group> getDialogs() { 1237 return dialogs; 1238 } 1239 1240 /** 1241 * Sets the list of dialog groups for this view 1242 * 1243 * @param dialogs - List of dialog groups 1244 */ 1245 public void setDialogs(List<? extends Group> dialogs) { 1246 this.dialogs = dialogs; 1247 } 1248 1249 /** 1250 * Provides configuration for displaying a link to the view from an 1251 * application menu 1252 * 1253 * @return Link view link field 1254 */ 1255 @BeanTagAttribute(name = "viewMenuLink", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1256 public Link getViewMenuLink() { 1257 return this.viewMenuLink; 1258 } 1259 1260 /** 1261 * Setter for the views link field 1262 * 1263 * @param viewMenuLink 1264 */ 1265 public void setViewMenuLink(Link viewMenuLink) { 1266 this.viewMenuLink = viewMenuLink; 1267 } 1268 1269 /** 1270 * Provides a grouping string for the view to group its menu link (within a 1271 * portal for instance) 1272 * 1273 * @return String menu grouping 1274 */ 1275 @BeanTagAttribute(name = "viewMenuGroupName") 1276 public String getViewMenuGroupName() { 1277 return this.viewMenuGroupName; 1278 } 1279 1280 /** 1281 * Setter for the views menu grouping 1282 * 1283 * @param viewMenuGroupName 1284 */ 1285 public void setViewMenuGroupName(String viewMenuGroupName) { 1286 this.viewMenuGroupName = viewMenuGroupName; 1287 } 1288 1289 /** 1290 * Indicates what lifecycle phase the View instance is in 1291 * <p> 1292 * The view lifecycle begins with the CREATED status. In this status a new 1293 * instance of the view has been retrieved from the dictionary, but no 1294 * further processing has been done. After the initialize phase has been run 1295 * the status changes to INITIALIZED. After the model has been applied and 1296 * the view is ready for render the status changes to FINAL 1297 * </p> 1298 * 1299 * @return String view status 1300 * @see org.kuali.rice.krad.uif.UifConstants.ViewStatus 1301 */ 1302 public String getViewStatus() { 1303 return this.viewStatus; 1304 } 1305 1306 /** 1307 * Setter for the view status 1308 * 1309 * @param viewStatus 1310 */ 1311 public void setViewStatus(String viewStatus) { 1312 this.viewStatus = viewStatus; 1313 } 1314 1315 /** 1316 * Indicates whether the view has been initialized 1317 * 1318 * @return boolean true if the view has been initialized, false if not 1319 */ 1320 public boolean isInitialized() { 1321 return StringUtils.equals(viewStatus, ViewStatus.INITIALIZED) || StringUtils.equals(viewStatus, 1322 ViewStatus.FINAL); 1323 } 1324 1325 /** 1326 * Indicates whether the view has been updated from the model and final 1327 * updates made 1328 * 1329 * @return boolean true if the view has been updated, false if not 1330 */ 1331 public boolean isFinal() { 1332 return StringUtils.equals(viewStatus, ViewStatus.FINAL); 1333 } 1334 1335 /** 1336 * Breadcrumb widget used for displaying homeward path and history 1337 * 1338 * @return the breadcrumbs 1339 */ 1340 @BeanTagAttribute(name = "breadcrumbs", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1341 public BreadCrumbs getBreadcrumbs() { 1342 return this.breadcrumbs; 1343 } 1344 1345 /** 1346 * @param breadcrumbs the breadcrumbs to set 1347 */ 1348 public void setBreadcrumbs(BreadCrumbs breadcrumbs) { 1349 this.breadcrumbs = breadcrumbs; 1350 } 1351 1352 /** 1353 * Indicates whether the breadcrumbs should be rendered in the view or if they have been rendered in 1354 * the application header 1355 * 1356 * <p> 1357 * For layout purposes it is sometimes necessary to render the breadcrumbs in the application header. This flag 1358 * indicates that is being done (by setting to false) and therefore should not be rendered in the view template. 1359 * </p> 1360 * 1361 * @return boolean true if breadcrumbs should be rendered in the view, false if not (are rendered in the 1362 * application header) 1363 */ 1364 @BeanTagAttribute(name = "renderBreadcrumbsInView") 1365 public boolean isRenderBreadcrumbsInView() { 1366 return renderBreadcrumbsInView; 1367 } 1368 1369 /** 1370 * Setter for the render breadcrumbs in view indicator 1371 * 1372 * @param renderBreadcrumbsInView 1373 */ 1374 public void setRenderBreadcrumbsInView(boolean renderBreadcrumbsInView) { 1375 this.renderBreadcrumbsInView = renderBreadcrumbsInView; 1376 } 1377 1378 /** 1379 * Growls widget which sets up global settings for the growls used in this 1380 * view and its pages 1381 * 1382 * @return the growls 1383 */ 1384 @BeanTagAttribute(name = "growls", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1385 public Growls getGrowls() { 1386 return this.growls; 1387 } 1388 1389 /** 1390 * @param growls the growls to set 1391 */ 1392 public void setGrowls(Growls growls) { 1393 this.growls = growls; 1394 } 1395 1396 /** 1397 * Set the refresh BlockUI used with single element blocking 1398 * (such as ajax based element loading/updates) 1399 * 1400 * @param refreshBlockUI 1401 */ 1402 public void setRefreshBlockUI(BlockUI refreshBlockUI) { 1403 this.refreshBlockUI = refreshBlockUI; 1404 } 1405 1406 /** 1407 * @return BlockUI returns the refresh block object 1408 */ 1409 @BeanTagAttribute(name = "refreshBlockUI", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1410 public BlockUI getRefreshBlockUI() { 1411 return refreshBlockUI; 1412 } 1413 1414 /** 1415 * Set the navigation BlockUI used with single page blocking 1416 * (such as full page loading/saving) 1417 * 1418 * @param navigationBlockUI 1419 */ 1420 public void setNavigationBlockUI(BlockUI navigationBlockUI) { 1421 this.navigationBlockUI = navigationBlockUI; 1422 } 1423 1424 /** 1425 * @return BlockUI returns the navigation block object 1426 */ 1427 @BeanTagAttribute(name = "navigationBlockUI", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1428 public BlockUI getNavigationBlockUI() { 1429 return navigationBlockUI; 1430 } 1431 1432 /** 1433 * whether to use growls to show messages - info, warning and error 1434 * 1435 * <p>Growls use the messages contained in the message map. If enabled, info 1436 * messages in their entirety will be displayed in growls, for warning and 1437 * error messages a growl message will notify the user that these messages 1438 * exist on the page.</p> 1439 * 1440 * <p> If this setting is disabled, it is recommended that 1441 * infoMessage display be enabled for the page ValidationMessages bean in order to 1442 * display relevant information to the user. Note: the growl scripts are 1443 * built out in the PageGroup class.</p> 1444 * 1445 * @return the growlMessagingEnabled 1446 */ 1447 @BeanTagAttribute(name = "growlMessagingEnabled") 1448 public boolean isGrowlMessagingEnabled() { 1449 return this.growlMessagingEnabled; 1450 } 1451 1452 /** 1453 * enable or disable showing of messages using growls 1454 * 1455 * @param growlMessagingEnabled the growlMessagingEnabled to set 1456 */ 1457 public void setGrowlMessagingEnabled(boolean growlMessagingEnabled) { 1458 this.growlMessagingEnabled = growlMessagingEnabled; 1459 } 1460 1461 /** 1462 * Indicates whether the form should be validated for dirtyness 1463 * 1464 * <p> 1465 * For FormView, it's necessary to validate when the user tries to navigate out of the form. If set, all the 1466 * InputFields will be validated on refresh, navigate, cancel or close Action or on form 1467 * unload and if dirty, displays a message and user can decide whether to continue with 1468 * the action or stay on the form. For lookup and inquiry, it's not needed to validate. 1469 * </p> 1470 * 1471 * @return true if dirty validation is set 1472 */ 1473 @BeanTagAttribute(name = "applyDirtyCheck") 1474 public boolean isApplyDirtyCheck() { 1475 return this.applyDirtyCheck; 1476 } 1477 1478 /** 1479 * Setter for dirty validation. 1480 */ 1481 public void setApplyDirtyCheck(boolean applyDirtyCheck) { 1482 this.applyDirtyCheck = applyDirtyCheck; 1483 } 1484 1485 /** 1486 * Indicates whether the Name of the Code should be displayed when a property is of type <code>KualiCode</code> 1487 * 1488 * @param translateCodesOnReadOnlyDisplay - indicates whether <code>KualiCode</code>'s name should be included 1489 */ 1490 public void setTranslateCodesOnReadOnlyDisplay(boolean translateCodesOnReadOnlyDisplay) { 1491 this.translateCodesOnReadOnlyDisplay = translateCodesOnReadOnlyDisplay; 1492 } 1493 1494 /** 1495 * Returns whether the current view supports displaying <code>KualiCode</code>'s name as additional display value 1496 * 1497 * @return true if the current view supports 1498 */ 1499 @BeanTagAttribute(name = "translateCodesOnReadOnlyDisplay") 1500 public boolean isTranslateCodesOnReadOnlyDisplay() { 1501 return translateCodesOnReadOnlyDisplay; 1502 } 1503 1504 /** 1505 * The property name to be used to determine what will be used in the 1506 * breadcrumb title of this view 1507 * 1508 * <p> 1509 * The title can be determined from a combination of this and viewLabelFieldbindingInfo: If only 1510 * viewLabelFieldPropertyName is set, the title we be determined against the 1511 * defaultBindingObjectPath. If only viewLabelFieldbindingInfo is set it 1512 * must provide information about what object(bindToForm or explicit) and 1513 * path to use. If both viewLabelFieldbindingInfo and viewLabelFieldPropertyName are set, 1514 * the bindingInfo will be used with a 1515 * the viewLabelFieldPropertyName as its bindingPath. If neither are set, 1516 * the default title attribute from the dataObject's metadata (determined by the 1517 * defaultBindingObjectPath's object) will be used. 1518 * </p> 1519 * 1520 * @return String property name whose value should be displayed in view label 1521 */ 1522 @BeanTagAttribute(name = "breadcrumbTitlePropertyName") 1523 public String getBreadcrumbTitlePropertyName() { 1524 return this.breadcrumbTitlePropertyName; 1525 } 1526 1527 /** 1528 * Setter for the view label property name 1529 * 1530 * @param breadcrumbTitlePropertyName the viewLabelFieldPropertyName to set 1531 */ 1532 public void setBreadcrumbTitlePropertyName(String breadcrumbTitlePropertyName) { 1533 this.breadcrumbTitlePropertyName = breadcrumbTitlePropertyName; 1534 } 1535 1536 /** 1537 * The option to use when appending the view label on the breadcrumb title. 1538 * Available options: 'dash', 'parenthesis', and 'replace'(don't append - 1539 * simply replace the title). MUST be set for the viewLabelField to be used 1540 * in the breadcrumb, if not set no appendage will be added. 1541 * 1542 * @return the appendOption 1543 */ 1544 @BeanTagAttribute(name = "breadcrumbTitleDisplayOption") 1545 public String getBreadcrumbTitleDisplayOption() { 1546 return this.breadcrumbTitleDisplayOption; 1547 } 1548 1549 /** 1550 * Setter for the append option 1551 * 1552 * @param breadcrumbTitleDisplayOption the appendOption to set 1553 */ 1554 public void setBreadcrumbTitleDisplayOption(String breadcrumbTitleDisplayOption) { 1555 this.breadcrumbTitleDisplayOption = breadcrumbTitleDisplayOption; 1556 } 1557 1558 /** 1559 * Indicates whether the view allows read only fields to be specified on the request URL which will 1560 * override the view setting 1561 * 1562 * <p> 1563 * If enabled, the readOnlyFields request parameter can be sent to indicate fields that should be set read only 1564 * </p> 1565 * 1566 * @return boolean true if read only request overrides are allowed, false if not 1567 */ 1568 @BeanTagAttribute(name = "supportsRequestOverrideOfReadOnlyFields") 1569 public boolean isSupportsRequestOverrideOfReadOnlyFields() { 1570 return supportsRequestOverrideOfReadOnlyFields; 1571 } 1572 1573 /** 1574 * Setter for the the read only field override indicator 1575 * 1576 * @param supportsRequestOverrideOfReadOnlyFields 1577 */ 1578 public void setSupportsRequestOverrideOfReadOnlyFields(boolean supportsRequestOverrideOfReadOnlyFields) { 1579 this.supportsRequestOverrideOfReadOnlyFields = supportsRequestOverrideOfReadOnlyFields; 1580 } 1581 1582 /** 1583 * Script that is executed at the beginning of page load (before any other script) 1584 * 1585 * <p> 1586 * Many used to set server variables client side 1587 * </p> 1588 * 1589 * @return String pre load script 1590 */ 1591 @BeanTagAttribute(name = "preLoadScript") 1592 public String getPreLoadScript() { 1593 return preLoadScript; 1594 } 1595 1596 /** 1597 * Setter for the pre load script 1598 * 1599 * @param preLoadScript 1600 */ 1601 public void setPreLoadScript(String preLoadScript) { 1602 this.preLoadScript = preLoadScript; 1603 } 1604 1605 /** 1606 * The theme which contains stylesheets for this view 1607 * 1608 * @return ViewTheme 1609 */ 1610 @BeanTagAttribute(name = "theme", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1611 public ViewTheme getTheme() { 1612 return theme; 1613 } 1614 1615 /** 1616 * Setter for The theme which contains stylesheets for this view 1617 * 1618 * @return 1619 */ 1620 public void setTheme(ViewTheme theme) { 1621 this.theme = theme; 1622 } 1623 1624 /** 1625 * The stateObject's binding path, this will be used along with the StateMapping's statePropertyName to 1626 * determine what field in the model state information is stored in for this view. Used during View validation. 1627 * 1628 * @return stateObjectBindingPath path to the object storing state information 1629 */ 1630 @BeanTagAttribute(name = "stateObjectBindingPath") 1631 public String getStateObjectBindingPath() { 1632 return stateObjectBindingPath; 1633 } 1634 1635 /** 1636 * The stateObject's binding path, this will be used along with the StateMapping's statePropertyName to 1637 * determine what field in the model state information is stored in for this view. Used during View validation. 1638 * 1639 * @param stateObjectBindingPath 1640 */ 1641 public void setStateObjectBindingPath(String stateObjectBindingPath) { 1642 this.stateObjectBindingPath = stateObjectBindingPath; 1643 } 1644 1645 /** 1646 * Gets the stateMapping. 1647 * 1648 * <p>The state mapping object is used to determine the state information for a view, 1649 * it must include an ordered list of states, and where to find the state information for the view. 1650 * A stateMapping must be set for state based validation to occur. When stateMapping information is 1651 * not included, the view's model is considered stateless and all constraints will apply regardless of their 1652 * state information or replacements (ie, they will function as they did in version 2.1).</p> 1653 * 1654 * @return StateMapping information needed for state based validation, if null no state based validation 1655 * functionality 1656 * will exist and configured constraints will apply regardless of state 1657 * @since 2.2 1658 */ 1659 @BeanTagAttribute(name = "stateMapping", type = BeanTagAttribute.AttributeType.SINGLEBEAN) 1660 public StateMapping getStateMapping() { 1661 return stateMapping; 1662 } 1663 1664 /** 1665 * Set the stateMapping 1666 * 1667 * @param stateMapping 1668 */ 1669 public void setStateMapping(StateMapping stateMapping) { 1670 this.stateMapping = stateMapping; 1671 } 1672 1673 /** 1674 * @see org.kuali.rice.krad.uif.component.Component#completeValidation 1675 */ 1676 @Override 1677 public void completeValidation(ValidationTrace tracer) { 1678 tracer.addBean(this); 1679 1680 // Check for the presence of a valid item with an not-null EntryPageId 1681 boolean validPageId = false; 1682 if (getEntryPageId() != null) { 1683 for (int i = 0; i < getItems().size(); i++) { 1684 if (getEntryPageId().compareTo(getItems().get(i).getId()) == 0) { 1685 validPageId = true; 1686 } 1687 } 1688 } else { 1689 validPageId = true; 1690 } 1691 if (!validPageId) { 1692 String currentValues[] = {"entryPageId = " + getEntryPageId()}; 1693 tracer.createError("Items must contain an item with a matching id to entryPageId", currentValues); 1694 } 1695 1696 // Check to insure the view as not already been set 1697 if (tracer.getValidationStage() == ValidationTrace.START_UP) { 1698 if (getViewStatus().compareTo(UifConstants.ViewStatus.CREATED) != 0) { 1699 String currentValues[] = {"viewStatus = " + getViewStatus()}; 1700 tracer.createError("ViewStatus should not be set", currentValues); 1701 } 1702 } 1703 1704 // Check to insure the binding object path is a valid property 1705 boolean validDefaultBindingObjectPath = false; 1706 if (getDefaultBindingObjectPath() == null) { 1707 validDefaultBindingObjectPath = true; 1708 } else if (DataDictionary.isPropertyOf(getFormClass(), getDefaultBindingObjectPath())) { 1709 validDefaultBindingObjectPath = true; 1710 } 1711 if (!validDefaultBindingObjectPath) { 1712 String currentValues[] = 1713 {"formClass = " + getFormClass(), "defaultBindingPath = " + getDefaultBindingObjectPath()}; 1714 tracer.createError("DefaultBingdingObjectPath must be a valid property of the formClass", currentValues); 1715 } 1716 1717 // Check to insure the page is set if the view is a single page 1718 if (isSinglePageView()) { 1719 if (getPage() == null) { 1720 String currentValues[] = {"singlePageView = " + isSinglePageView(), "page = " + getPage()}; 1721 tracer.createError("Page must be set if singlePageView is true", currentValues); 1722 } 1723 for (int i = 0; i < getItems().size(); i++) { 1724 if (getItems().get(i).getClass() == PageGroup.class) { 1725 String currentValues[] = 1726 {"singlePageView = " + isSinglePageView(), "items(" + i + ") = " + getItems().get(i) 1727 .getClass()}; 1728 tracer.createError("Items cannot be pageGroups if singlePageView is true", currentValues); 1729 } 1730 } 1731 } 1732 1733 // Checks to insure the Growls are set if growl messaging is enabled 1734 if (isGrowlMessagingEnabled() == true && getGrowls() == null) { 1735 if (Validator.checkExpressions(this, "growls")) { 1736 String currentValues[] = 1737 {"growlMessagingEnabled = " + isGrowlMessagingEnabled(), "growls = " + getGrowls()}; 1738 tracer.createError("Growls cannot be null if Growl Messaging is enabled", currentValues); 1739 } 1740 } 1741 1742 // Checks that there are items present if the view is not a single page 1743 if (!isSinglePageView()) { 1744 if (getItems().size() == 0) { 1745 String currentValues[] = 1746 {"singlePageView = " + isSinglePageView(), "items.size = " + getItems().size()}; 1747 tracer.createWarning("Items cannot be empty if singlePageView is false", currentValues); 1748 } else { 1749 for (int i = 0; i < getItems().size(); i++) { 1750 if (getItems().get(i).getClass() != PageGroup.class) { 1751 String currentValues[] = 1752 {"singlePageView = " + isSinglePageView(), "items(" + i + ") = " + getItems().get(i) 1753 .getClass()}; 1754 tracer.createError("Items must be pageGroups if singlePageView is false", currentValues); 1755 } 1756 } 1757 } 1758 } 1759 super.completeValidation(tracer.getCopy()); 1760 } 1761 1762 }