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