View Javadoc

1   /**
2    * Copyright 2005-2014 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.datadictionary.DataDictionary;
20  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
21  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
22  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
23  import org.kuali.rice.krad.datadictionary.state.StateMapping;
24  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
25  import org.kuali.rice.krad.datadictionary.validator.Validator;
26  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
27  import org.kuali.rice.krad.uif.UifConstants;
28  import org.kuali.rice.krad.uif.UifConstants.ViewStatus;
29  import org.kuali.rice.krad.uif.UifConstants.ViewType;
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.container.Container;
34  import org.kuali.rice.krad.uif.container.ContainerBase;
35  import org.kuali.rice.krad.uif.container.Group;
36  import org.kuali.rice.krad.uif.container.NavigationGroup;
37  import org.kuali.rice.krad.uif.container.PageGroup;
38  import org.kuali.rice.krad.uif.element.Header;
39  import org.kuali.rice.krad.uif.element.Link;
40  import org.kuali.rice.krad.uif.layout.LayoutManager;
41  import org.kuali.rice.krad.uif.service.ViewHelperService;
42  import org.kuali.rice.krad.uif.util.BooleanMap;
43  import org.kuali.rice.krad.uif.util.ClientValidationUtils;
44  import org.kuali.rice.krad.uif.widget.BlockUI;
45  import org.kuali.rice.krad.uif.widget.BreadCrumbs;
46  import org.kuali.rice.krad.uif.widget.Growls;
47  import org.kuali.rice.krad.util.ObjectUtils;
48  import org.kuali.rice.krad.web.form.UifFormBase;
49  
50  import java.util.ArrayList;
51  import java.util.HashMap;
52  import java.util.HashSet;
53  import java.util.List;
54  import java.util.Map;
55  import java.util.Set;
56  
57  /**
58   * Root of the component tree which encompasses a set of related
59   * <code>GroupContainer</code> instances tied together with a common page layout
60   * and navigation.
61   *
62   * <p>
63   * The <code>View</code> component ties together all the components and
64   * configuration of the User Interface for a piece of functionality. In Rice
65   * applications the view is typically associated with a <code>Document</code>
66   * instance.
67   * </p>
68   *
69   * <p>
70   * The view template lays out the common header, footer, and navigation for the
71   * related pages. In addition the view renders the HTML head element bringing in
72   * common script files and style sheets, along with optionally rendering a form
73   * element for pages that need to post data back to the server.
74   * </p>
75   *
76   * <p>
77   * Configuration of UIF features such as model validation is also done through
78   * the <code>View</code>
79   * </p>
80   *
81   * @author Kuali Rice Team (rice.collab@kuali.org)
82   */
83  @BeanTags({@BeanTag(name = "view-bean", parent = "Uif-View"), @BeanTag(name = "view-knsTheme-bean", parent = "Uif-View-KnsTheme")
84  })
85  public class View extends ContainerBase {
86      private static final long serialVersionUID = -1220009725554576953L;
87  
88      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(View.class);
89  
90      private String namespaceCode;
91      private String viewName;
92      private ViewTheme theme;
93  
94      private int idSequence;
95  
96      private String stateObjectBindingPath;
97      private StateMapping stateMapping;
98  
99      // application
100     private Header applicationHeader;
101     private Group applicationFooter;
102 
103     // Breadcrumbs
104     private BreadCrumbs breadcrumbs;
105     private String breadcrumbTitlePropertyName;
106     private String breadcrumbTitleDisplayOption;
107 
108     private boolean renderBreadcrumbsInView;
109 
110     // Growls support
111     private Growls growls;
112     private boolean growlMessagingEnabled;
113 
114     private BlockUI refreshBlockUI;
115     private BlockUI navigationBlockUI;
116 
117     private String entryPageId;
118 
119     @RequestParameter
120     private String currentPageId;
121 
122     private Group navigation;
123 
124     private Class<?> formClass;
125     private String defaultBindingObjectPath;
126     private Map<String, Class<?>> objectPathToConcreteClassMapping;
127 
128     private List<String> additionalScriptFiles;
129     private List<String> additionalCssFiles;
130 
131     private ViewType viewTypeName;
132 
133     private String viewStatus;
134     private ViewIndex viewIndex;
135     private Map<String, String> viewRequestParameters;
136 
137     private boolean persistFormToSession;
138 
139     private ViewPresentationController presentationController;
140     private ViewAuthorizer authorizer;
141 
142     private BooleanMap actionFlags;
143     private BooleanMap editModes;
144 
145     private Map<String, String> expressionVariables;
146 
147     private boolean singlePageView;
148     private boolean mergeWithPageItems;
149     private PageGroup page;
150 
151     private List<? extends Group> items;
152     private List<? extends Group> dialogs;
153 
154     private Link viewMenuLink;
155     private String viewMenuGroupName;
156 
157     private boolean applyDirtyCheck;
158     private boolean translateCodesOnReadOnlyDisplay;
159     private boolean supportsRequestOverrideOfReadOnlyFields;
160 
161     private String preLoadScript;
162 
163     private int preloadPoolSize;
164 
165     private List<String> viewTemplates;
166 
167     private Class<? extends ViewHelperService> viewHelperServiceClass;
168 
169     @ReferenceCopy
170     private ViewHelperService viewHelperService;
171 
172     public View() {
173         singlePageView = false;
174         mergeWithPageItems = true;
175         translateCodesOnReadOnlyDisplay = false;
176         viewTypeName = ViewType.DEFAULT;
177         viewStatus = UifConstants.ViewStatus.CREATED;
178         formClass = UifFormBase.class;
179         renderBreadcrumbsInView = true;
180         supportsRequestOverrideOfReadOnlyFields = true;
181         persistFormToSession = true;
182 
183         idSequence = 0;
184         this.viewIndex = new ViewIndex();
185         preloadPoolSize = 0;
186 
187         additionalScriptFiles = new ArrayList<String>();
188         additionalCssFiles = new ArrayList<String>();
189         items = new ArrayList<Group>();
190         objectPathToConcreteClassMapping = new HashMap<String, Class<?>>();
191         viewRequestParameters = new HashMap<String, String>();
192         expressionVariables = new HashMap<String, String>();
193 
194         dialogs = new ArrayList<Group>();
195         viewTemplates = new ArrayList<String>();
196     }
197 
198     /**
199      * The following initialization is performed:
200      *
201      * <ul>
202      * <li>If a single paged view, set items in page group and put the page in
203      * the items list</li>
204      * </ul>
205      *
206      * @see org.kuali.rice.krad.uif.container.ContainerBase#performInitialization(View, java.lang.Object)
207      */
208     @SuppressWarnings("unchecked")
209     @Override
210     public void performInitialization(View view, Object model) {
211         super.performInitialization(view, model);
212 
213         // populate items on page for single paged view
214         if (singlePageView) {
215             if (page != null) {
216                 // remove default sections of page when requested
217                 if (!mergeWithPageItems) {
218                     page.setItems(new ArrayList<Group>());
219                 }
220 
221                 view.assignComponentIds(page);
222 
223                 // add the items configured on the view to the page items, and set as the
224                 // new page items
225                 List<Component> newItems = (List<Component>) page.getItems();
226                 newItems.addAll(items);
227                 page.setItems(newItems);
228 
229                 // reset the items list to include the one page
230                 items = new ArrayList<Group>();
231                 ((List<Group>) items).add(page);
232             } else {
233                 throw new RuntimeException("For single paged views the page Group must be set.");
234             }
235         }
236 
237         // make sure all the pages have ids before selecting the current page
238         for (Group group : this.getItems()) {
239             if (StringUtils.isBlank(group.getId())) {
240                 group.setId(view.getNextId());
241             }
242         }
243     }
244 
245     /**
246      * The following updates are done here:
247      *
248      * <ul>
249      * <li>Invoke expression evaluation on view theme</li>
250      * </ul>
251      */
252     public void performApplyModel(View view, Object model, Component parent) {
253         super.performApplyModel(view, model, parent);
254 
255         if (theme != null) {
256             KRADServiceLocatorWeb.getExpressionEvaluatorService().evaluateExpressionsOnConfigurable(view, theme, model,
257                     getContext());
258         }
259     }
260 
261     /**
262      * The following is performed:
263      *
264      * <ul>
265      * <li>Adds to its document ready script the setupValidator js function for setting
266      * up the validator for this view</li>
267      * </ul>
268      *
269      * @see org.kuali.rice.krad.uif.container.ContainerBase#performFinalize(View,
270      *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
271      */
272     @Override
273     public void performFinalize(View view, Object model, Component parent) {
274         super.performFinalize(view, model, parent);
275 
276         String preLoadScript = "";
277         if (this.getPreLoadScript() != null) {
278             preLoadScript = this.getPreLoadScript();
279         }
280 
281         // Retrieve Growl and BlockUI settings
282         Growls gw = view.getGrowls();
283         if (!gw.getTemplateOptions().isEmpty()) {
284             preLoadScript += "setGrowlDefaults(" + gw.getTemplateOptionsJSString() + ");";
285         }
286 
287         BlockUI navBlockUI = view.getNavigationBlockUI();
288         if (!navBlockUI.getTemplateOptions().isEmpty()) {
289             preLoadScript += "setBlockUIDefaults("
290                     + navBlockUI.getTemplateOptionsJSString()
291                     + ", '"
292                     + UifConstants.BLOCKUI_NAVOPTS
293                     + "');";
294         }
295 
296         BlockUI refBlockUI = view.getRefreshBlockUI();
297         if (!refBlockUI.getTemplateOptions().isEmpty()) {
298             preLoadScript += "setBlockUIDefaults("
299                     + refBlockUI.getTemplateOptionsJSString()
300                     + ", '"
301                     + UifConstants.BLOCKUI_REFRESHOPTS
302                     + "');";
303         }
304 
305         this.setPreLoadScript(preLoadScript);
306 
307         String onReadyScript = "";
308         if (this.getOnDocumentReadyScript() != null) {
309             onReadyScript = this.getOnDocumentReadyScript();
310         }
311 
312         this.setOnDocumentReadyScript(onReadyScript + "jQuery.extend(jQuery.validator.messages, " +
313                 ClientValidationUtils.generateValidatorMessagesOption() + ");");
314     }
315 
316     /**
317      * Assigns an id to the component if one was not configured
318      *
319      * @param component - component instance to assign id to
320      */
321     public void assignComponentIds(Component component) {
322         if (component == null) {
323             return;
324         }
325 
326         Integer currentSequenceVal = idSequence;
327 
328         // assign ID if necessary
329         if (StringUtils.isBlank(component.getId())) {
330             component.setId(UifConstants.COMPONENT_ID_PREFIX + getNextId());
331         }
332 
333         // capture current sequence value for component refreshes
334         getViewIndex().addSequenceValueToSnapshot(component.getId(), currentSequenceVal);
335 
336         if (component instanceof Container) {
337             LayoutManager layoutManager = ((Container) component).getLayoutManager();
338             if (layoutManager != null) {
339                 if (StringUtils.isBlank(layoutManager.getId())) {
340                     layoutManager.setId(UifConstants.COMPONENT_ID_PREFIX + getNextId());
341                 }
342             }
343         }
344 
345         // assign id to nested components
346         List<Component> allNested = new ArrayList<Component>(component.getComponentsForLifecycle());
347         allNested.addAll(component.getComponentPrototypes());
348         for (Component nestedComponent : allNested) {
349             assignComponentIds(nestedComponent);
350         }
351     }
352 
353     /**
354      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
355      */
356     @Override
357     public List<Component> getComponentsForLifecycle() {
358         List<Component> components = new ArrayList<Component>();
359 
360         components.add(applicationHeader);
361         components.add(applicationFooter);
362         components.add(navigation);
363         components.add(breadcrumbs);
364         components.add(growls);
365         components.addAll(dialogs);
366         components.add(viewMenuLink);
367         components.add(navigationBlockUI);
368         components.add(refreshBlockUI);
369 
370         // Note super items should be added after navigation and other view components so
371         // conflicting ids between nav and page do not occur on page navigation via ajax
372         components.addAll(super.getComponentsForLifecycle());
373 
374         // remove all pages that are not the current page
375         if (!singlePageView) {
376             for (Group group : this.getItems()) {
377                 if ((group instanceof PageGroup) && !StringUtils.equals(group.getId(), getCurrentPageId()) && components
378                         .contains(group)) {
379                     components.remove(group);
380                 }
381             }
382         }
383 
384         return components;
385     }
386 
387     /**
388      * @see org.kuali.rice.krad.uif.container.Container#getSupportedComponents()
389      */
390     @Override
391     public Set<Class<? extends Component>> getSupportedComponents() {
392         Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>();
393         supportedComponents.add(Group.class);
394 
395         return supportedComponents;
396     }
397 
398     /**
399      * @see org.kuali.rice.krad.uif.component.Component#getComponentTypeName()
400      */
401     @Override
402     public String getComponentTypeName() {
403         return "view";
404     }
405 
406     /**
407      * Iterates through the contained page items and returns the Page that
408      * matches the set current page id
409      *
410      * @return Page instance
411      */
412     public PageGroup getCurrentPage() {
413         for (Group pageGroup : this.getItems()) {
414             if (StringUtils.equals(pageGroup.getId(), getCurrentPageId()) && pageGroup instanceof PageGroup) {
415                 return (PageGroup) pageGroup;
416             }
417         }
418 
419         return null;
420     }
421 
422     /**
423      * Override sort method to prevent sorting in the case of a single page view, since the items
424      * will get pushed into the configured page and sorted through the page
425      */
426     @Override
427     protected void sortItems(View view, Object model) {
428         if (!singlePageView) {
429             super.sortItems(view, model);
430         }
431     }
432 
433     /**
434      * Namespace code the view should be associated with
435      *
436      * <p>
437      * The namespace code is used within the framework in such places as permission checks and parameter
438      * retrieval
439      * </p>
440      *
441      * @return String namespace code
442      */
443     @BeanTagAttribute(name = "namespaceCode")
444     public String getNamespaceCode() {
445         return namespaceCode;
446     }
447 
448     /**
449      * Setter for the view's namespace code
450      *
451      * @param namespaceCode
452      */
453     public void setNamespaceCode(String namespaceCode) {
454         this.namespaceCode = namespaceCode;
455     }
456 
457     /**
458      * View name provides an identifier for a view within a type. That is if a
459      * set of <code>View</code> instances have the same values for the
460      * properties that are used to retrieve them by their type, the name can be
461      * given to further qualify the view that should be retrieved.
462      * <p>
463      * A view type like the <code>LookupView</code> might have several views for
464      * the same object class, but one that is the 'default' lookup and another
465      * that is the 'advanced' lookup. Therefore the name on the first could be
466      * set to 'default', and likewise the name for the second 'advanced'.
467      * </p>
468      *
469      * @return String name of view
470      */
471     @BeanTagAttribute(name = "viewName")
472     public String getViewName() {
473         return this.viewName;
474     }
475 
476     /**
477      * Setter for the view's name
478      *
479      * @param viewName
480      */
481     public void setViewName(String viewName) {
482         this.viewName = viewName;
483     }
484 
485     /**
486      * Header for the application containing the view
487      *
488      * <p>
489      * When deploying outside a portal, the application header and footer property can be configured to
490      * display a consistent header/footer across all views. Here application logos, menus, login controls
491      * and so on can be rendered.
492      * </p>
493      *
494      * @return HeaderField application header
495      */
496     @BeanTagAttribute(name = "applicationHeader", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
497     public Header getApplicationHeader() {
498         return applicationHeader;
499     }
500 
501     /**
502      * Setter for the application header
503      *
504      * @param applicationHeader
505      */
506     public void setApplicationHeader(Header applicationHeader) {
507         this.applicationHeader = applicationHeader;
508     }
509 
510     /**
511      * Footer for the application containing the view
512      *
513      * <p>
514      * When deploying outside a portal, the application header and footer property can be configured to
515      * display a consistent header/footer across all views. Here such things as application links, copyrights
516      * and so on can be rendered.
517      * </p>
518      *
519      * @return Group application footer
520      */
521     @BeanTagAttribute(name = "applicationFooter", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
522     public Group getApplicationFooter() {
523         return applicationFooter;
524     }
525 
526     /**
527      * Setter for the application footer
528      *
529      * @param applicationFooter
530      */
531     public void setApplicationFooter(Group applicationFooter) {
532         this.applicationFooter = applicationFooter;
533     }
534 
535     /**
536      * Current sequence value for id assignment
537      *
538      * @return int id sequence
539      */
540     public int getIdSequence() {
541         return idSequence;
542     }
543 
544     /**
545      * Setter for the current id sequence value
546      *
547      * @param idSequence
548      */
549     public void setIdSequence(int idSequence) {
550         this.idSequence = idSequence;
551     }
552 
553     /**
554      * Returns the next unique id available for components within the view instance
555      *
556      * @return String next id available
557      */
558     public String getNextId() {
559         idSequence += 1;
560         return Integer.toString(idSequence);
561     }
562 
563     /**
564      * Specifies what page should be rendered by default. This is the page that
565      * will be rendered when the <code>View</code> is first rendered or when the
566      * current page is not set
567      *
568      * @return String id of the page to render by default
569      */
570     @BeanTagAttribute(name = "entryPageId")
571     public String getEntryPageId() {
572         return this.entryPageId;
573     }
574 
575     /**
576      * Setter for default Page id
577      *
578      * @param entryPageId
579      */
580     public void setEntryPageId(String entryPageId) {
581         this.entryPageId = entryPageId;
582     }
583 
584     /**
585      * The id for the page within the view that should be displayed in the UI.
586      * Other pages of the view will not be rendered
587      *
588      * <p>
589      * If current page id is not set, it is set to the configured entry page or first item in list id
590      * </p>
591      *
592      * @return String id of the page that should be displayed
593      */
594     public String getCurrentPageId() {
595         // default current page if not set
596         if (StringUtils.isBlank(currentPageId)) {
597             if (StringUtils.isNotBlank(entryPageId)) {
598                 currentPageId = entryPageId;
599             } else if ((getItems() != null) && !getItems().isEmpty()) {
600                 Group firstPageGroup = getItems().get(0);
601                 currentPageId = firstPageGroup.getId();
602             }
603         }
604 
605         return this.currentPageId;
606     }
607 
608     /**
609      * Setter for the page id to display
610      *
611      * @param currentPageId
612      */
613     public void setCurrentPageId(String currentPageId) {
614         this.currentPageId = currentPageId;
615     }
616 
617     /**
618      * <code>NavigationGroup</code> instance for the <code>View</code>
619      * <p>
620      * Provides configuration necessary to render the navigation. This includes
621      * navigation items in addition to configuration for the navigation
622      * renderer.
623      * </p>
624      *
625      * @return NavigationGroup
626      */
627     @BeanTagAttribute(name = "navigation", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
628     public Group getNavigation() {
629         return this.navigation;
630     }
631 
632     /**
633      * Setter for the View's <code>NavigationGroup</code>
634      *
635      * @param navigation
636      */
637     public void setNavigation(Group navigation) {
638         this.navigation = navigation;
639     }
640 
641     /**
642      * Class of the Form that should be used with the <code>View</code>
643      * instance. The form is the top level object for all the view's data and is
644      * used to present and accept data in the user interface. All form classes
645      * should extend UifFormBase
646      *
647      * @return Class<?> class for the view's form
648      * @see org.kuali.rice.krad.web.form.UifFormBase
649      */
650     @BeanTagAttribute(name = "formClass")
651     public Class<?> getFormClass() {
652         return this.formClass;
653     }
654 
655     /**
656      * Setter for the form class
657      *
658      * @param formClass
659      */
660     public void setFormClass(Class<?> formClass) {
661         this.formClass = formClass;
662     }
663 
664     /**
665      * For <code>View</code> types that work primarily with one nested object of
666      * the form (for instance document, or bo) the default binding object path
667      * can be set for each of the views <code>DataBinding</code> components. If
668      * the component does not set its own binding object path it will inherit
669      * the default
670      *
671      * @return String binding path to the object from the form
672      */
673     @BeanTagAttribute(name = "defaultObjectPath")
674     public String getDefaultBindingObjectPath() {
675         return this.defaultBindingObjectPath;
676     }
677 
678     /**
679      * Setter for the default binding object path to use for the view
680      *
681      * @param defaultBindingObjectPath
682      */
683     public void setDefaultBindingObjectPath(String defaultBindingObjectPath) {
684         this.defaultBindingObjectPath = defaultBindingObjectPath;
685     }
686 
687     /**
688      * Configures the concrete classes that will be used for properties in the
689      * form object graph that have an abstract or interface type
690      *
691      * <p>
692      * For properties that have an abstract or interface type, it is not
693      * possible to perform operations like getting/settings property values and
694      * getting information from the dictionary. When these properties are
695      * encountered in the object graph, this <code>Map</code> will be consulted
696      * to determine the concrete type to use.
697      * </p>
698      *
699      * <p>
700      * e.g. Suppose we have a property document.accountingLine.accountNumber and
701      * the accountingLine property on the document instance has an interface
702      * type 'AccountingLine'. We can then put an entry into this map with key
703      * 'document.accountingLine', and value
704      * 'org.kuali.rice.sampleapp.TravelAccountingLine'. When getting the
705      * property type or an entry from the dictionary for accountNumber, the
706      * TravelAccountingLine class will be used.
707      * </p>
708      *
709      * @return Map<String, Class> of class implementations keyed by path
710      */
711     @BeanTagAttribute(name = "objectPathConcreteClassMapping", type = BeanTagAttribute.AttributeType.MAPVALUE)
712     public Map<String, Class<?>> getObjectPathToConcreteClassMapping() {
713         return this.objectPathToConcreteClassMapping;
714     }
715 
716     /**
717      * Setter for the Map of class implementations keyed by path
718      *
719      * @param objectPathToConcreteClassMapping
720      */
721     public void setObjectPathToConcreteClassMapping(Map<String, Class<?>> objectPathToConcreteClassMapping) {
722         this.objectPathToConcreteClassMapping = objectPathToConcreteClassMapping;
723     }
724 
725     /**
726      * Declares additional script files that should be included with the
727      * <code>View</code>. These files are brought into the HTML page along with
728      * common script files configured for the Rice application. Each entry
729      * contain the path to the CSS file, either a relative path, path from web
730      * root, or full URI
731      * <p>
732      * e.g. '/krad/scripts/myScript.js', '../scripts/myScript.js',
733      * 'http://my.edu/web/myScript.js'
734      * </p>
735      *
736      * @return List<String> script file locations
737      */
738     @BeanTagAttribute(name = "additionalScriptFiles", type = BeanTagAttribute.AttributeType.LISTVALUE)
739     public List<String> getAdditionalScriptFiles() {
740         return this.additionalScriptFiles;
741     }
742 
743     /**
744      * Setter for the List of additional script files to included with the
745      * <code>View</code>
746      *
747      * @param additionalScriptFiles
748      */
749     public void setAdditionalScriptFiles(List<String> additionalScriptFiles) {
750         this.additionalScriptFiles = additionalScriptFiles;
751     }
752 
753     /**
754      * Declares additional CSS files that should be included with the
755      * <code>View</code>. These files are brought into the HTML page along with
756      * common CSS files configured for the Rice application. Each entry should
757      * contain the path to the CSS file, either a relative path, path from web
758      * root, or full URI
759      * <p>
760      * e.g. '/krad/css/stacked-view.css', '../css/stacked-view.css',
761      * 'http://my.edu/web/stacked-view.css'
762      * </p>
763      *
764      * @return List<String> CSS file locations
765      */
766     @BeanTagAttribute(name = "additionalCssFiles", type = BeanTagAttribute.AttributeType.LISTVALUE)
767     public List<String> getAdditionalCssFiles() {
768         return this.additionalCssFiles;
769     }
770 
771     /**
772      * Setter for the List of additional CSS files to included with the
773      * <code>View</code>
774      *
775      * @param additionalCssFiles
776      */
777     public void setAdditionalCssFiles(List<String> additionalCssFiles) {
778         this.additionalCssFiles = additionalCssFiles;
779     }
780 
781     /**
782      * Specifies the size of the pool that will contain pre-loaded views
783      *
784      * <p>
785      * The spring loading of some views can take a few seconds which hurts performance. The framework supports
786      * pre-loading of view instances so they are available right away when a request is made. This property configures
787      * how many view instances will be pre-loaded. A value of 0 (the default) means no view instances will be
788      * pre-loaded
789      * </p>
790      *
791      * @return int number of view instances to pre-load
792      */
793     @BeanTagAttribute(name = "preloadPoolSize")
794     public int getPreloadPoolSize() {
795         return preloadPoolSize;
796     }
797 
798     /**
799      * Setter for the preloaded view pool size
800      *
801      * @param preloadPoolSize
802      */
803     public void setPreloadPoolSize(int preloadPoolSize) {
804         this.preloadPoolSize = preloadPoolSize;
805     }
806 
807     /**
808      * List of templates that are used to render the view
809      *
810      * <p>
811      * This list will be populated by unique template names as the components of the view are being processed.
812      * Additional templates can be added in the view configuration if desired. At the beginning of the the view
813      * rendering, each template in the list will then be included or processed by the template language
814      * </p>
815      *
816      * <p>
817      * Note the user of this depends on the template language being used for rendering. Some languages might require
818      * including the template for each component instance (for example JSP templates). While others might simply
819      * include markup that is then available for rendering each component instance (for example FreeMarker which has
820      * a macro for each component that the template defines)
821      * </p>
822      *
823      * @return List<String> list of template names that should be included for rendering the view
824      */
825     public List<String> getViewTemplates() {
826         return viewTemplates;
827     }
828 
829     /**
830      * Setter for the the list of template names that should be included to render the view
831      *
832      * @param viewTemplates
833      */
834     public void setViewTemplates(List<String> viewTemplates) {
835         this.viewTemplates = viewTemplates;
836     }
837 
838     /**
839      * View type name the view is associated with the view instance
840      *
841      * <p>
842      * Views that share common features and functionality can be grouped by the
843      * view type. Usually view types extend the <code>View</code> class to
844      * provide additional configuration and to set defaults. View types can also
845      * implement the <code>ViewTypeService</code> to add special indexing and
846      * retrieval of views.
847      * </p>
848      *
849      * @return String view type name for the view
850      */
851     @BeanTagAttribute(name = "viewTypeName", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
852     public ViewType getViewTypeName() {
853         return this.viewTypeName;
854     }
855 
856     /**
857      * Setter for the view's type name
858      *
859      * @param viewTypeName
860      */
861     public void setViewTypeName(ViewType viewTypeName) {
862         this.viewTypeName = viewTypeName;
863     }
864 
865     /**
866      * Class name of the <code>ViewHelperService</code> that handles the various
867      * phases of the Views lifecycle
868      *
869      * @return Class for the spring bean
870      * @see org.kuali.rice.krad.uif.service.ViewHelperService
871      */
872     @BeanTagAttribute(name = "viewHelperServiceClass")
873     public Class<? extends ViewHelperService> getViewHelperServiceClass() {
874         return this.viewHelperServiceClass;
875     }
876 
877     /**
878      * Setter for the <code>ViewHelperService</code> class name
879      *
880      * @param viewHelperServiceClass
881      */
882     public void setViewHelperServiceClass(Class<? extends ViewHelperService> viewHelperServiceClass) {
883         this.viewHelperServiceClass = viewHelperServiceClass;
884     }
885 
886     /**
887      * Creates the <code>ViewHelperService</code> associated with the View
888      *
889      * @return ViewHelperService instance
890      */
891     @BeanTagAttribute(name = "viewHelperService", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
892     public ViewHelperService getViewHelperService() {
893         if ((this.viewHelperService == null) && (this.viewHelperServiceClass != null)) {
894             viewHelperService = ObjectUtils.newInstance(viewHelperServiceClass);
895         }
896 
897         return viewHelperService;
898     }
899 
900     /**
901      * Invoked to produce a ViewIndex of the current view's components
902      */
903     public void index() {
904         if (this.viewIndex == null) {
905             this.viewIndex = new ViewIndex();
906         }
907         this.viewIndex.index(this);
908     }
909 
910     /**
911      * Holds field indexes of the <code>View</code> instance for retrieval
912      *
913      * @return ViewIndex instance
914      */
915     @BeanTagAttribute(name = "viewIndex", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
916     public ViewIndex getViewIndex() {
917         return this.viewIndex;
918     }
919 
920     /**
921      * Map of parameters from the request that set view options, used to rebuild
922      * the view on each post
923      * <p>
924      * Views can be configured by parameters. These might impact which parts of
925      * the view are rendered or how the view behaves. Generally these would get
926      * passed in when a new view is requested (by request parameters). These
927      * will be used to initially populate the view properties. In addition, on a
928      * post the view will be rebuilt and properties reset again by the allow
929      * request parameters.
930      * </p>
931      * <p>
932      * Example parameter would be for MaintenaceView whether a New, Edit, or
933      * Copy was requested (maintenance mode)
934      * </p>
935      *
936      * @return
937      */
938     public Map<String, String> getViewRequestParameters() {
939         return this.viewRequestParameters;
940     }
941 
942     /**
943      * Setter for the view's request parameters map
944      *
945      * @param viewRequestParameters
946      */
947     public void setViewRequestParameters(Map<String, String> viewRequestParameters) {
948         this.viewRequestParameters = viewRequestParameters;
949     }
950 
951     /**
952      * Indicates whether the form (model) associated with the view should be stored in the user session
953      *
954      * <p>
955      * The form class (or model) is used to hold the data that backs the view along with the built view object. Storing
956      * the form instance in session allows many things:
957      *
958      * <ul>
959      * <li>Data does not need to be rebuilt for each server request (for example a collection)</li>
960      * <li>Data that does not need to go to the user can remain on the form, reducing the size of the response and
961      * improving security</li>
962      * <li>Data can be keep around in a 'pre-save' state. When requested by the user changes can then be persisted to
963      * the database</li>
964      * <li>Certain information about the view that was rendered, such as input fields, collection paths, and refresh
965      * components can be kept on the form to support UI interaction</li>
966      * </ul>
967      *
968      * Setting this flag to false will prevent the form from being kept in session and as a result will limit what can
969      * be done by the framework. In almost all cases this is not recommended.
970      * </p>
971      *
972      * <p>
973      * Note all forms will be cleared when the user session expires (based on the rice configuration). In addition, the
974      * framework enables clear points on certain actions to remove the form when it is no longer needed
975      * </p>
976      *
977      * @return boolean true if the form should be stored in the user session, false if only request based
978      */
979     @BeanTagAttribute(name = "persistFormToSession")
980     public boolean isPersistFormToSession() {
981         return persistFormToSession;
982     }
983 
984     /**
985      * Setter for the persist form to session indicator
986      *
987      * @param persistFormToSession
988      */
989     public void setPersistFormToSession(boolean persistFormToSession) {
990         this.persistFormToSession = persistFormToSession;
991     }
992 
993     /**
994      * PresentationController that should be used for the <code>View</code> instance
995      *
996      * <p>
997      * The presentation controller is consulted to determine component (group,
998      * field) state such as required, read-only, and hidden. The presentation
999      * controller does not take into account user permissions. The presentation
1000      * controller can also output action flags and edit modes that will be set
1001      * onto the view instance and can be referred to by conditional expressions
1002      * </p>
1003      *
1004      * @return PresentationController
1005      */
1006     @BeanTagAttribute(name = "presentationController", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1007     public ViewPresentationController getPresentationController() {
1008         return this.presentationController;
1009     }
1010 
1011     /**
1012      * Setter for the view's presentation controller
1013      *
1014      * @param presentationController
1015      */
1016     public void setPresentationController(ViewPresentationController presentationController) {
1017         this.presentationController = presentationController;
1018     }
1019 
1020     /**
1021      * Setter for the view's presentation controller by class
1022      *
1023      * @param presentationControllerClass
1024      */
1025     public void setPresentationControllerClass(
1026             Class<? extends ViewPresentationController> presentationControllerClass) {
1027         this.presentationController = ObjectUtils.newInstance(presentationControllerClass);
1028     }
1029 
1030     /**
1031      * Authorizer that should be used for the <code>View</code> instance
1032      *
1033      * <p>
1034      * The authorizer class is consulted to determine component (group, field)
1035      * state such as required, read-only, and hidden based on the users
1036      * permissions. It typically communicates with the Kuali Identity Management
1037      * system to determine roles and permissions. It is used with the
1038      * presentation controller and dictionary conditional logic to determine the
1039      * final component state. The authorizer can also output action flags and
1040      * edit modes that will be set onto the view instance and can be referred to
1041      * by conditional expressions
1042      * </p>
1043      *
1044      * @return Authorizer
1045      */
1046     @BeanTagAttribute(name = "authorizer", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1047     public ViewAuthorizer getAuthorizer() {
1048         return this.authorizer;
1049     }
1050 
1051     /**
1052      * Setter for the view's authorizer
1053      *
1054      * @param authorizer
1055      */
1056     public void setAuthorizer(ViewAuthorizer authorizer) {
1057         this.authorizer = authorizer;
1058     }
1059 
1060     /**
1061      * Setter for the view's authorizer by class
1062      *
1063      * @param authorizerClass
1064      */
1065     public void setAuthorizerClass(Class<? extends ViewAuthorizer> authorizerClass) {
1066         this.authorizer = ObjectUtils.newInstance(authorizerClass);
1067     }
1068 
1069     /**
1070      * Map of strings that flag what actions can be taken in the UI
1071      * <p>
1072      * These can be used in conditional expressions in the dictionary or by
1073      * other UI logic
1074      * </p>
1075      *
1076      * @return BooleanMap action flags
1077      */
1078     @BeanTagAttribute(name = "actionFlags", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1079     public BooleanMap getActionFlags() {
1080         return this.actionFlags;
1081     }
1082 
1083     /**
1084      * Setter for the action flags Map
1085      *
1086      * @param actionFlags
1087      */
1088     public void setActionFlags(BooleanMap actionFlags) {
1089         this.actionFlags = actionFlags;
1090     }
1091 
1092     /**
1093      * Map of edit modes that enabled for the view
1094      * <p>
1095      * These can be used in conditional expressions in the dictionary or by
1096      * other UI logic
1097      * </p>
1098      *
1099      * @return BooleanMap edit modes
1100      */
1101     @BeanTagAttribute(name = "editModes", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1102     public BooleanMap getEditModes() {
1103         return this.editModes;
1104     }
1105 
1106     /**
1107      * Setter for the edit modes Map
1108      *
1109      * @param editModes
1110      */
1111     public void setEditModes(BooleanMap editModes) {
1112         this.editModes = editModes;
1113     }
1114 
1115     /**
1116      * Map that contains expressions to evaluate and make available as variables
1117      * for conditional expressions within the view
1118      * <p>
1119      * Each Map entry contains one expression variables, where the map key gives
1120      * the name for the variable, and the map value gives the variable
1121      * expression. The variables expressions will be evaluated before
1122      * conditional logic is run and made available as variables for other
1123      * conditional expressions. Variable expressions can be based on the model
1124      * and any object contained in the view's context
1125      * </p>
1126      *
1127      * @return Map<String, String> variable expressions
1128      */
1129     @BeanTagAttribute(name = "expressionVariables", type = BeanTagAttribute.AttributeType.MAPVALUE)
1130     public Map<String, String> getExpressionVariables() {
1131         return this.expressionVariables;
1132     }
1133 
1134     /**
1135      * Setter for the view's map of variable expressions
1136      *
1137      * @param expressionVariables
1138      */
1139     public void setExpressionVariables(Map<String, String> expressionVariables) {
1140         this.expressionVariables = expressionVariables;
1141     }
1142 
1143     /**
1144      * Indicates whether the <code>View</code> only has a single page
1145      * <code>Group</code> or contains multiple page <code>Group</code>
1146      * instances. In the case of a single page it is assumed the group's items
1147      * list contains the section groups for the page, and the page itself is
1148      * given by the page property ({@link #getPage()}. This is for convenience
1149      * of configuration and also can drive other configuration like styling.
1150      *
1151      * @return boolean true if the view only contains one page group, false if
1152      *         it contains multple pages
1153      */
1154     @BeanTagAttribute(name = "singlePageView")
1155     public boolean isSinglePageView() {
1156         return this.singlePageView;
1157     }
1158 
1159     /**
1160      * Setter for the single page indicator
1161      *
1162      * @param singlePageView
1163      */
1164     public void setSinglePageView(boolean singlePageView) {
1165         this.singlePageView = singlePageView;
1166     }
1167 
1168     /**
1169      * Indicates whether the default sections specified in the page items list
1170      * should be included for this view.  This only applies to single paged views.
1171      *
1172      * @return boolean true if the view should contain the default sections
1173      *         specified in the page
1174      */
1175     public boolean isMergeWithPageItems() {
1176         return mergeWithPageItems;
1177     }
1178 
1179     /**
1180      * Setter for the include page default sections indicator
1181      *
1182      * @param mergeWithPageItems
1183      */
1184     public void setMergeWithPageItems(boolean mergeWithPageItems) {
1185         this.mergeWithPageItems = mergeWithPageItems;
1186     }
1187 
1188     /**
1189      * For single paged views ({@link #isSinglePageView()}, gives the page
1190      * <code>Group</code> the view should render. The actual items for the page
1191      * is taken from the group's items list ({@link #getItems()}, and set onto
1192      * the give page group. This is for convenience of configuration.
1193      *
1194      * @return Group page group for single page views
1195      */
1196     @BeanTagAttribute(name = "page", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1197     public PageGroup getPage() {
1198         return this.page;
1199     }
1200 
1201     /**
1202      * Setter for the page group for single page views
1203      *
1204      * @param page
1205      */
1206     public void setPage(PageGroup page) {
1207         this.page = page;
1208     }
1209 
1210     /**
1211      * @see org.kuali.rice.krad.uif.container.ContainerBase#getItems()
1212      */
1213     @Override
1214     @BeanTagAttribute(name = "items", type = BeanTagAttribute.AttributeType.LISTBEAN)
1215     public List<? extends Group> getItems() {
1216         return this.items;
1217     }
1218 
1219     /**
1220      * Setter for the view's <code>Group</code> instances
1221      *
1222      * @param items
1223      */
1224     @Override
1225     public void setItems(List<? extends Component> items) {
1226         // TODO: fix this generic issue
1227         this.items = (List<? extends Group>) items;
1228     }
1229 
1230     /**
1231      * Provide a list of dialog groups associated with this view
1232      *
1233      * @return List of dialog Groups
1234      */
1235     @BeanTagAttribute(name = "dialogs", type = BeanTagAttribute.AttributeType.LISTBEAN)
1236     public List<? extends Group> getDialogs() {
1237         return dialogs;
1238     }
1239 
1240     /**
1241      * Sets the list of dialog groups for this view
1242      *
1243      * @param dialogs - List of dialog groups
1244      */
1245     public void setDialogs(List<? extends Group> dialogs) {
1246         this.dialogs = dialogs;
1247     }
1248 
1249     /**
1250      * Provides configuration for displaying a link to the view from an
1251      * application menu
1252      *
1253      * @return Link view link field
1254      */
1255     @BeanTagAttribute(name = "viewMenuLink", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1256     public Link getViewMenuLink() {
1257         return this.viewMenuLink;
1258     }
1259 
1260     /**
1261      * Setter for the views link field
1262      *
1263      * @param viewMenuLink
1264      */
1265     public void setViewMenuLink(Link viewMenuLink) {
1266         this.viewMenuLink = viewMenuLink;
1267     }
1268 
1269     /**
1270      * Provides a grouping string for the view to group its menu link (within a
1271      * portal for instance)
1272      *
1273      * @return String menu grouping
1274      */
1275     @BeanTagAttribute(name = "viewMenuGroupName")
1276     public String getViewMenuGroupName() {
1277         return this.viewMenuGroupName;
1278     }
1279 
1280     /**
1281      * Setter for the views menu grouping
1282      *
1283      * @param viewMenuGroupName
1284      */
1285     public void setViewMenuGroupName(String viewMenuGroupName) {
1286         this.viewMenuGroupName = viewMenuGroupName;
1287     }
1288 
1289     /**
1290      * Indicates what lifecycle phase the View instance is in
1291      * <p>
1292      * The view lifecycle begins with the CREATED status. In this status a new
1293      * instance of the view has been retrieved from the dictionary, but no
1294      * further processing has been done. After the initialize phase has been run
1295      * the status changes to INITIALIZED. After the model has been applied and
1296      * the view is ready for render the status changes to FINAL
1297      * </p>
1298      *
1299      * @return String view status
1300      * @see org.kuali.rice.krad.uif.UifConstants.ViewStatus
1301      */
1302     public String getViewStatus() {
1303         return this.viewStatus;
1304     }
1305 
1306     /**
1307      * Setter for the view status
1308      *
1309      * @param viewStatus
1310      */
1311     public void setViewStatus(String viewStatus) {
1312         this.viewStatus = viewStatus;
1313     }
1314 
1315     /**
1316      * Indicates whether the view has been initialized
1317      *
1318      * @return boolean true if the view has been initialized, false if not
1319      */
1320     public boolean isInitialized() {
1321         return StringUtils.equals(viewStatus, ViewStatus.INITIALIZED) || StringUtils.equals(viewStatus,
1322                 ViewStatus.FINAL);
1323     }
1324 
1325     /**
1326      * Indicates whether the view has been updated from the model and final
1327      * updates made
1328      *
1329      * @return boolean true if the view has been updated, false if not
1330      */
1331     public boolean isFinal() {
1332         return StringUtils.equals(viewStatus, ViewStatus.FINAL);
1333     }
1334 
1335     /**
1336      * Breadcrumb widget used for displaying homeward path and history
1337      *
1338      * @return the breadcrumbs
1339      */
1340     @BeanTagAttribute(name = "breadcrumbs", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1341     public BreadCrumbs getBreadcrumbs() {
1342         return this.breadcrumbs;
1343     }
1344 
1345     /**
1346      * @param breadcrumbs the breadcrumbs to set
1347      */
1348     public void setBreadcrumbs(BreadCrumbs breadcrumbs) {
1349         this.breadcrumbs = breadcrumbs;
1350     }
1351 
1352     /**
1353      * Indicates whether the breadcrumbs should be rendered in the view or if they have been rendered in
1354      * the application header
1355      *
1356      * <p>
1357      * For layout purposes it is sometimes necessary to render the breadcrumbs in the application header. This flag
1358      * indicates that is being done (by setting to false) and therefore should not be rendered in the view template.
1359      * </p>
1360      *
1361      * @return boolean true if breadcrumbs should be rendered in the view, false if not (are rendered in the
1362      *         application header)
1363      */
1364     @BeanTagAttribute(name = "renderBreadcrumbsInView")
1365     public boolean isRenderBreadcrumbsInView() {
1366         return renderBreadcrumbsInView;
1367     }
1368 
1369     /**
1370      * Setter for the render breadcrumbs in view indicator
1371      *
1372      * @param renderBreadcrumbsInView
1373      */
1374     public void setRenderBreadcrumbsInView(boolean renderBreadcrumbsInView) {
1375         this.renderBreadcrumbsInView = renderBreadcrumbsInView;
1376     }
1377 
1378     /**
1379      * Growls widget which sets up global settings for the growls used in this
1380      * view and its pages
1381      *
1382      * @return the growls
1383      */
1384     @BeanTagAttribute(name = "growls", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1385     public Growls getGrowls() {
1386         return this.growls;
1387     }
1388 
1389     /**
1390      * @param growls the growls to set
1391      */
1392     public void setGrowls(Growls growls) {
1393         this.growls = growls;
1394     }
1395 
1396     /**
1397      * Set the refresh BlockUI used with single element blocking
1398      * (such as ajax based element loading/updates)
1399      *
1400      * @param refreshBlockUI
1401      */
1402     public void setRefreshBlockUI(BlockUI refreshBlockUI) {
1403         this.refreshBlockUI = refreshBlockUI;
1404     }
1405 
1406     /**
1407      * @return BlockUI returns the refresh block object
1408      */
1409     @BeanTagAttribute(name = "refreshBlockUI", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1410     public BlockUI getRefreshBlockUI() {
1411         return refreshBlockUI;
1412     }
1413 
1414     /**
1415      * Set the navigation BlockUI used with single page blocking
1416      * (such as full page loading/saving)
1417      *
1418      * @param navigationBlockUI
1419      */
1420     public void setNavigationBlockUI(BlockUI navigationBlockUI) {
1421         this.navigationBlockUI = navigationBlockUI;
1422     }
1423 
1424     /**
1425      * @return BlockUI returns the navigation block object
1426      */
1427     @BeanTagAttribute(name = "navigationBlockUI", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1428     public BlockUI getNavigationBlockUI() {
1429         return navigationBlockUI;
1430     }
1431 
1432     /**
1433      * whether to use growls to show messages - info, warning and error
1434      *
1435      * <p>Growls use the messages contained in the message map. If enabled, info
1436      * messages in their entirety will be displayed in growls, for warning and
1437      * error messages a growl message will notify the user that these messages
1438      * exist on the page.</p>
1439      *
1440      * <p> If this setting is disabled, it is recommended that
1441      * infoMessage display be enabled for the page ValidationMessages bean in order to
1442      * display relevant information to the user. Note: the growl scripts are
1443      * built out in the PageGroup class.</p>
1444      *
1445      * @return the growlMessagingEnabled
1446      */
1447     @BeanTagAttribute(name = "growlMessagingEnabled")
1448     public boolean isGrowlMessagingEnabled() {
1449         return this.growlMessagingEnabled;
1450     }
1451 
1452     /**
1453      * enable or disable showing of messages using growls
1454      *
1455      * @param growlMessagingEnabled the growlMessagingEnabled to set
1456      */
1457     public void setGrowlMessagingEnabled(boolean growlMessagingEnabled) {
1458         this.growlMessagingEnabled = growlMessagingEnabled;
1459     }
1460 
1461     /**
1462      * Indicates whether the form should be validated for dirtyness
1463      *
1464      * <p>
1465      * For FormView, it's necessary to validate when the user tries to navigate out of the form. If set, all the
1466      * InputFields will be validated on refresh, navigate, cancel or close Action or on form
1467      * unload and if dirty, displays a message and user can decide whether to continue with
1468      * the action or stay on the form. For lookup and inquiry, it's not needed to validate.
1469      * </p>
1470      *
1471      * @return true if dirty validation is set
1472      */
1473     @BeanTagAttribute(name = "applyDirtyCheck")
1474     public boolean isApplyDirtyCheck() {
1475         return this.applyDirtyCheck;
1476     }
1477 
1478     /**
1479      * Setter for dirty validation.
1480      */
1481     public void setApplyDirtyCheck(boolean applyDirtyCheck) {
1482         this.applyDirtyCheck = applyDirtyCheck;
1483     }
1484 
1485     /**
1486      * Indicates whether the Name of the Code should be displayed when a property is of type <code>KualiCode</code>
1487      *
1488      * @param translateCodesOnReadOnlyDisplay - indicates whether <code>KualiCode</code>'s name should be included
1489      */
1490     public void setTranslateCodesOnReadOnlyDisplay(boolean translateCodesOnReadOnlyDisplay) {
1491         this.translateCodesOnReadOnlyDisplay = translateCodesOnReadOnlyDisplay;
1492     }
1493 
1494     /**
1495      * Returns whether the current view supports displaying <code>KualiCode</code>'s name as additional display value
1496      *
1497      * @return true if the current view supports
1498      */
1499     @BeanTagAttribute(name = "translateCodesOnReadOnlyDisplay")
1500     public boolean isTranslateCodesOnReadOnlyDisplay() {
1501         return translateCodesOnReadOnlyDisplay;
1502     }
1503 
1504     /**
1505      * The property name to be used to determine what will be used in the
1506      * breadcrumb title of this view
1507      *
1508      * <p>
1509      * The title can be determined from a combination of this and viewLabelFieldbindingInfo: If only
1510      * viewLabelFieldPropertyName is set, the title we be determined against the
1511      * defaultBindingObjectPath. If only viewLabelFieldbindingInfo is set it
1512      * must provide information about what object(bindToForm or explicit) and
1513      * path to use. If both viewLabelFieldbindingInfo and viewLabelFieldPropertyName are set,
1514      * the bindingInfo will be used with a
1515      * the viewLabelFieldPropertyName as its bindingPath. If neither are set,
1516      * the default title attribute from the dataObject's metadata (determined by the
1517      * defaultBindingObjectPath's object) will be used.
1518      * </p>
1519      *
1520      * @return String property name whose value should be displayed in view label
1521      */
1522     @BeanTagAttribute(name = "breadcrumbTitlePropertyName")
1523     public String getBreadcrumbTitlePropertyName() {
1524         return this.breadcrumbTitlePropertyName;
1525     }
1526 
1527     /**
1528      * Setter for the view label property name
1529      *
1530      * @param breadcrumbTitlePropertyName the viewLabelFieldPropertyName to set
1531      */
1532     public void setBreadcrumbTitlePropertyName(String breadcrumbTitlePropertyName) {
1533         this.breadcrumbTitlePropertyName = breadcrumbTitlePropertyName;
1534     }
1535 
1536     /**
1537      * The option to use when appending the view label on the breadcrumb title.
1538      * Available options: 'dash', 'parenthesis', and 'replace'(don't append -
1539      * simply replace the title). MUST be set for the viewLabelField to be used
1540      * in the breadcrumb, if not set no appendage will be added.
1541      *
1542      * @return the appendOption
1543      */
1544     @BeanTagAttribute(name = "breadcrumbTitleDisplayOption")
1545     public String getBreadcrumbTitleDisplayOption() {
1546         return this.breadcrumbTitleDisplayOption;
1547     }
1548 
1549     /**
1550      * Setter for the append option
1551      *
1552      * @param breadcrumbTitleDisplayOption the appendOption to set
1553      */
1554     public void setBreadcrumbTitleDisplayOption(String breadcrumbTitleDisplayOption) {
1555         this.breadcrumbTitleDisplayOption = breadcrumbTitleDisplayOption;
1556     }
1557 
1558     /**
1559      * Indicates whether the view allows read only fields to be specified on the request URL which will
1560      * override the view setting
1561      *
1562      * <p>
1563      * If enabled, the readOnlyFields request parameter can be sent to indicate fields that should be set read only
1564      * </p>
1565      *
1566      * @return boolean true if read only request overrides are allowed, false if not
1567      */
1568     @BeanTagAttribute(name = "supportsRequestOverrideOfReadOnlyFields")
1569     public boolean isSupportsRequestOverrideOfReadOnlyFields() {
1570         return supportsRequestOverrideOfReadOnlyFields;
1571     }
1572 
1573     /**
1574      * Setter for the the read only field override indicator
1575      *
1576      * @param supportsRequestOverrideOfReadOnlyFields
1577      */
1578     public void setSupportsRequestOverrideOfReadOnlyFields(boolean supportsRequestOverrideOfReadOnlyFields) {
1579         this.supportsRequestOverrideOfReadOnlyFields = supportsRequestOverrideOfReadOnlyFields;
1580     }
1581 
1582     /**
1583      * Script that is executed at the beginning of page load (before any other script)
1584      *
1585      * <p>
1586      * Many used to set server variables client side
1587      * </p>
1588      *
1589      * @return String pre load script
1590      */
1591     @BeanTagAttribute(name = "preLoadScript")
1592     public String getPreLoadScript() {
1593         return preLoadScript;
1594     }
1595 
1596     /**
1597      * Setter for the pre load script
1598      *
1599      * @param preLoadScript
1600      */
1601     public void setPreLoadScript(String preLoadScript) {
1602         this.preLoadScript = preLoadScript;
1603     }
1604 
1605     /**
1606      * The theme which contains stylesheets for this view
1607      *
1608      * @return ViewTheme
1609      */
1610     @BeanTagAttribute(name = "theme", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1611     public ViewTheme getTheme() {
1612         return theme;
1613     }
1614 
1615     /**
1616      * Setter for The theme which contains stylesheets for this view
1617      *
1618      * @return
1619      */
1620     public void setTheme(ViewTheme theme) {
1621         this.theme = theme;
1622     }
1623 
1624     /**
1625      * The stateObject's binding path, this will be used along with the StateMapping's statePropertyName to
1626      * determine what field in the model state information is stored in for this view.  Used during View validation.
1627      *
1628      * @return stateObjectBindingPath path to the object storing state information
1629      */
1630     @BeanTagAttribute(name = "stateObjectBindingPath")
1631     public String getStateObjectBindingPath() {
1632         return stateObjectBindingPath;
1633     }
1634 
1635     /**
1636      * The stateObject's binding path, this will be used along with the StateMapping's statePropertyName to
1637      * determine what field in the model state information is stored in for this view.  Used during View validation.
1638      *
1639      * @param stateObjectBindingPath
1640      */
1641     public void setStateObjectBindingPath(String stateObjectBindingPath) {
1642         this.stateObjectBindingPath = stateObjectBindingPath;
1643     }
1644 
1645     /**
1646      * Gets the stateMapping.
1647      *
1648      * <p>The state mapping object is used to determine the state information for a view,
1649      * it must include an ordered list of states, and where to find the state information for the view.
1650      * A stateMapping must be set for state based validation to occur.  When stateMapping information is
1651      * not included, the view's model is considered stateless and all constraints will apply regardless of their
1652      * state information or replacements (ie, they will function as they did in version 2.1).</p>
1653      *
1654      * @return StateMapping information needed for state based validation, if null no state based validation
1655      *         functionality
1656      *         will exist and configured constraints will apply regardless of state
1657      * @since 2.2
1658      */
1659     @BeanTagAttribute(name = "stateMapping", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1660     public StateMapping getStateMapping() {
1661         return stateMapping;
1662     }
1663 
1664     /**
1665      * Set the stateMapping
1666      *
1667      * @param stateMapping
1668      */
1669     public void setStateMapping(StateMapping stateMapping) {
1670         this.stateMapping = stateMapping;
1671     }
1672 
1673     /**
1674      * @see org.kuali.rice.krad.uif.component.Component#completeValidation
1675      */
1676     @Override
1677     public void completeValidation(ValidationTrace tracer) {
1678         tracer.addBean(this);
1679 
1680         // Check for the presence of a valid item with an not-null EntryPageId
1681         boolean validPageId = false;
1682         if (getEntryPageId() != null) {
1683             for (int i = 0; i < getItems().size(); i++) {
1684                 if (getEntryPageId().compareTo(getItems().get(i).getId()) == 0) {
1685                     validPageId = true;
1686                 }
1687             }
1688         } else {
1689             validPageId = true;
1690         }
1691         if (!validPageId) {
1692             String currentValues[] = {"entryPageId = " + getEntryPageId()};
1693             tracer.createError("Items must contain an item with a matching id to entryPageId", currentValues);
1694         }
1695 
1696         // Check to insure the view as not already been set
1697         if (tracer.getValidationStage() == ValidationTrace.START_UP) {
1698             if (getViewStatus().compareTo(UifConstants.ViewStatus.CREATED) != 0) {
1699                 String currentValues[] = {"viewStatus = " + getViewStatus()};
1700                 tracer.createError("ViewStatus should not be set", currentValues);
1701             }
1702         }
1703 
1704         // Check to insure the binding object path is a valid property
1705         boolean validDefaultBindingObjectPath = false;
1706         if (getDefaultBindingObjectPath() == null) {
1707             validDefaultBindingObjectPath = true;
1708         } else if (DataDictionary.isPropertyOf(getFormClass(), getDefaultBindingObjectPath())) {
1709             validDefaultBindingObjectPath = true;
1710         }
1711         if (!validDefaultBindingObjectPath) {
1712             String currentValues[] =
1713                     {"formClass = " + getFormClass(), "defaultBindingPath = " + getDefaultBindingObjectPath()};
1714             tracer.createError("DefaultBingdingObjectPath must be a valid property of the formClass", currentValues);
1715         }
1716 
1717         // Check to insure the page is set if the view is a single page
1718         if (isSinglePageView()) {
1719             if (getPage() == null) {
1720                 String currentValues[] = {"singlePageView = " + isSinglePageView(), "page = " + getPage()};
1721                 tracer.createError("Page must be set if singlePageView is true", currentValues);
1722             }
1723             for (int i = 0; i < getItems().size(); i++) {
1724                 if (getItems().get(i).getClass() == PageGroup.class) {
1725                     String currentValues[] =
1726                             {"singlePageView = " + isSinglePageView(), "items(" + i + ") = " + getItems().get(i)
1727                                     .getClass()};
1728                     tracer.createError("Items cannot be pageGroups if singlePageView is true", currentValues);
1729                 }
1730             }
1731         }
1732 
1733         // Checks to insure the Growls are set if growl messaging is enabled
1734         if (isGrowlMessagingEnabled() == true && getGrowls() == null) {
1735             if (Validator.checkExpressions(this, "growls")) {
1736                 String currentValues[] =
1737                         {"growlMessagingEnabled = " + isGrowlMessagingEnabled(), "growls = " + getGrowls()};
1738                 tracer.createError("Growls cannot be null if Growl Messaging is enabled", currentValues);
1739             }
1740         }
1741 
1742         // Checks that there are items present if the view is not a single page
1743         if (!isSinglePageView()) {
1744             if (getItems().size() == 0) {
1745                 String currentValues[] =
1746                         {"singlePageView = " + isSinglePageView(), "items.size = " + getItems().size()};
1747                 tracer.createWarning("Items cannot be empty if singlePageView is false", currentValues);
1748             } else {
1749                 for (int i = 0; i < getItems().size(); i++) {
1750                     if (getItems().get(i).getClass() != PageGroup.class) {
1751                         String currentValues[] =
1752                                 {"singlePageView = " + isSinglePageView(), "items(" + i + ") = " + getItems().get(i)
1753                                         .getClass()};
1754                         tracer.createError("Items must be pageGroups if singlePageView is false", currentValues);
1755                     }
1756                 }
1757             }
1758         }
1759         super.completeValidation(tracer.getCopy());
1760     }
1761 
1762 }