View Javadoc

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 }