1 /** 2 * Copyright 2005-2015 The Kuali Foundation 3 * 4 * Licensed under the Educational Community License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.opensource.org/licenses/ecl2.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.kuali.rice.krad.uif.view; 17 18 import org.apache.commons.lang.StringUtils; 19 import org.kuali.rice.krad.uif.UifConstants; 20 import org.kuali.rice.krad.uif.UifConstants.ViewStatus; 21 import org.kuali.rice.krad.uif.UifConstants.ViewType; 22 import org.kuali.rice.krad.uif.container.Container; 23 import org.kuali.rice.krad.uif.container.ContainerBase; 24 import org.kuali.rice.krad.uif.container.Group; 25 import org.kuali.rice.krad.uif.container.NavigationGroup; 26 import org.kuali.rice.krad.uif.container.PageGroup; 27 import org.kuali.rice.krad.uif.component.Component; 28 import org.kuali.rice.krad.uif.component.ReferenceCopy; 29 import org.kuali.rice.krad.uif.component.RequestParameter; 30 import org.kuali.rice.krad.uif.field.HeaderField; 31 import org.kuali.rice.krad.uif.field.LinkField; 32 import org.kuali.rice.krad.uif.layout.LayoutManager; 33 import org.kuali.rice.krad.uif.service.ViewHelperService; 34 import org.kuali.rice.krad.uif.util.BooleanMap; 35 import org.kuali.rice.krad.uif.util.ClientValidationUtils; 36 import org.kuali.rice.krad.uif.widget.BreadCrumbs; 37 import org.kuali.rice.krad.uif.widget.Growls; 38 import org.kuali.rice.krad.util.ObjectUtils; 39 import org.kuali.rice.krad.web.form.UifFormBase; 40 41 import java.util.ArrayList; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Set; 47 48 /** 49 * Root of the component tree which encompasses a set of related 50 * <code>GroupContainer</code> instances tied together with a common page layout 51 * and navigation. 52 * 53 * <p> 54 * The <code>View</code> component ties together all the components and 55 * configuration of the User Interface for a piece of functionality. In Rice 56 * applications the view is typically associated with a <code>Document</code> 57 * instance. 58 * </p> 59 * 60 * <p> 61 * The view template lays out the common header, footer, and navigation for the 62 * related pages. In addition the view renders the HTML head element bringing in 63 * common script files and style sheets, along with optionally rendering a form 64 * element for pages that need to post data back to the server. 65 * </p> 66 * 67 * <p> 68 * Configuration of UIF features such as model validation is also done through 69 * the <code>View</code> 70 * </p> 71 * 72 * @author Kuali Rice Team (rice.collab@kuali.org) 73 */ 74 public class View extends ContainerBase { 75 private static final long serialVersionUID = -1220009725554576953L; 76 77 private String viewNamespaceCode; 78 private String viewName; 79 private ViewTheme theme; 80 81 private int idSequence; 82 83 // application 84 private HeaderField applicationHeader; 85 private Group applicationFooter; 86 87 // Breadcrumbs 88 private BreadCrumbs breadcrumbs; 89 private String viewLabelFieldPropertyName; 90 private String appendOption; 91 private boolean breadcrumbsInApplicationHeader; 92 93 // Growls support 94 private Growls growls; 95 private boolean growlMessagingEnabled; 96 97 private String entryPageId; 98 99 @RequestParameter 100 private String currentPageId; 101 102 private NavigationGroup navigation; 103 104 private Class<?> formClass; 105 private String defaultBindingObjectPath; 106 private Map<String, Class<?>> abstractTypeClasses; 107 108 private List<String> additionalScriptFiles; 109 private List<String> additionalCssFiles; 110 111 private ViewType viewTypeName; 112 private Class<? extends ViewHelperService> viewHelperServiceClassName; 113 114 private String viewStatus; 115 private ViewIndex viewIndex; 116 private Map<String, String> viewRequestParameters; 117 118 private ViewPresentationController presentationController; 119 private ViewAuthorizer authorizer; 120 121 private BooleanMap actionFlags; 122 private BooleanMap editModes; 123 124 private Map<String, String> expressionVariables; 125 126 private boolean singlePageView; 127 private PageGroup page; 128 129 private List<? extends Group> items; 130 131 private LinkField viewMenuLink; 132 private String viewMenuGrouping; 133 134 private boolean validateDirty; 135 private boolean translateCodes; 136 private String preLoadScript; 137 private Map<String, Object> clientSideState; 138 139 private boolean supportsReadOnlyFieldsOverride; 140 141 @RequestParameter 142 private boolean dialogMode; 143 144 @ReferenceCopy 145 private ViewHelperService viewHelperService; 146 147 public View() { 148 dialogMode = false; 149 singlePageView = false; 150 translateCodes = false; 151 viewTypeName = ViewType.DEFAULT; 152 viewStatus = UifConstants.ViewStatus.CREATED; 153 formClass = UifFormBase.class; 154 breadcrumbsInApplicationHeader = false; 155 supportsReadOnlyFieldsOverride = true; 156 157 idSequence = 0; 158 this.viewIndex = new ViewIndex(); 159 160 additionalScriptFiles = new ArrayList<String>(); 161 additionalCssFiles = new ArrayList<String>(); 162 items = new ArrayList<Group>(); 163 abstractTypeClasses = new HashMap<String, Class<?>>(); 164 viewRequestParameters = new HashMap<String, String>(); 165 expressionVariables = new HashMap<String, String>(); 166 clientSideState = new HashMap<String, Object>(); 167 } 168 169 /** 170 * The following initialization is performed: 171 * 172 * <ul> 173 * <li>If a single paged view, set items in page group and put the page in 174 * the items list</li> 175 * </ul> 176 * 177 * @see org.kuali.rice.krad.uif.container.ContainerBase#performInitialization(View, java.lang.Object) 178 */ 179 @SuppressWarnings("unchecked") 180 @Override 181 public void performInitialization(View view, Object model) { 182 super.performInitialization(view, model); 183 184 // populate items on page for single paged view 185 if (singlePageView) { 186 if (page != null) { 187 page.setItems(new ArrayList<Group>(items)); 188 189 // reset the items list to include the one page 190 items = new ArrayList<Group>(); 191 ((List<Group>) items).add(page); 192 } else { 193 throw new RuntimeException("For single paged views the page Group must be set."); 194 } 195 } 196 197 // make sure all the pages have ids before selecting the current page 198 for (Group group : this.getItems()) { 199 if (StringUtils.isBlank(group.getId())) { 200 group.setId(view.getNextId()); 201 } 202 } 203 } 204 205 /** 206 * The following is performed: 207 * 208 * <ul> 209 * <li>Adds to its document ready script the setupValidator js function for setting 210 * up the validator for this view</li> 211 * </ul> 212 * 213 * @see org.kuali.rice.krad.uif.container.ContainerBase#performFinalize(View, 214 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 215 */ 216 @Override 217 public void performFinalize(View view, Object model, Component parent) { 218 super.performFinalize(view, model, parent); 219 220 String prefixScript = ""; 221 if (this.getOnDocumentReadyScript() != null) { 222 prefixScript = this.getPreLoadScript(); 223 } 224 225 String growlScript = ""; 226 Growls gw = view.getGrowls(); 227 if (!gw.getComponentOptions().isEmpty()) { 228 growlScript = "setGrowlDefaults(" + gw.getComponentOptionsJSString() + ");"; 229 } 230 231 this.setPreLoadScript(prefixScript + growlScript); 232 233 prefixScript = ""; 234 if (this.getOnDocumentReadyScript() != null) { 235 prefixScript = this.getOnDocumentReadyScript(); 236 } 237 238 this.setOnDocumentReadyScript(prefixScript + "jQuery.extend(jQuery.validator.messages, " + 239 ClientValidationUtils.generateValidatorMessagesOption() + ");"); 240 } 241 242 /** 243 * Assigns an id to the component if one was not configured 244 * 245 * @param component - component instance to assign id to 246 */ 247 public void assignComponentIds(Component component) { 248 if (component == null) { 249 return; 250 } 251 252 Integer currentSequenceVal = idSequence; 253 254 // assign ID if necessary 255 if (StringUtils.isBlank(component.getId())) { 256 component.setId(UifConstants.COMPONENT_ID_PREFIX + getNextId()); 257 } 258 259 // capture current sequence value for component refreshes 260 getViewIndex().addSequenceValueToSnapshot(component.getId(), currentSequenceVal); 261 262 if (component instanceof Container) { 263 LayoutManager layoutManager = ((Container) component).getLayoutManager(); 264 if ((layoutManager != null) && StringUtils.isBlank(layoutManager.getId())) { 265 layoutManager.setId(UifConstants.COMPONENT_ID_PREFIX + getNextId()); 266 } 267 } 268 269 // check if component has already been initialized to prevent cyclic references 270 // TODO: move to VHS initialize 271 // if (initializedComponentIds.contains(component.getId())) { 272 // throw new RiceRuntimeException( 273 // "Circular reference or duplicate id found for component with id: " + component.getId()); 274 // } 275 // initializedComponentIds.add(component.getId()); 276 277 // assign id to nested components 278 List<Component> allNested = new ArrayList<Component>(component.getComponentsForLifecycle()); 279 allNested.addAll(component.getComponentPrototypes()); 280 for (Component nestedComponent : allNested) { 281 assignComponentIds(nestedComponent); 282 } 283 } 284 285 /** 286 * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle() 287 */ 288 @Override 289 public List<Component> getComponentsForLifecycle() { 290 List<Component> components = super.getComponentsForLifecycle(); 291 292 components.add(applicationHeader); 293 components.add(applicationFooter); 294 components.add(navigation); 295 components.add(breadcrumbs); 296 components.add(growls); 297 components.add(viewMenuLink); 298 299 // remove all pages that are not the current page 300 if (!singlePageView) { 301 for (Group group : this.getItems()) { 302 if ((group instanceof PageGroup) && !StringUtils.equals(group.getId(), getCurrentPageId()) && components 303 .contains(group)) { 304 components.remove(group); 305 } 306 } 307 } 308 309 return components; 310 } 311 312 /** 313 * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes() 314 */ 315 @Override 316 public List<Component> getComponentPrototypes() { 317 List<Component> components = super.getComponentPrototypes(); 318 319 components.add(page); 320 321 return components; 322 } 323 324 /** 325 * @see org.kuali.rice.krad.uif.container.Container#getSupportedComponents() 326 */ 327 @Override 328 public Set<Class<? extends Component>> getSupportedComponents() { 329 Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>(); 330 supportedComponents.add(Group.class); 331 332 return supportedComponents; 333 } 334 335 /** 336 * @see org.kuali.rice.krad.uif.component.Component#getComponentTypeName() 337 */ 338 @Override 339 public String getComponentTypeName() { 340 return "view"; 341 } 342 343 /** 344 * Iterates through the contained page items and returns the Page that 345 * matches the set current page id 346 * 347 * @return Page instance 348 */ 349 public PageGroup getCurrentPage() { 350 for (Group pageGroup : this.getItems()) { 351 if (StringUtils.equals(pageGroup.getId(), getCurrentPageId()) && pageGroup instanceof PageGroup) { 352 return (PageGroup) pageGroup; 353 } 354 } 355 356 return null; 357 } 358 359 /** 360 * Namespace code the view should be associated with 361 * 362 * <p> 363 * The namespace code is used within the framework in such places as permission checks and parameter 364 * retrieval 365 * </p> 366 * 367 * @return String namespace code 368 */ 369 public String getViewNamespaceCode() { 370 return viewNamespaceCode; 371 } 372 373 /** 374 * Setter for the view's namespace code 375 * 376 * @param viewNamespaceCode 377 */ 378 public void setViewNamespaceCode(String viewNamespaceCode) { 379 this.viewNamespaceCode = viewNamespaceCode; 380 } 381 382 /** 383 * View name provides an identifier for a view within a type. That is if a 384 * set of <code>View</code> instances have the same values for the 385 * properties that are used to retrieve them by their type, the name can be 386 * given to further qualify the view that should be retrieved. 387 * <p> 388 * A view type like the <code>LookupView</code> might have several views for 389 * the same object class, but one that is the 'default' lookup and another 390 * that is the 'advanced' lookup. Therefore the name on the first could be 391 * set to 'default', and likewise the name for the second 'advanced'. 392 * </p> 393 * 394 * @return String name of view 395 */ 396 public String getViewName() { 397 return this.viewName; 398 } 399 400 /** 401 * Setter for the view's name 402 * 403 * @param viewName 404 */ 405 public void setViewName(String viewName) { 406 this.viewName = viewName; 407 } 408 409 /** 410 * Header for the application containing the view 411 * 412 * <p> 413 * When deploying outside a portal, the application header and footer property can be configured to 414 * display a consistent header/footer across all views. Here application logos, menus, login controls 415 * and so on can be rendered. 416 * </p> 417 * 418 * @return HeaderField application header 419 */ 420 public HeaderField getApplicationHeader() { 421 return applicationHeader; 422 } 423 424 /** 425 * Setter for the application header 426 * 427 * @param applicationHeader 428 */ 429 public void setApplicationHeader(HeaderField applicationHeader) { 430 this.applicationHeader = applicationHeader; 431 } 432 433 /** 434 * Footer for the application containing the view 435 * 436 * <p> 437 * When deploying outside a portal, the application header and footer property can be configured to 438 * display a consistent header/footer across all views. Here such things as application links, copyrights 439 * and so on can be rendered. 440 * </p> 441 * 442 * @return Group application footer 443 */ 444 public Group getApplicationFooter() { 445 return applicationFooter; 446 } 447 448 /** 449 * Setter for the application footer 450 * 451 * @param applicationFooter 452 */ 453 public void setApplicationFooter(Group applicationFooter) { 454 this.applicationFooter = applicationFooter; 455 } 456 457 /** 458 * Current sequence value for id assignment 459 * 460 * @return int id sequence 461 */ 462 public int getIdSequence() { 463 return idSequence; 464 } 465 466 /** 467 * Setter for the current id sequence value 468 * 469 * @param idSequence 470 */ 471 public void setIdSequence(int idSequence) { 472 this.idSequence = idSequence; 473 } 474 475 /** 476 * Returns the next unique id available for components within the view instance 477 * 478 * @return String next id available 479 */ 480 public String getNextId() { 481 idSequence += 1; 482 return Integer.toString(idSequence); 483 } 484 485 /** 486 * Specifies what page should be rendered by default. This is the page that 487 * will be rendered when the <code>View</code> is first rendered or when the 488 * current page is not set 489 * 490 * @return String id of the page to render by default 491 */ 492 public String getEntryPageId() { 493 return this.entryPageId; 494 } 495 496 /** 497 * Setter for default Page id 498 * 499 * @param entryPageId 500 */ 501 public void setEntryPageId(String entryPageId) { 502 this.entryPageId = entryPageId; 503 } 504 505 /** 506 * The id for the page within the view that should be displayed in the UI. 507 * Other pages of the view will not be rendered 508 * 509 * <p> 510 * If current page id is not set, it is set to the configured entry page or first item in list id 511 * </p> 512 * 513 * @return String id of the page that should be displayed 514 */ 515 public String getCurrentPageId() { 516 // default current page if not set 517 if (StringUtils.isBlank(currentPageId)) { 518 if (StringUtils.isNotBlank(entryPageId)) { 519 currentPageId = entryPageId; 520 } else if ((getItems() != null) && !getItems().isEmpty()) { 521 Group firstPageGroup = getItems().get(0); 522 currentPageId = firstPageGroup.getId(); 523 } 524 } 525 526 return this.currentPageId; 527 } 528 529 /** 530 * Setter for the page id to display 531 * 532 * @param currentPageId 533 */ 534 public void setCurrentPageId(String currentPageId) { 535 this.currentPageId = currentPageId; 536 } 537 538 /** 539 * <code>NavigationGroup</code> instance for the <code>View</code> 540 * <p> 541 * Provides configuration necessary to render the navigation. This includes 542 * navigation items in addition to configuration for the navigation 543 * renderer. 544 * </p> 545 * 546 * @return NavigationGroup 547 */ 548 public NavigationGroup getNavigation() { 549 return this.navigation; 550 } 551 552 /** 553 * Setter for the View's <code>NavigationGroup</code> 554 * 555 * @param navigation 556 */ 557 public void setNavigation(NavigationGroup navigation) { 558 this.navigation = navigation; 559 } 560 561 /** 562 * Class of the Form that should be used with the <code>View</code> 563 * instance. The form is the top level object for all the view's data and is 564 * used to present and accept data in the user interface. All form classes 565 * should extend UifFormBase 566 * 567 * @return Class<?> class for the view's form 568 * @see org.kuali.rice.krad.web.form.UifFormBase 569 */ 570 public Class<?> getFormClass() { 571 return this.formClass; 572 } 573 574 /** 575 * Setter for the form class 576 * 577 * @param formClass 578 */ 579 public void setFormClass(Class<?> formClass) { 580 this.formClass = formClass; 581 } 582 583 /** 584 * For <code>View</code> types that work primarily with one nested object of 585 * the form (for instance document, or bo) the default binding object path 586 * can be set for each of the views <code>DataBinding</code> components. If 587 * the component does not set its own binding object path it will inherit 588 * the default 589 * 590 * @return String binding path to the object from the form 591 */ 592 public String getDefaultBindingObjectPath() { 593 return this.defaultBindingObjectPath; 594 } 595 596 /** 597 * Setter for the default binding object path to use for the view 598 * 599 * @param defaultBindingObjectPath 600 */ 601 public void setDefaultBindingObjectPath(String defaultBindingObjectPath) { 602 this.defaultBindingObjectPath = defaultBindingObjectPath; 603 } 604 605 /** 606 * Configures the concrete classes that will be used for properties in the 607 * form object graph that have an abstract or interface type 608 * 609 * <p> 610 * For properties that have an abstract or interface type, it is not 611 * possible to perform operations like getting/settings property values and 612 * getting information from the dictionary. When these properties are 613 * encountered in the object graph, this <code>Map</code> will be consulted 614 * to determine the concrete type to use. 615 * </p> 616 * 617 * <p> 618 * e.g. Suppose we have a property document.accountingLine.accountNumber and 619 * the accountingLine property on the document instance has an interface 620 * type 'AccountingLine'. We can then put an entry into this map with key 621 * 'document.accountingLine', and value 622 * 'org.kuali.rice.sampleapp.TravelAccountingLine'. When getting the 623 * property type or an entry from the dictionary for accountNumber, the 624 * TravelAccountingLine class will be used. 625 * </p> 626 * 627 * @return Map<String, Class> of class implementations keyed by path 628 */ 629 public Map<String, Class<?>> getAbstractTypeClasses() { 630 return this.abstractTypeClasses; 631 } 632 633 /** 634 * Setter for the Map of class implementations keyed by path 635 * 636 * @param abstractTypeClasses 637 */ 638 public void setAbstractTypeClasses(Map<String, Class<?>> abstractTypeClasses) { 639 this.abstractTypeClasses = abstractTypeClasses; 640 } 641 642 /** 643 * Declares additional script files that should be included with the 644 * <code>View</code>. These files are brought into the HTML page along with 645 * common script files configured for the Rice application. Each entry 646 * contain the path to the CSS file, either a relative path, path from web 647 * root, or full URI 648 * <p> 649 * e.g. '/krad/scripts/myScript.js', '../scripts/myScript.js', 650 * 'http://my.edu/web/myScript.js' 651 * </p> 652 * 653 * @return List<String> script file locations 654 */ 655 public List<String> getAdditionalScriptFiles() { 656 return this.additionalScriptFiles; 657 } 658 659 /** 660 * Setter for the List of additional script files to included with the 661 * <code>View</code> 662 * 663 * @param additionalScriptFiles 664 */ 665 public void setAdditionalScriptFiles(List<String> additionalScriptFiles) { 666 this.additionalScriptFiles = additionalScriptFiles; 667 } 668 669 /** 670 * Declares additional CSS files that should be included with the 671 * <code>View</code>. These files are brought into the HTML page along with 672 * common CSS files configured for the Rice application. Each entry should 673 * contain the path to the CSS file, either a relative path, path from web 674 * root, or full URI 675 * <p> 676 * e.g. '/krad/css/stacked-view.css', '../css/stacked-view.css', 677 * 'http://my.edu/web/stacked-view.css' 678 * </p> 679 * 680 * @return List<String> CSS file locations 681 */ 682 public List<String> getAdditionalCssFiles() { 683 return this.additionalCssFiles; 684 } 685 686 /** 687 * Setter for the List of additional CSS files to included with the 688 * <code>View</code> 689 * 690 * @param additionalCssFiles 691 */ 692 public void setAdditionalCssFiles(List<String> additionalCssFiles) { 693 this.additionalCssFiles = additionalCssFiles; 694 } 695 696 public boolean isDialogMode() { 697 return this.dialogMode; 698 } 699 700 public void setDialogMode(boolean dialogMode) { 701 this.dialogMode = dialogMode; 702 } 703 704 /** 705 * View type name the view is associated with the view instance 706 * 707 * <p> 708 * Views that share common features and functionality can be grouped by the 709 * view type. Usually view types extend the <code>View</code> class to 710 * provide additional configuration and to set defaults. View types can also 711 * implement the <code>ViewTypeService</code> to add special indexing and 712 * retrieval of views. 713 * </p> 714 * 715 * @return String view type name for the view 716 */ 717 public ViewType getViewTypeName() { 718 return this.viewTypeName; 719 } 720 721 /** 722 * Setter for the view's type name 723 * 724 * @param viewTypeName 725 */ 726 public void setViewTypeName(ViewType viewTypeName) { 727 this.viewTypeName = viewTypeName; 728 } 729 730 /** 731 * Class name of the <code>ViewHelperService</code> that handles the various 732 * phases of the Views lifecycle 733 * 734 * @return Class for the spring bean 735 * @see org.kuali.rice.krad.uif.service.ViewHelperService 736 */ 737 public Class<? extends ViewHelperService> getViewHelperServiceClassName() { 738 return this.viewHelperServiceClassName; 739 } 740 741 /** 742 * Setter for the <code>ViewHelperService</code> class name 743 * 744 * @param viewHelperServiceClassName 745 */ 746 public void setViewHelperServiceClassName(Class<? extends ViewHelperService> viewHelperServiceClassName) { 747 this.viewHelperServiceClassName = viewHelperServiceClassName; 748 } 749 750 /** 751 * Creates the <code>ViewHelperService</code> associated with the View 752 * 753 * @return ViewHelperService instance 754 */ 755 public ViewHelperService getViewHelperService() { 756 if (this.viewHelperService == null) { 757 viewHelperService = ObjectUtils.newInstance(viewHelperServiceClassName); 758 } 759 760 return viewHelperService; 761 } 762 763 /** 764 * Invoked to produce a ViewIndex of the current view's components 765 */ 766 public void index() { 767 if (this.viewIndex == null) { 768 this.viewIndex = new ViewIndex(); 769 } 770 this.viewIndex.index(this); 771 } 772 773 /** 774 * Holds field indexes of the <code>View</code> instance for retrieval 775 * 776 * @return ViewIndex instance 777 */ 778 public ViewIndex getViewIndex() { 779 return this.viewIndex; 780 } 781 782 /** 783 * Map of parameters from the request that set view options, used to rebuild 784 * the view on each post 785 * <p> 786 * Views can be configured by parameters. These might impact which parts of 787 * the view are rendered or how the view behaves. Generally these would get 788 * passed in when a new view is requested (by request parameters). These 789 * will be used to initially populate the view properties. In addition, on a 790 * post the view will be rebuilt and properties reset again by the allow 791 * request parameters. 792 * </p> 793 * <p> 794 * Example parameter would be for MaintenaceView whether a New, Edit, or 795 * Copy was requested (maintenance mode) 796 * </p> 797 * 798 * @return 799 */ 800 public Map<String, String> getViewRequestParameters() { 801 return this.viewRequestParameters; 802 } 803 804 /** 805 * Setter for the view's request parameters map 806 * 807 * @param viewRequestParameters 808 */ 809 public void setViewRequestParameters(Map<String, String> viewRequestParameters) { 810 this.viewRequestParameters = viewRequestParameters; 811 } 812 813 /** 814 * PresentationController that should be used for the <code>View</code> instance 815 * 816 * <p> 817 * The presentation controller is consulted to determine component (group, 818 * field) state such as required, read-only, and hidden. The presentation 819 * controller does not take into account user permissions. The presentation 820 * controller can also output action flags and edit modes that will be set 821 * onto the view instance and can be referred to by conditional expressions 822 * </p> 823 * 824 * @return PresentationController 825 */ 826 public ViewPresentationController getPresentationController() { 827 return this.presentationController; 828 } 829 830 /** 831 * Setter for the view's presentation controller 832 * 833 * @param presentationController 834 */ 835 public void setPresentationController(ViewPresentationController presentationController) { 836 this.presentationController = presentationController; 837 } 838 839 /** 840 * Setter for the view's presentation controller by class 841 * 842 * @param presentationControllerClass 843 */ 844 public void setPresentationControllerClass( 845 Class<? extends ViewPresentationController> presentationControllerClass) { 846 this.presentationController = ObjectUtils.newInstance(presentationControllerClass); 847 } 848 849 /** 850 * Authorizer that should be used for the <code>View</code> instance 851 * 852 * <p> 853 * The authorizer class is consulted to determine component (group, field) 854 * state such as required, read-only, and hidden based on the users 855 * permissions. It typically communicates with the Kuali Identity Management 856 * system to determine roles and permissions. It is used with the 857 * presentation controller and dictionary conditional logic to determine the 858 * final component state. The authorizer can also output action flags and 859 * edit modes that will be set onto the view instance and can be referred to 860 * by conditional expressions 861 * </p> 862 * 863 * @return Authorizer 864 */ 865 public ViewAuthorizer getAuthorizer() { 866 return this.authorizer; 867 } 868 869 /** 870 * Setter for the view's authorizer 871 * 872 * @param authorizer 873 */ 874 public void setAuthorizer(ViewAuthorizer authorizer) { 875 this.authorizer = authorizer; 876 } 877 878 /** 879 * Setter for the view's authorizer by class 880 * 881 * @param authorizerClass 882 */ 883 public void setAuthorizerClass(Class<? extends ViewAuthorizer> authorizerClass) { 884 this.authorizer = ObjectUtils.newInstance(authorizerClass); 885 } 886 887 /** 888 * Map of strings that flag what actions can be taken in the UI 889 * <p> 890 * These can be used in conditional expressions in the dictionary or by 891 * other UI logic 892 * </p> 893 * 894 * @return BooleanMap action flags 895 */ 896 public BooleanMap getActionFlags() { 897 return this.actionFlags; 898 } 899 900 /** 901 * Setter for the action flags Map 902 * 903 * @param actionFlags 904 */ 905 public void setActionFlags(BooleanMap actionFlags) { 906 this.actionFlags = actionFlags; 907 } 908 909 /** 910 * Map of edit modes that enabled for the view 911 * <p> 912 * These can be used in conditional expressions in the dictionary or by 913 * other UI logic 914 * </p> 915 * 916 * @return BooleanMap edit modes 917 */ 918 public BooleanMap getEditModes() { 919 return this.editModes; 920 } 921 922 /** 923 * Setter for the edit modes Map 924 * 925 * @param editModes 926 */ 927 public void setEditModes(BooleanMap editModes) { 928 this.editModes = editModes; 929 } 930 931 /** 932 * Map that contains expressions to evaluate and make available as variables 933 * for conditional expressions within the view 934 * <p> 935 * Each Map entry contains one expression variables, where the map key gives 936 * the name for the variable, and the map value gives the variable 937 * expression. The variables expressions will be evaluated before 938 * conditional logic is run and made available as variables for other 939 * conditional expressions. Variable expressions can be based on the model 940 * and any object contained in the view's context 941 * </p> 942 * 943 * @return Map<String, String> variable expressions 944 */ 945 public Map<String, String> getExpressionVariables() { 946 return this.expressionVariables; 947 } 948 949 /** 950 * Setter for the view's map of variable expressions 951 * 952 * @param expressionVariables 953 */ 954 public void setExpressionVariables(Map<String, String> expressionVariables) { 955 this.expressionVariables = expressionVariables; 956 } 957 958 /** 959 * Indicates whether the <code>View</code> only has a single page 960 * <code>Group</code> or contains multiple page <code>Group</code> 961 * instances. In the case of a single page it is assumed the group's items 962 * list contains the section groups for the page, and the page itself is 963 * given by the page property ({@link #getPage()}. This is for convenience 964 * of configuration and also can drive other configuration like styling. 965 * 966 * @return boolean true if the view only contains one page group, false if 967 * it contains multple pages 968 */ 969 public boolean isSinglePageView() { 970 return this.singlePageView; 971 } 972 973 /** 974 * Setter for the single page indicator 975 * 976 * @param singlePageView 977 */ 978 public void setSinglePageView(boolean singlePageView) { 979 this.singlePageView = singlePageView; 980 } 981 982 /** 983 * For single paged views ({@link #isSinglePageView()}, gives the page 984 * <code>Group</code> the view should render. The actual items for the page 985 * is taken from the group's items list ({@link #getItems()}, and set onto 986 * the give page group. This is for convenience of configuration. 987 * 988 * @return Group page group for single page views 989 */ 990 public PageGroup getPage() { 991 return this.page; 992 } 993 994 /** 995 * Setter for the page group for single page views 996 * 997 * @param page 998 */ 999 public void setPage(PageGroup page) { 1000 this.page = page; 1001 } 1002 1003 /** 1004 * @see org.kuali.rice.krad.uif.container.ContainerBase#getItems() 1005 */ 1006 @Override 1007 public List<? extends Group> getItems() { 1008 return this.items; 1009 } 1010 1011 /** 1012 * Setter for the view's <code>Group</code> instances 1013 * 1014 * @param items 1015 */ 1016 @Override 1017 public void setItems(List<? extends Component> items) { 1018 // TODO: fix this generic issue 1019 this.items = (List<? extends Group>) items; 1020 } 1021 1022 /** 1023 * Provides configuration for displaying a link to the view from an 1024 * application menu 1025 * 1026 * @return LinkField view link field 1027 */ 1028 public LinkField getViewMenuLink() { 1029 return this.viewMenuLink; 1030 } 1031 1032 /** 1033 * Setter for the views link field 1034 * 1035 * @param viewMenuLink 1036 */ 1037 public void setViewMenuLink(LinkField viewMenuLink) { 1038 this.viewMenuLink = viewMenuLink; 1039 } 1040 1041 /** 1042 * Provides a grouping string for the view to group its menu link (within a 1043 * portal for instance) 1044 * 1045 * @return String menu grouping 1046 */ 1047 public String getViewMenuGrouping() { 1048 return this.viewMenuGrouping; 1049 } 1050 1051 /** 1052 * Setter for the views menu grouping 1053 * 1054 * @param viewMenuGrouping 1055 */ 1056 public void setViewMenuGrouping(String viewMenuGrouping) { 1057 this.viewMenuGrouping = viewMenuGrouping; 1058 } 1059 1060 /** 1061 * Indicates what lifecycle phase the View instance is in 1062 * <p> 1063 * The view lifecycle begins with the CREATED status. In this status a new 1064 * instance of the view has been retrieved from the dictionary, but no 1065 * further processing has been done. After the initialize phase has been run 1066 * the status changes to INITIALIZED. After the model has been applied and 1067 * the view is ready for render the status changes to FINAL 1068 * </p> 1069 * 1070 * @return String view status 1071 * @see org.kuali.rice.krad.uif.UifConstants.ViewStatus 1072 */ 1073 public String getViewStatus() { 1074 return this.viewStatus; 1075 } 1076 1077 /** 1078 * Setter for the view status 1079 * 1080 * @param viewStatus 1081 */ 1082 public void setViewStatus(String viewStatus) { 1083 this.viewStatus = viewStatus; 1084 } 1085 1086 /** 1087 * Indicates whether the view has been initialized 1088 * 1089 * @return boolean true if the view has been initialized, false if not 1090 */ 1091 public boolean isInitialized() { 1092 return StringUtils.equals(viewStatus, ViewStatus.INITIALIZED) || 1093 StringUtils.equals(viewStatus, ViewStatus.FINAL); 1094 } 1095 1096 /** 1097 * Indicates whether the view has been updated from the model and final 1098 * updates made 1099 * 1100 * @return boolean true if the view has been updated, false if not 1101 */ 1102 public boolean isFinal() { 1103 return StringUtils.equals(viewStatus, ViewStatus.FINAL); 1104 } 1105 1106 /** 1107 * onSubmit script configured on the <code>View</code> gets placed on the 1108 * form element 1109 * 1110 * @see org.kuali.rice.krad.uif.component.ComponentBase#getSupportsOnSubmit() 1111 */ 1112 @Override 1113 public boolean getSupportsOnSubmit() { 1114 return true; 1115 } 1116 1117 /** 1118 * onLoad script configured on the <code>View</code> gets placed in a load 1119 * call 1120 * 1121 * @see org.kuali.rice.krad.uif.component.ComponentBase#getSupportsOnLoad() 1122 */ 1123 @Override 1124 public boolean getSupportsOnLoad() { 1125 return true; 1126 } 1127 1128 /** 1129 * onDocumentReady script configured on the <code>View</code> gets placed in 1130 * a document ready jQuery block 1131 * 1132 * @see org.kuali.rice.krad.uif.component.ComponentBase#getSupportsOnLoad() 1133 */ 1134 @Override 1135 public boolean getSupportsOnDocumentReady() { 1136 return true; 1137 } 1138 1139 /** 1140 * Breadcrumb widget used for displaying homeward path and history 1141 * 1142 * @return the breadcrumbs 1143 */ 1144 public BreadCrumbs getBreadcrumbs() { 1145 return this.breadcrumbs; 1146 } 1147 1148 /** 1149 * @param breadcrumbs the breadcrumbs to set 1150 */ 1151 public void setBreadcrumbs(BreadCrumbs breadcrumbs) { 1152 this.breadcrumbs = breadcrumbs; 1153 } 1154 1155 /** 1156 * Indicates whether the breadcrumbs are rendered in the application header and should not 1157 * be rendered as part of the view template 1158 * 1159 * <p> 1160 * For layout purposes it is sometimes necessary to render the breadcrumbs in the application header. This flag 1161 * indicates that is being done and therefore should not be rendered in the view template. 1162 * </p> 1163 * 1164 * @return boolean true if breadcrumbs are rendered in the application header, false if not and they should be 1165 * rendered with the view 1166 */ 1167 public boolean isBreadcrumbsInApplicationHeader() { 1168 return breadcrumbsInApplicationHeader; 1169 } 1170 1171 /** 1172 * Setter for the breadcrumbs in application header indicator 1173 * 1174 * @param breadcrumbsInApplicationHeader 1175 */ 1176 public void setBreadcrumbsInApplicationHeader(boolean breadcrumbsInApplicationHeader) { 1177 this.breadcrumbsInApplicationHeader = breadcrumbsInApplicationHeader; 1178 } 1179 1180 /** 1181 * Growls widget which sets up global settings for the growls used in this 1182 * view and its pages 1183 * 1184 * @return the growls 1185 */ 1186 public Growls getGrowls() { 1187 return this.growls; 1188 } 1189 1190 /** 1191 * @param growls the growls to set 1192 */ 1193 public void setGrowls(Growls growls) { 1194 this.growls = growls; 1195 } 1196 1197 /** 1198 * Growls use the messages contained in the message map. If enabled, info 1199 * messages in their entirety will be displayed in growls, for warning and 1200 * error messages a growl message will notify the user that these messages 1201 * exist on the page. If this setting is disabled, it is recommended that 1202 * infoMessage display be enabled for the page ErrorsField bean in order to 1203 * display relevant information to the user. Note: the growl scripts are 1204 * built out in the PageGroup class. 1205 * 1206 * @return the growlMessagingEnabled 1207 */ 1208 public boolean isGrowlMessagingEnabled() { 1209 return this.growlMessagingEnabled; 1210 } 1211 1212 /** 1213 * @param growlMessagingEnabled the growlMessagingEnabled to set 1214 */ 1215 public void setGrowlMessagingEnabled(boolean growlMessagingEnabled) { 1216 this.growlMessagingEnabled = growlMessagingEnabled; 1217 } 1218 1219 /** 1220 * Indicates whether the form should be validated for dirtyness 1221 * 1222 * <p> 1223 * For FormView, it's necessary to validate when the user tries to navigate out of the form. If set, all the 1224 * InputFields will be validated on refresh, navigate, cancel or close Action or on form 1225 * unload and if dirty, displays a message and user can decide whether to continue with 1226 * the action or stay on the form. For lookup and inquiry, it's not needed to validate. 1227 * </p> 1228 * 1229 * @return true if dirty validation is set 1230 */ 1231 public boolean isValidateDirty() { 1232 return this.validateDirty; 1233 } 1234 1235 /** 1236 * Setter for dirty validation. 1237 */ 1238 public void setValidateDirty(boolean validateDirty) { 1239 this.validateDirty = validateDirty; 1240 } 1241 1242 /** 1243 * Indicates whether the Name of the Code should be displayed when a property is of type <code>KualiCode</code> 1244 * 1245 * @param translateCodes - indicates whether <code>KualiCode</code>'s name should be included 1246 */ 1247 public void setTranslateCodes(boolean translateCodes) { 1248 this.translateCodes = translateCodes; 1249 } 1250 1251 /** 1252 * Returns whether the current view supports displaying <code>KualiCode</code>'s name as additional display value 1253 * 1254 * @return true if the current view supports 1255 */ 1256 public boolean isTranslateCodes() { 1257 return translateCodes; 1258 } 1259 1260 /** 1261 * The property name to be used to determine what will be used in the 1262 * breadcrumb title of this view 1263 * 1264 * <p> 1265 * The title can be determined from a combination of this and viewLabelFieldbindingInfo: If only 1266 * viewLabelFieldPropertyName is set, the title we be determined against the 1267 * defaultBindingObjectPath. If only viewLabelFieldbindingInfo is set it 1268 * must provide information about what object(bindToForm or explicit) and 1269 * path to use. If both viewLabelFieldbindingInfo and viewLabelFieldPropertyName are set, 1270 * the bindingInfo will be used with a 1271 * the viewLabelFieldPropertyName as its bindingPath. If neither are set, 1272 * the default title attribute from the dataObject's metadata (determined by the 1273 * defaultBindingObjectPath's object) will be used. 1274 * </p> 1275 * 1276 * @return String property name whose value should be displayed in view label 1277 */ 1278 public String getViewLabelFieldPropertyName() { 1279 return this.viewLabelFieldPropertyName; 1280 } 1281 1282 /** 1283 * Setter for the view label property name 1284 * 1285 * @param viewLabelFieldPropertyName the viewLabelFieldPropertyName to set 1286 */ 1287 public void setViewLabelFieldPropertyName(String viewLabelFieldPropertyName) { 1288 this.viewLabelFieldPropertyName = viewLabelFieldPropertyName; 1289 } 1290 1291 /** 1292 * The option to use when appending the view label on the breadcrumb title. 1293 * Available options: 'dash', 'parenthesis', and 'replace'(don't append - 1294 * simply replace the title). MUST be set for the viewLabelField to be used 1295 * in the breadcrumb, if not set no appendage will be added. 1296 * 1297 * @return the appendOption 1298 */ 1299 public String getAppendOption() { 1300 return this.appendOption; 1301 } 1302 1303 /** 1304 * Setter for the append option 1305 * 1306 * @param appendOption the appendOption to set 1307 */ 1308 public void setAppendOption(String appendOption) { 1309 this.appendOption = appendOption; 1310 } 1311 1312 /** 1313 * Map of key name/value pairs that will be exposed on the client with JavaScript 1314 * 1315 * <p> 1316 * Any state contained in the Map will be in addition to general state added by the 1317 * <code>ViewHelperService</code> and also state generated from the component properties 1318 * annotated with <code>ClientSideState</code>. If this map does contain a key that is 1319 * the same as the generated state, it will override the generated, with the exception 1320 * of keys that refer to component ids and have a nested map as value, which will be merged 1321 * </p> 1322 * 1323 * @return Map<String, Object> contains key name/value pairs to expose on client 1324 */ 1325 public Map<String, Object> getClientSideState() { 1326 return clientSideState; 1327 } 1328 1329 /** 1330 * Setter for the client side state map 1331 * 1332 * @param clientSideState 1333 */ 1334 public void setClientSideState(Map<String, Object> clientSideState) { 1335 this.clientSideState = clientSideState; 1336 } 1337 1338 /** 1339 * Adds a variable name/value pair to the client side state map associated with the given 1340 * component id 1341 * 1342 * @param componentId - id of the component the state is associated with 1343 * @param variableName - name to expose the state as 1344 * @param value - initial value for the variable on the client 1345 */ 1346 public void addToClientSideState(String componentId, String variableName, Object value) { 1347 Map<String, Object> componentClientState = new HashMap<String, Object>(); 1348 1349 // find any existing client state for component 1350 if (clientSideState.containsKey(componentId)) { 1351 Object clientState = clientSideState.get(componentId); 1352 if ((clientState != null) && (clientState instanceof Map)) { 1353 componentClientState = (Map<String, Object>) clientState; 1354 } else { 1355 throw new IllegalArgumentException("Client side state for component: " + componentId + " is not a Map"); 1356 } 1357 } 1358 1359 // add variables to component state and reinsert into view's client state 1360 componentClientState.put(variableName, value); 1361 clientSideState.put(componentId, componentClientState); 1362 } 1363 1364 /** 1365 * Indicates whether the view allows read only fields to be specified on the request URL which will 1366 * override the view setting 1367 * 1368 * <p> 1369 * If enabled, the readOnlyFields request parameter can be sent to indicate fields that should be set read only 1370 * </p> 1371 * 1372 * @return boolean true if read only request overrides are allowed, false if not 1373 */ 1374 public boolean isSupportsReadOnlyFieldsOverride() { 1375 return supportsReadOnlyFieldsOverride; 1376 } 1377 1378 /** 1379 * Setter for the the read only field override indicator 1380 * 1381 * @param supportsReadOnlyFieldsOverride 1382 */ 1383 public void setSupportsReadOnlyFieldsOverride(boolean supportsReadOnlyFieldsOverride) { 1384 this.supportsReadOnlyFieldsOverride = supportsReadOnlyFieldsOverride; 1385 } 1386 1387 /** 1388 * Script that is executed at the beginning of page load (before any other script) 1389 * 1390 * <p> 1391 * Many used to set server variables client side 1392 * </p> 1393 * 1394 * @return String pre load script 1395 */ 1396 public String getPreLoadScript() { 1397 return preLoadScript; 1398 } 1399 1400 /** 1401 * Setter for the pre load script 1402 * 1403 * @param preLoadScript 1404 */ 1405 public void setPreLoadScript(String preLoadScript) { 1406 this.preLoadScript = preLoadScript; 1407 } 1408 1409 /** 1410 * The theme which contains stylesheets for this view 1411 * @return 1412 */ 1413 public ViewTheme getTheme() { 1414 return theme; 1415 } 1416 1417 /** 1418 * Setter for The theme which contains stylesheets for this view 1419 * @return 1420 */ 1421 public void setTheme(ViewTheme theme) { 1422 this.theme = theme; 1423 } 1424 1425 }