View Javadoc

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