View Javadoc

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