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