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