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