View Javadoc
1   /**
2    * Copyright 2005-2015 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.lookup;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.kuali.rice.core.api.mo.common.active.Inactivatable;
26  import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
27  import org.kuali.rice.kim.api.identity.Person;
28  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
29  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
30  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
31  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
32  import org.kuali.rice.krad.uif.UifConstants;
33  import org.kuali.rice.krad.uif.UifConstants.ViewType;
34  import org.kuali.rice.krad.uif.UifParameters;
35  import org.kuali.rice.krad.uif.UifPropertyPaths;
36  import org.kuali.rice.krad.uif.component.Component;
37  import org.kuali.rice.krad.uif.component.RequestParameter;
38  import org.kuali.rice.krad.uif.container.CollectionGroup;
39  import org.kuali.rice.krad.uif.container.Group;
40  import org.kuali.rice.krad.uif.control.Control;
41  import org.kuali.rice.krad.uif.control.FilterableLookupCriteriaControl;
42  import org.kuali.rice.krad.uif.control.FilterableLookupCriteriaControlPostData;
43  import org.kuali.rice.krad.uif.control.TextAreaControl;
44  import org.kuali.rice.krad.uif.control.TextControl;
45  import org.kuali.rice.krad.uif.element.Action;
46  import org.kuali.rice.krad.uif.element.Message;
47  import org.kuali.rice.krad.uif.field.FieldGroup;
48  import org.kuali.rice.krad.uif.field.InputField;
49  import org.kuali.rice.krad.uif.layout.TableLayoutManager;
50  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
51  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleRestriction;
52  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils;
53  import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
54  import org.kuali.rice.krad.uif.lifecycle.initialize.AssignIdsTask;
55  import org.kuali.rice.krad.uif.util.ComponentFactory;
56  import org.kuali.rice.krad.uif.util.ComponentUtils;
57  import org.kuali.rice.krad.uif.util.LifecycleElement;
58  import org.kuali.rice.krad.uif.view.FormView;
59  import org.kuali.rice.krad.util.GlobalVariables;
60  import org.kuali.rice.krad.util.KRADConstants;
61  
62  /**
63   * View type for lookups.
64   *
65   * <p>Supports doing a search against a data object class or performing a more advanced query. The view
66   * type is primarily made up of two groups, the search (or criteria) group and the results group. Many
67   * options are supported on the view to enable/disable certain features, like what actions are available
68   * on the search results.</p>
69   *
70   * <p>Works in conjunction with {@link org.kuali.rice.krad.lookup.Lookupable} which customizes the view and
71   * carries out the business functionality</p>
72   *
73   * @author Kuali Rice Team (rice.collab@kuali.org)
74   */
75  @BeanTag(name = "lookupView", parent = "Uif-LookupView")
76  public class LookupView extends FormView {
77  
78      private static final long serialVersionUID = 716926008488403616L;
79  
80      private Class<?> dataObjectClass;
81  
82      private List<Component> criteriaFields;
83      private Group criteriaGroup;
84  
85      @RequestParameter
86      private boolean hideCriteriaOnSearch;
87  
88      private List<Component> resultFields;
89      private CollectionGroup resultsGroup;
90  
91      private List<String> defaultSortAttributeNames;
92      private boolean defaultSortAscending;
93  
94      @RequestParameter
95      private Boolean renderReturnLink;
96  
97      @RequestParameter
98      private boolean renderResultActions;
99  
100     @RequestParameter
101     private Boolean renderMaintenanceLinks;
102 
103     @RequestParameter
104     private boolean multipleValuesSelect;
105 
106     @RequestParameter
107     private boolean renderLookupCriteria;
108 
109     @RequestParameter
110     private boolean renderCriteriaActions;
111 
112     private Integer resultSetLimit;
113     private Integer multipleValuesSelectResultSetLimit;
114 
115     private String maintenanceUrlMapping;
116 
117     private FieldGroup rangeFieldGroupPrototype;
118     private Message rangedToMessage;
119 
120     private boolean autoAddActiveCriteria;
121 
122     private List<String> additionalSecurePropertyNames;
123 
124     public LookupView() {
125         super();
126 
127         setViewTypeName(ViewType.LOOKUP);
128 
129         defaultSortAscending = true;
130         autoAddActiveCriteria = true;
131         renderLookupCriteria = true;
132         renderCriteriaActions = true;
133         renderResultActions = true;
134 
135         additionalSecurePropertyNames = new ArrayList<String>();
136     }
137 
138     /**
139      * Initializes Lookupable with data object class and sets the abstractTypeClasses map for the
140      * lookup object path.
141      *
142      * {@inheritDoc}
143      */
144     @Override
145     public void performInitialization(Object model) {
146         // init the view helper with the data object class
147         Lookupable lookupable = (Lookupable) getViewHelperService();
148         lookupable.setDataObjectClass(dataObjectClass);
149 
150         initializeGroups();
151 
152         super.performInitialization(model);
153 
154         getObjectPathToConcreteClassMapping().put(UifPropertyPaths.LOOKUP_CRITERIA, getDataObjectClass());
155         if (StringUtils.isNotBlank(getDefaultBindingObjectPath())) {
156             getObjectPathToConcreteClassMapping().put(getDefaultBindingObjectPath(), getDataObjectClass());
157         }
158     }
159 
160     /**
161      * Reads the convenience render flags and sets the corresponding component property, processing the criteria
162      * fields for any adjustments, and invokes the lookup authorizer to determine whether maintenance links should
163      * be shown.
164      *
165      * {@inheritDoc}
166      */
167     @Override
168     public void performApplyModel(Object model, LifecycleElement parent) {
169         LookupForm lookupForm = (LookupForm) model;
170 
171         // don't render criteria group footer/actions
172         if (!renderCriteriaActions || hideCriteriaOnSearch) {
173             criteriaGroup.getFooter().setRender(false);
174         }
175 
176         // don't render criteria if not supposed to or (hide on search results and displaying the results)
177         if (!renderLookupCriteria || (hideCriteriaOnSearch && lookupForm.isDisplayResults())) {
178             criteriaGroup.setRender(false);
179         }
180 
181         // if hide on search results and not displaying search results don't render results
182         if (hideCriteriaOnSearch && !lookupForm.isDisplayResults()) {
183             resultsGroup.setRender(false);
184         }
185 
186         boolean returnLinkAllowed = false;
187         boolean maintenanceLinksAllowed = false;
188 
189         // neither return nor maintenance links are shown for multi-value select
190         if (!multipleValuesSelect) {
191             // if coming from a quickfinder we will show the return URL
192             if ((lookupForm.getInitialRequestParameters() != null) && lookupForm.getInitialRequestParameters()
193                     .containsKey(UifParameters.CONVERSION_FIELDS)) {
194                 returnLinkAllowed = true;
195             } else {
196                 maintenanceLinksAllowed = true;
197             }
198         } else {
199             renderResultActions = false;
200         }
201 
202         // only override view properties if they were not manually configured
203         if (renderReturnLink == null) {
204             renderReturnLink = returnLinkAllowed;
205         }
206 
207         if (renderMaintenanceLinks == null) {
208             renderMaintenanceLinks = maintenanceLinksAllowed;
209         }
210 
211         // if maintenance links enabled, verify the user had permission
212         if (renderMaintenanceLinks) {
213             LookupViewAuthorizerBase lookupAuthorizer = (LookupViewAuthorizerBase) getAuthorizer();
214 
215             Person user = GlobalVariables.getUserSession().getPerson();
216             renderMaintenanceLinks = lookupAuthorizer.canInitiateMaintenanceDocument(getDataObjectClass().getName(),
217                     user);
218         }
219 
220         // autoTruncateColumns: use system wide lookup result configuration if not specified
221         if (this.getResultsGroup().getLayoutManager() instanceof TableLayoutManager) {
222             TableLayoutManager resultsTableLayoutManager =
223                     (TableLayoutManager) this.getResultsGroup().getLayoutManager();
224             if (resultsTableLayoutManager.isAutoTruncateColumns() == null) {
225                 resultsTableLayoutManager.setAutoTruncateColumns(
226                         CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
227                                 KRADConstants.KRAD_NAMESPACE, KRADConstants.DetailTypes.LOOKUP_PARM_DETAIL_TYPE,
228                                 KRADConstants.SystemGroupParameterNames.AUTO_TRUNCATE_COLUMNS, false));
229             }
230         }
231 
232         convertLookupCriteriaFields(criteriaGroup);
233 
234         super.performApplyModel(model, parent);
235     }
236 
237     /**
238      * Forces session persistence on the criteria fields so the search criteria can be validated on post.
239      *
240      * {@inheritDoc}
241      */
242     @Override
243     public void performFinalize(Object model, LifecycleElement parent) {
244         super.performFinalize(model, parent);
245 
246         LookupForm lookupForm = (LookupForm) model;
247         String viewId = lookupForm.getViewId();
248 
249         Map<String, FilterableLookupCriteriaControlPostData> filterableLookupCriteria =
250                 new HashMap<String, FilterableLookupCriteriaControlPostData>();
251 
252         List<InputField> fields = ViewLifecycleUtils.getElementsOfTypeDeep(criteriaGroup, InputField.class);
253 
254         for (InputField field : fields) {
255             field.setForceSessionPersistence(true);
256 
257             String propertyName = field.getPropertyName();
258 
259             if (field.getControl() instanceof FilterableLookupCriteriaControl) {
260                 FilterableLookupCriteriaControl control = (FilterableLookupCriteriaControl) field.getControl();
261                 filterableLookupCriteria.put(propertyName, control.getPostData(propertyName));
262             }
263         }
264 
265         ViewPostMetadata viewPostMetadata = ViewLifecycle.getViewPostMetadata();
266         viewPostMetadata.addComponentPostData(viewId, UifConstants.PostMetadata.FILTERABLE_LOOKUP_CRITERIA,
267                 filterableLookupCriteria);
268 
269         if (lookupForm.isReturnByScript()) {
270             getAdditionalHiddenValues().put(UifParameters.RETURN_BY_SCRIPT, "true");
271         }
272 
273         // if the lookup was called within a dialog then we want to add it to the action's parameters
274         String dialogId = lookupForm.getShowDialogId();
275         if (StringUtils.isNotBlank(dialogId)) {
276             List<Action> actions = ViewLifecycleUtils.getElementsOfTypeDeep(getFooter().getItems(), Action.class);
277 
278             for (Action action : actions) {
279                 action.addActionParameter(UifParameters.DIALOG_ID, dialogId);
280             }
281         } else {
282             dialogId = lookupForm.getActionParamaterValue(UifParameters.DIALOG_ID);
283             lookupForm.setShowDialogId(dialogId);
284         }
285     }
286 
287     /**
288      * Adds the 'active' property criteria to the criteria fields if the BO is inactivatable and their is
289      * not already a lookup field for the active property.
290      */
291     protected void addActiveCriteriaIfNecessary() {
292         boolean isInactivatableClass = Inactivatable.class.isAssignableFrom(dataObjectClass);
293 
294         if (!autoAddActiveCriteria || !isInactivatableClass) {
295             return;
296         }
297 
298         boolean hasActiveCriteria = false;
299         for (Component field : getCriteriaFields()) {
300             if (((InputField) field).getPropertyName().equals(UifPropertyPaths.ACTIVE)) {
301                 hasActiveCriteria = true;
302             }
303         }
304 
305         if (hasActiveCriteria) {
306             return;
307         }
308 
309         AttributeDefinition attributeDefinition =
310                 KRADServiceLocatorWeb.getDataDictionaryService().getAttributeDefinition(dataObjectClass.getName(),
311                         UifPropertyPaths.ACTIVE);
312 
313         LookupInputField activeLookupField;
314         if (attributeDefinition == null) {
315             activeLookupField = (LookupInputField) ComponentFactory.getNewComponentInstance(
316                     ComponentFactory.LOOKUP_ACTIVE_INPUT_FIELD);
317         } else {
318             activeLookupField = (LookupInputField) ComponentFactory.getNewComponentInstance(
319                     ComponentFactory.LOOKUP_INPUT_FIELD);
320 
321             activeLookupField.setPropertyName(UifPropertyPaths.ACTIVE);
322             activeLookupField.copyFromAttributeDefinition(attributeDefinition);
323         }
324 
325         getCriteriaFields().add(activeLookupField);
326     }
327 
328     /**
329      * Adds the list of criteria and result fields to their group prototypes, then adds the criteria and result
330      * groups to the items for the view.
331      */
332     protected void initializeGroups() {
333         if ((getCriteriaGroup() != null) && (getCriteriaGroup().getItems().isEmpty())) {
334             getCriteriaGroup().setItems(getCriteriaFields());
335         }
336 
337         if (getResultsGroup() != null) {
338             if ((getResultsGroup().getItems().isEmpty()) && (getResultFields() != null)) {
339                 getResultsGroup().setItems(getResultFields());
340             }
341 
342             if (getResultsGroup().getCollectionObjectClass() == null) {
343                 getResultsGroup().setCollectionObjectClass(getDataObjectClass());
344             }
345         }
346 
347         if (getItems().isEmpty()) {
348             setItems(Arrays.asList(getCriteriaGroup(), getResultsGroup()));
349         }
350     }
351 
352     /**
353      * Performs conversions of the lookup criteria fields within the given group's items.
354      *
355      * <p>Max lengths are removed on text controls so wildcards can be added. Ranged date fields are
356      * converted to field groups with the from/to date fields</p>
357      */
358     protected void convertLookupCriteriaFields(Group lookupGroup) {
359         @SuppressWarnings("unchecked")
360         List<Component> criteriaGroupItems = (List<Component>) lookupGroup.getItems();
361 
362         // holds the index and range field group for replacement into the items
363         HashMap<Integer, Component> dateRangeFieldMap = new HashMap<Integer, Component>();
364 
365         int rangeIndex = 0;
366         for (Component component : criteriaGroupItems) {
367             if (component == null) {
368                 continue;
369             }
370 
371             if (Group.class.isAssignableFrom(component.getClass())) {
372                 convertLookupCriteriaFields((Group) component);
373             } else if (FieldGroup.class.isAssignableFrom(component.getClass())) {
374                 convertLookupCriteriaFields(((FieldGroup) component).getGroup());
375             } else if (LookupInputField.class.isAssignableFrom(component.getClass())) {
376                 LookupInputField lookupInputField = (LookupInputField) component;
377 
378                 // set the max length on the controls to allow for wildcards
379                 Control control = lookupInputField.getControl();
380 
381                 if (control instanceof TextControl) {
382                     ((TextControl) control).setMaxLength(null);
383                 } else if (control instanceof TextAreaControl) {
384                     ((TextAreaControl) control).setMaxLength(null);
385                 }
386 
387                 if (lookupInputField.isRanged()) {
388                     FieldGroup rangeFieldGroup = createDateRangeFieldGroup(lookupInputField);
389 
390                     dateRangeFieldMap.put(rangeIndex, rangeFieldGroup);
391                 }
392             }
393 
394             rangeIndex++;
395         }
396 
397         // replace original fields with range field groups
398         for (Integer index : dateRangeFieldMap.keySet()) {
399             criteriaGroupItems.set(index, dateRangeFieldMap.get(index));
400         }
401 
402         criteriaGroup.setItems(criteriaGroupItems);
403     }
404 
405     /**
406      * Creates a {@link FieldGroup} instance to replace the given lookup input field as a
407      * date criteria range.
408      *
409      * <p>The field group is created by copying {@link LookupView#rangeFieldGroupPrototype}. This can be
410      * used to configure how the field group will appear. In addition, the two lookup fields are separated
411      * with a message that can be configured with {@link LookupView#rangedToMessage}</p>
412      *
413      * @param toDate lookup input field that field group should be build for
414      * @return field group that contains a from and to lookup input field for searching a date range
415      *
416      * @see LookupView#rangeFieldGroupPrototype
417      * @see LookupView#rangedToMessage
418      */
419     protected FieldGroup createDateRangeFieldGroup(LookupInputField toDate) {
420         // Generate an ID when the "to date" field is out of the normal lifecycle flow
421         if (toDate.getId() == null) {
422             toDate.setId(AssignIdsTask.generateId(toDate, ViewLifecycle.getView()));
423         }
424 
425         FieldGroup rangeFieldGroup = ComponentUtils.copy(getRangeFieldGroupPrototype());
426 
427         // Copy some properties from the "to date" field to the field group
428         rangeFieldGroup.setFieldLabel(ComponentUtils.copy(toDate.getFieldLabel()));
429         rangeFieldGroup.setPropertyExpressions(toDate.getPropertyExpressions());
430         rangeFieldGroup.setProgressiveRender(toDate.getProgressiveRender());
431         rangeFieldGroup.setProgressiveRenderViaAJAX(toDate.isProgressiveRenderViaAJAX());
432         rangeFieldGroup.setConditionalRefresh(toDate.getConditionalRefresh());
433         rangeFieldGroup.setRefreshWhenChangedPropertyNames(toDate.getRefreshWhenChangedPropertyNames());
434         rangeFieldGroup.setForceSessionPersistence(true);
435 
436         // Reset some fields for the "to date" field
437         toDate.getFieldLabel().setRender(false);
438         toDate.setRefreshWhenChangedPropertyNames(null);
439         toDate.setForceSessionPersistence(true);
440 
441         // Create a "from date" field from the "to date" field
442         LookupInputField fromDate = ComponentUtils.copy(toDate,
443                 KRADConstants.LOOKUP_DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL);
444         fromDate.getBindingInfo().setBindingName(
445                 KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + fromDate.getPropertyName());
446         fromDate.setPropertyName(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + fromDate.getPropertyName());
447         fromDate.setOrder(0);
448 
449         // add the criteria fields to the field group
450         List<Component> fieldGroupItems = new ArrayList<Component>();
451         fieldGroupItems.add(fromDate);
452         fieldGroupItems.add(rangedToMessage);
453         fieldGroupItems.add(toDate);
454         rangeFieldGroup.setItems(fieldGroupItems);
455 
456         return rangeFieldGroup;
457     }
458 
459     /**
460      * Class for the data object the lookup applies to.
461      *
462      * <p>The object class name is used to pick up a dictionary entry which will feed the attribute field
463      * definitions and other configuration. In addition it is to configure the
464      * {@link org.kuali.rice.krad.lookup.Lookupable} which will carry out the search action</p>
465      *
466      * @return lookup data object class
467      */
468     @BeanTagAttribute(name = "dataObjectClass")
469     public Class<?> getDataObjectClass() {
470         return this.dataObjectClass;
471     }
472 
473     /**
474      * @see LookupView#getDataObjectClass()
475      */
476     public void setDataObjectClass(Class<?> dataObjectClass) {
477         this.dataObjectClass = dataObjectClass;
478     }
479 
480     /**
481      * Convenience setter to configure the lookup data object class by class name.
482      *
483      * @param dataObjectClassName full class name for the lookup data object
484      */
485     public void setDataObjectClassName(String dataObjectClassName) {
486         try {
487             this.dataObjectClass = Class.forName(dataObjectClassName);
488         } catch (ClassNotFoundException e) {
489             throw new RuntimeException("Unable to set class for class name: " + dataObjectClassName, e);
490         }
491     }
492 
493     /**
494      * Indicates whether a return value link should be rendered for each result row.
495      *
496      * <p>When the lookup is called from a view (using a {@link org.kuali.rice.krad.uif.widget.QuickFinder} the return
497      * link can be returned to allow the user to return a value(s) for a selected row. Note, if this is not manually
498      * set the framework will determine when the lookup is called from a quickfinder and turn this flag on</p>
499      *
500      * @return boolean true if the return link should be rendered for each result row, false if not
501      */
502     @BeanTagAttribute(name = "renderReturnLink")
503     public Boolean isRenderReturnLink() {
504         return this.renderReturnLink;
505     }
506 
507     /**
508      * @see LookupView#isRenderReturnLink()
509      */
510     public void setRenderReturnLink(Boolean renderReturnLink) {
511         this.renderReturnLink = renderReturnLink;
512     }
513 
514     /**
515      * Indicates whether the actions column for the search results collection group should be rendered (default
516      * is true).
517      *
518      * <p>Note this is a convenience property for setting the render property on the result collection group</p>
519      *
520      * @return boolean true if the result actions column should be rendered, false if not
521      */
522     @BeanTagAttribute(name = "isRenderResultActions")
523     public boolean isRenderResultActions() {
524         return this.renderResultActions;
525     }
526 
527     /**
528      * @see LookupView#isRenderResultActions()
529      */
530     public void setRenderResultActions(boolean renderResultActions) {
531         this.renderResultActions = renderResultActions;
532     }
533 
534     /**
535      * Indicates whether links for maintenance actions (new, edit, copy, delete) should be rendered.
536      *
537      * <p>When this property is not manually set it will be enabled by the framework when a lookup is not invoked
538      * from a quickfinder (for example a standard link from a menu). Regardless if the flag is manually enabled
539      * or enabled by the framework, an additional authorization check will be performed to determine if the user
540      * has initiate permission for the maintenance document associated with the lookup data object class. If not,
541      * this flag will be disabled</p>
542      *
543      * @return boolean true if maintenance links should be rendered, false if not
544      */
545     @BeanTagAttribute(name = "renderMaintenanceLinks")
546     public Boolean isRenderMaintenanceLinks() {
547         return this.renderMaintenanceLinks;
548     }
549 
550     /**
551      * @see LookupView#isRenderMaintenanceLinks()
552      */
553     public void setRenderMaintenanceLinks(Boolean renderMaintenanceLinks) {
554         this.renderMaintenanceLinks = renderMaintenanceLinks;
555     }
556 
557     /**
558      * Indicates whether multiple values select should be enabled for the lookup.
559      *
560      * <p>When set to true, the select field is enabled for the lookup results group that allows the user
561      * to select one or more rows for returning. The framework will also set the {@link #isRenderReturnLink()}
562      * and {@link #isRenderMaintenanceLinks()} properties to false (unless manually overridden)</p>
563      *
564      * @return true if multiple values select should be enabled, false otherwise
565      */
566     @BeanTagAttribute(name = "multipleValueSelect")
567     public boolean isMultipleValuesSelect() {
568         return multipleValuesSelect;
569     }
570 
571     /**
572      * @see LookupView#isMultipleValuesSelect()
573      */
574     public void setMultipleValuesSelect(boolean multipleValuesSelect) {
575         this.multipleValuesSelect = multipleValuesSelect;
576     }
577 
578     /**
579      * List of fields that will be rendered for the lookup criteria.
580      *
581      * <p>This is a convenience property for setting the items in {@link #getCriteriaGroup()}, which is the
582      * group the criteria for the lookup is rendered in. This property can be bypassed and the items set
583      * directly in the criteria group (for more flexibility)</p>
584      *
585      * @return List of components to render as the lookup criteria
586      */
587     @ViewLifecycleRestriction
588     @BeanTagAttribute(name = "criteriaFields", type = BeanTagAttribute.AttributeType.LISTBEAN)
589     public List<Component> getCriteriaFields() {
590         return this.criteriaFields;
591     }
592 
593     /**
594      * @see LookupView#getCriteriaFields()
595      */
596     public void setCriteriaFields(List<Component> criteriaFields) {
597         this.criteriaFields = criteriaFields;
598     }
599 
600     /**
601      * Component {@link Group} instance to render as search criteria.
602      *
603      * <p>Fields that make up the criteria for the lookup will be rendered in this group. This can be used in a few
604      * different ways:
605      *
606      * <ul>
607      * <li>Set the group to have the desired layout, style, and other general group properties. Note this
608      * is done in the base lookup view. The actual criteria fields can then be configured using
609      * {@link #getCriteriaFields()}</li>
610      * <li>Configure the criteria group entirely (ignoring criteria fields). This would allow you to do things
611      * like have multiple groups for the criteria.</li>
612      * </ul></p>
613      *
614      * <p>Note the footer for the criteria group can contain actions (such as search, clear, custom actions)</p>
615      *
616      * @return group instance that will hold the search criteria fields
617      */
618     @ViewLifecycleRestriction
619     @BeanTagAttribute(name = "criteriaGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
620     public Group getCriteriaGroup() {
621         return this.criteriaGroup;
622     }
623 
624     /**
625      * @see LookupView#getCriteriaGroup()
626      */
627     public void setCriteriaGroup(Group criteriaGroup) {
628         this.criteriaGroup = criteriaGroup;
629     }
630 
631     public boolean isHideCriteriaOnSearch() {
632         return hideCriteriaOnSearch;
633     }
634 
635     public void setHideCriteriaOnSearch(boolean hideCriteriaOnSearch) {
636         this.hideCriteriaOnSearch = hideCriteriaOnSearch;
637     }
638 
639     /**
640      * List of fields that will be rendered for the result collection group, each field will be a column
641      * (assuming table layout is used).
642      *
643      * <p>This is a convenience property for setting the items in {@link #getResultsGroup()}, which is the
644      * collection group the results for the lookup is rendered in. This property can be bypassed and the items set
645      * directly in the results group (for more flexibility)</p>
646      *
647      * @return List of components to render in the results group
648      */
649     @ViewLifecycleRestriction
650     @BeanTagAttribute(name = "resultFields", type = BeanTagAttribute.AttributeType.LISTBEAN)
651     public List<Component> getResultFields() {
652         return this.resultFields;
653     }
654 
655     /**
656      * @see LookupView#getResultFields()
657      */
658     public void setResultFields(List<Component> resultFields) {
659         this.resultFields = resultFields;
660     }
661 
662     /**
663      * Component {@link CollectionGroup} instance to render for the lookup results.
664      *
665      * <p>After a search is performed, the resulting data objects will be rendered in this collection group. This
666      * collection group can be used in two ways:
667      *
668      * <ul>
669      * <li>Set the desired layout, style, and other general collection group properties. Note this is done
670      * in the base lookup view. Then the actual fields that are rendered in the collection group can be
671      * configured using {@link #getResultFields()}</li>
672      * <li>Configure the results group entirely (ignoring result fields)</li>
673      * </ul></p>
674      *
675      * <p>Note actions that are presented for the results can be configured using the
676      * {@link org.kuali.rice.krad.uif.container.CollectionGroup#getLineActions()} property</p>
677      *
678      * @return collection group instance to render for the lookup results
679      */
680     @ViewLifecycleRestriction
681     @BeanTagAttribute(name = "resultsGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
682     public CollectionGroup getResultsGroup() {
683         return this.resultsGroup;
684     }
685 
686     /**
687      * @see LookupView#getResultsGroup()
688      */
689     public void setResultsGroup(CollectionGroup resultsGroup) {
690         this.resultsGroup = resultsGroup;
691     }
692 
693     /**
694      * List of property names on the configured data object class that will be used to perform the initial
695      * sorting of the search results.
696      *
697      * @return list of property names valid for the configured data object class
698      *
699      * @see LookupView#isDefaultSortAscending()
700      */
701     @BeanTagAttribute(name = "defaultSortAttributeNames", type = BeanTagAttribute.AttributeType.LISTVALUE)
702     public List<String> getDefaultSortAttributeNames() {
703         return this.defaultSortAttributeNames;
704     }
705 
706     /**
707      * @see LookupView#getDefaultSortAttributeNames()
708      */
709     public void setDefaultSortAttributeNames(List<String> defaultSortAttributeNames) {
710         this.defaultSortAttributeNames = defaultSortAttributeNames;
711     }
712 
713     /**
714      * Indicates whether the initial sort performed using {@link #getDefaultSortAttributeNames()} is done based
715      * on ascending or descending order (default is true, ascending).
716      *
717      * @return boolean true if ascending sort should be performed, false if descending sort should be
718      * performed
719      */
720     @BeanTagAttribute(name = "defaultSortAscending")
721     public boolean isDefaultSortAscending() {
722         return this.defaultSortAscending;
723     }
724 
725     /**
726      * @see LookupView#isDefaultSortAscending()
727      */
728     public void setDefaultSortAscending(boolean defaultSortAscending) {
729         this.defaultSortAscending = defaultSortAscending;
730     }
731 
732     /**
733      * Retrieves the maximum number of records that will be listed as a result of the lookup search.
734      *
735      * @return Integer result set limit
736      */
737     @BeanTagAttribute(name = "resultSetLimit")
738     public Integer getResultSetLimit() {
739         return resultSetLimit;
740     }
741 
742     /**
743      * @see LookupView#getResultSetLimit()
744      */
745     public void setResultSetLimit(Integer resultSetLimit) {
746         this.resultSetLimit = resultSetLimit;
747     }
748 
749     /**
750      * Retrieves the maximum number of records that will be listed as a result of the multiple
751      * values select lookup search.
752      *
753      * @return multiple values select result set limit
754      */
755     @BeanTagAttribute(name = "multipleValuesSelectResultSetLimit")
756     public Integer getMultipleValuesSelectResultSetLimit() {
757         return multipleValuesSelectResultSetLimit;
758     }
759 
760     /**
761      * @see LookupView#getMultipleValuesSelectResultSetLimit()
762      */
763     public void setMultipleValuesSelectResultSetLimit(Integer multipleValuesSelectResultSetLimit) {
764         this.multipleValuesSelectResultSetLimit = multipleValuesSelectResultSetLimit;
765     }
766 
767     /**
768      * String that maps to the maintenance controller for the maintenance document (if any) associated with the
769      * lookup data object class.
770      *
771      * <p>Mapping will be used to build the maintenance action links (such as edit, copy, and new). If not given, the
772      * default maintenance mapping will be used</p>
773      *
774      * @return mapping string
775      */
776     @BeanTagAttribute(name = "maintenanceUrlMapping")
777     public String getMaintenanceUrlMapping() {
778         return maintenanceUrlMapping;
779     }
780 
781     /**
782      * @see LookupView#getMaintenanceUrlMapping()
783      */
784     public void setMaintenanceUrlMapping(String maintenanceUrlMapping) {
785         this.maintenanceUrlMapping = maintenanceUrlMapping;
786     }
787 
788     /**
789      * Indicates whether the action buttons like search in the criteria group footer should be rendered,
790      * defaults to true.
791      *
792      * @return boolean true if the criteria actions should be rendered, false if not
793      */
794     public boolean isRenderCriteriaActions() {
795         return renderCriteriaActions;
796     }
797 
798     /**
799      * @see LookupView#isRenderCriteriaActions()
800      */
801     public void setRenderCriteriaActions(boolean renderCriteriaActions) {
802         this.renderCriteriaActions = renderCriteriaActions;
803     }
804 
805     /**
806      * Indicates whether the lookup criteria group should be rendered, default to true.
807      *
808      * <p>Hiding the criteria group can be useful in cases where the criteria is passed in through the request and
809      * also the search is executed on the initial request</p>
810      *
811      * @return boolean true if criteria group should be rendered, false if not
812      */
813     public boolean isRenderLookupCriteria() {
814         return renderLookupCriteria;
815     }
816 
817     /**
818      * @see LookupView#isRenderLookupCriteria()
819      */
820     public void setRenderLookupCriteria(boolean renderLookupCriteria) {
821         this.renderLookupCriteria = renderLookupCriteria;
822     }
823 
824     /**
825      * Field group prototype that will be copied to create any date range field groups.
826      *
827      * @return field group instance to use for creating range field groups
828      */
829     @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
830     public FieldGroup getRangeFieldGroupPrototype() {
831         return rangeFieldGroupPrototype;
832     }
833 
834     /**
835      * @see LookupView#getRangeFieldGroupPrototype()
836      */
837     public void setRangeFieldGroupPrototype(FieldGroup rangeFieldGroupPrototype) {
838         this.rangeFieldGroupPrototype = rangeFieldGroupPrototype;
839     }
840 
841     /**
842      * Component {@link Message} instance to render between the range criteria fields within a range
843      * field group.
844      *
845      * @return message instance for range field group
846      */
847     @ViewLifecycleRestriction(UifConstants.ViewPhases.INITIALIZE)
848     public Message getRangedToMessage() {
849         return rangedToMessage;
850     }
851 
852     /**
853      * @see LookupView#getRangedToMessage()
854      */
855     public void setRangedToMessage(Message rangedToMessage) {
856         this.rangedToMessage = rangedToMessage;
857     }
858 
859     /**
860      * Indicates whether the 'active' criteria field must be added automatically for Inactivatable business
861      * objects.
862      *
863      * @return boolean true if active criteria should be added
864      */
865     public boolean isAutoAddActiveCriteria() {
866         return autoAddActiveCriteria;
867     }
868 
869     /**
870      * @see LookupView#isAutoAddActiveCriteria()
871      */
872     public void setAutoAddActiveCriteria(boolean autoAddActiveCriteria) {
873         this.autoAddActiveCriteria = autoAddActiveCriteria;
874     }
875 
876     /**
877      * List of secure property names that are in addition to the
878      * {@link org.kuali.rice.krad.uif.component.ComponentSecurity} or
879      * {@link org.kuali.rice.krad.datadictionary.AttributeSecurity} attributes.
880      *
881      * @return list of secure property names
882      */
883     @BeanTagAttribute(name = "additionalSecurePropertyNames", type = BeanTagAttribute.AttributeType.LISTVALUE)
884     public List<String> getAdditionalSecurePropertyNames() {
885         return additionalSecurePropertyNames;
886     }
887 
888     /**
889      * @see LookupView#getAdditionalSecurePropertyNames()
890      */
891     public void setAdditionalSecurePropertyNames(List<String> additionalSecurePropertyNames) {
892         this.additionalSecurePropertyNames = additionalSecurePropertyNames;
893     }
894 }