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