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