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