View Javadoc

1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.view;
17  
18  import com.google.common.collect.Lists;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.mo.common.active.Inactivatable;
21  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
22  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
23  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
24  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
25  import org.kuali.rice.krad.uif.UifConstants.ViewType;
26  import org.kuali.rice.krad.uif.UifPropertyPaths;
27  import org.kuali.rice.krad.uif.container.CollectionGroup;
28  import org.kuali.rice.krad.uif.container.Group;
29  import org.kuali.rice.krad.uif.component.Component;
30  import org.kuali.rice.krad.uif.component.RequestParameter;
31  import org.kuali.rice.krad.uif.control.Control;
32  import org.kuali.rice.krad.uif.control.TextAreaControl;
33  import org.kuali.rice.krad.uif.control.TextControl;
34  import org.kuali.rice.krad.uif.element.Action;
35  import org.kuali.rice.krad.uif.element.Message;
36  import org.kuali.rice.krad.uif.field.FieldGroup;
37  import org.kuali.rice.krad.uif.field.InputField;
38  import org.kuali.rice.krad.uif.field.LookupInputField;
39  import org.kuali.rice.krad.uif.util.ComponentFactory;
40  import org.kuali.rice.krad.uif.util.ComponentUtils;
41  import org.kuali.rice.krad.util.KRADConstants;
42  import org.kuali.rice.krad.web.form.LookupForm;
43  
44  import java.util.ArrayList;
45  import java.util.Arrays;
46  import java.util.HashMap;
47  import java.util.List;
48  
49  /**
50   * View type for lookups
51   *
52   * <p>
53   * Supports doing a search against a data object class or performing a more advanced query. The view
54   * type is primarily made up of two groups, the search (or criteria) group and the results group. Many
55   * options are supported on the view to enable/disable certain features, like what actions are available
56   * on the search results.
57   * </p>
58   *
59   * <p>
60   * Works in conjunction with <code>LookupableImpl</code> which customizes the view and carries out the
61   * business functionality
62   * </p>
63   *
64   * @author Kuali Rice Team (rice.collab@kuali.org)
65   */
66  @BeanTag(name = "lookupView-bean", parent = "Uif-LookupView")
67  public class LookupView extends FormView {
68      private static final long serialVersionUID = 716926008488403616L;
69  
70      private Class<?> dataObjectClassName;
71  
72      private Group criteriaGroup;
73      private CollectionGroup resultsGroup;
74  
75      private List<Component> criteriaFields;
76      private List<Component> resultFields;
77      private List<String> defaultSortAttributeNames;
78  
79      protected boolean defaultSortAscending = true;
80  
81      @RequestParameter
82      private boolean hideReturnLinks = false;
83      @RequestParameter
84      private boolean suppressActions = false;
85      @RequestParameter
86      private boolean showMaintenanceLinks = false;
87      @RequestParameter
88      private boolean multipleValuesSelect = false;
89      @RequestParameter
90      private boolean renderLookupCriteria = true;
91      @RequestParameter
92      private boolean renderSearchButtons = true;
93      @RequestParameter
94      private boolean renderHeader = true;
95  
96      @RequestParameter
97      private String returnTarget;
98  
99      @RequestParameter
100     private boolean returnByScript;
101 
102     private boolean triggerOnChange;
103 
104     private Integer resultSetLimit = null;
105     private Integer multipleValuesSelectResultSetLimit = null;
106 
107     private String maintenanceUrlMapping;
108 
109     private FieldGroup rangeFieldGroupPrototype;
110 
111     private Message rangedToMessage;
112 
113     private boolean autoAddActiveCriteria;
114 
115     public LookupView() {
116         super();
117 
118         setViewTypeName(ViewType.LOOKUP);
119         setApplyDirtyCheck(false);
120         setTriggerOnChange(false);
121         setAutoAddActiveCriteria(true);
122     }
123 
124     /**
125      * The following initialization is performed:
126      *
127      * <ul>
128      * <li>Set the abstractTypeClasses map for the lookup object path</li>
129      * </ul>
130      *
131      * @see org.kuali.rice.krad.uif.container.ContainerBase#performInitialization(org.kuali.rice.krad.uif.view.View,
132      *      java.lang.Object)
133      */
134     @Override
135     public void performInitialization(View view, Object model) {
136 
137         boolean isInactivatableClass = Inactivatable.class.isAssignableFrom(dataObjectClassName);
138 
139         if (autoAddActiveCriteria && isInactivatableClass) {
140             autoAddActiveCriteria();
141         }
142 
143         initializeGroups();
144 
145         // since we don't have these as prototypes need to assign ids here
146         view.assignComponentIds(getCriteriaGroup());
147         view.assignComponentIds(getResultsGroup());
148 
149         if (getItems().isEmpty()) {
150             setItems(Arrays.asList(getCriteriaGroup(), getResultsGroup()));
151         }
152 
153         super.performInitialization(view, model);
154 
155         // if this is a multi-value lookup, don't show return column
156         if (multipleValuesSelect) {
157             hideReturnLinks = true;
158         }
159 
160         getObjectPathToConcreteClassMapping().put(UifPropertyPaths.LOOKUP_CRITERIA, getDataObjectClassName());
161         if (StringUtils.isNotBlank(getDefaultBindingObjectPath())) {
162             getObjectPathToConcreteClassMapping().put(getDefaultBindingObjectPath(), getDataObjectClassName());
163         }
164     }
165 
166     /**
167      * Adds the 'active' property criteria to the criteria fields if the BO is inactivatable
168      */
169     private void autoAddActiveCriteria() {
170         boolean hasActiveCriteria = false;
171 
172         for (Component field : getCriteriaFields()) {
173             if (((InputField)field).getPropertyName().equals("active")) {
174                 hasActiveCriteria = true;
175             }
176         }
177 
178         if (!hasActiveCriteria) {
179             AttributeDefinition attributeDefinition = KRADServiceLocatorWeb.getDataDictionaryService().getAttributeDefinition(
180                     dataObjectClassName.getName(), "active");
181             LookupInputField activeField = new LookupInputField();
182 
183             if (attributeDefinition == null) {
184                 activeField = (LookupInputField)ComponentFactory.getNewComponentInstance("Uif-LookupActiveInputField");
185             }else{
186                 activeField = (LookupInputField)ComponentFactory.getNewComponentInstance("Uif-LookupCriteriaInputField");
187                 activeField.setPropertyName("active");
188                 activeField.copyFromAttributeDefinition(this, attributeDefinition);
189             }
190 
191             getCriteriaFields().add(activeField);
192         }
193     }
194 
195     protected void initializeGroups() {
196         if (renderLookupCriteria && (getCriteriaGroup() != null) && (getCriteriaGroup().getItems().isEmpty())) {
197             getCriteriaGroup().setItems(getCriteriaFields());
198         }
199 
200         if (getResultsGroup() != null) {
201             if ((getResultsGroup().getItems().isEmpty()) && (getResultFields() != null)) {
202                 getResultsGroup().setItems(getResultFields());
203             }
204             if (getResultsGroup().getCollectionObjectClass() == null) {
205                 getResultsGroup().setCollectionObjectClass(getDataObjectClassName());
206             }
207         }
208     }
209 
210     /**
211      * @see org.kuali.rice.krad.uif.container.ContainerBase#performApplyModel(View, Object,
212      * org.kuali.rice.krad.uif.component.Component)
213      */
214     @Override
215     public void performApplyModel(View view, Object model, Component parent) {
216         LookupForm lookupForm = (LookupForm) model;
217 
218         if (!renderSearchButtons) {
219             criteriaGroup.getFooter().setRender(false);
220         }
221 
222         if (!renderLookupCriteria) {
223             criteriaGroup.setRender(false);
224         }
225 
226         if (!renderHeader) {
227             getHeader().setRender(false);
228         }
229 
230         setupLookupCriteriaFields(view, model);
231 
232         // Get the search action button for trigger on change and trigger on enter
233         Group actionGroup = criteriaGroup.getFooter();
234         Action searchButton = findSearchButton(actionGroup.getItems());
235 
236         // Only add trigger on script if an action with methodToCall search exists
237         if (searchButton != null) {
238             String searchButtonId = searchButton.getId();
239 
240             for (Component criteriaField : criteriaGroup.getItems()) {
241                 addTriggerScripts(searchButtonId, criteriaField);
242             }
243         }
244 
245         super.performApplyModel(view, model, parent);
246     }
247 
248     /**
249      * @see org.kuali.rice.krad.uif.container.ContainerBase#performFinalize(org.kuali.rice.krad.uif.view.View,
250      *      Object, org.kuali.rice.krad.uif.component.Component)
251      */
252     @Override
253     public void performFinalize(View view, Object model, Component parent) {
254         super.performFinalize(view, model, parent);
255 
256         // force session persistence of criteria fields so we can validate the search input
257         List<InputField> fields = ComponentUtils.getComponentsOfTypeDeep(criteriaGroup, InputField.class);
258         for (InputField field : fields) {
259             field.setForceSessionPersistence(true);
260         }
261     }
262 
263     /**
264      * Adds an on change script to fields with the isTriggerOnChange set to true. Also prevents adds script to execute
265      * search on enter when focus is in a criteris field
266      *
267      * @param searchButtonId the id of the search button
268      * @param criteriaField that the script will be added to
269      */
270     private void addTriggerScripts(String searchButtonId, Component criteriaField) {
271         if (criteriaField instanceof LookupInputField) {
272 
273             criteriaField.setOnKeyPressScript("if(e.which == 13) { e.preventDefault();jQuery('#" + searchButtonId + "' ).click();}");
274 
275             if (isTriggerOnChange() || ((LookupInputField)criteriaField).isTriggerOnChange()) {
276                 criteriaField.setOnChangeScript("jQuery('#" + searchButtonId + "' ).click();");
277             }
278         }
279     }
280 
281     /**
282      * Finds an Action with the search methodToCall from a list of Actions
283      *
284      * @param componentList list of components
285      * @return the Action component with methodToCall of search
286      */
287     private Action findSearchButton(List<? extends Component> componentList) {
288         List<? extends Action> actionList = ComponentUtils.getComponentsOfType(componentList, Action.class);
289         for (Action action : actionList) {
290             String methodToCall = action.getMethodToCall();
291             if (methodToCall != null && methodToCall.equals("search")) {
292                 return action;
293             }
294         }
295         return null;
296     }
297 
298     /**
299      * Helper method to do any lookup specific changes to the criteria fields
300      */
301     private void setupLookupCriteriaFields(View view, Object model) {
302         HashMap<Integer, Component> dateRangeFieldMap = new HashMap<Integer, Component>();
303 
304         ExpressionEvaluator expressionEvaluator =
305                 view.getViewHelperService().getExpressionEvaluator();
306 
307         int rangeIndex = 0;
308         for (Component criteriaField : criteriaGroup.getItems()) {
309             // Set the max length on the controls to allow for wildcards
310             Control control = ((InputField)criteriaField).getControl();
311             if (control instanceof TextControl) {
312                 ((TextControl) control).setMaxLength(null);
313             } else if (control instanceof TextAreaControl) {
314                 ((TextAreaControl) control).setMaxLength(null);
315             }
316 
317             if (((LookupInputField)criteriaField).isRanged()) {
318                 // Create field group
319                 FieldGroup rangeFieldGroup = ComponentUtils.copy(rangeFieldGroupPrototype, criteriaField.getId());
320                 rangeFieldGroup.setLabel(((LookupInputField)criteriaField).getLabel());
321 
322                 // Evaluate and set the required property and reset the required message on the 'to' label
323                 expressionEvaluator.evaluatePropertyExpression(view, criteriaField.getContext(), criteriaField,
324                         "required", true);
325                 rangeFieldGroup.setRequired(criteriaField.getRequired());
326                 ((LookupInputField) criteriaField).getFieldLabel().setRequiredMessage(new Message());
327 
328                 // Evaluate and set the render property
329                 expressionEvaluator.evaluatePropertyExpression(view, criteriaField.getContext(), criteriaField,
330                         UifPropertyPaths.RENDER, true);
331                 rangeFieldGroup.setRender(criteriaField.isRender());
332 
333                 List<Component> fieldGroupItems = new ArrayList<Component>();
334 
335                 // Create a new from date field
336                 LookupInputField fromDate = (LookupInputField) ComponentUtils.copy(criteriaField,
337                         KRADConstants.LOOKUP_DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL);
338                 fromDate.getBindingInfo().setBindingName(
339                         KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + fromDate.getPropertyName());
340                 fromDate.setPropertyName(
341                         KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + fromDate.getPropertyName());
342 
343                 // Set the criteria fields labels
344                 fromDate.setLabel("");
345                 fromDate.getFieldLabel().setRenderColon(false);
346                 ((LookupInputField)criteriaField).getFieldLabel().setRender(false);
347 
348                 // Add the cirteria fields to the field group
349                 fieldGroupItems.add(fromDate);
350                 fieldGroupItems.add(rangedToMessage);
351                 fieldGroupItems.add(criteriaField);
352                 rangeFieldGroup.setItems(fieldGroupItems);
353 
354                 // Add fieldgroup to map with index as key
355                 dateRangeFieldMap.put(rangeIndex, rangeFieldGroup);
356             }
357 
358             rangeIndex++;
359         }
360 
361         // Replace original fields with range fieldgroups
362         List<Component> itemList = (List<Component>)criteriaGroup.getItems();
363         for (Integer index : dateRangeFieldMap.keySet()) {
364                 itemList.set(index, dateRangeFieldMap.get(index));
365         }
366 
367         criteriaGroup.setItems(itemList);
368     }
369 
370     /**
371      * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes()
372      */
373     @Override
374     public List<Component> getComponentPrototypes() {
375         List<Component> components = super.getComponentPrototypes();
376 
377         components.add(rangeFieldGroupPrototype);
378         components.add(rangedToMessage);
379 
380         return components;
381     }
382 
383     public void applyConditionalLogicForFieldDisplay() {
384         // TODO: work into view lifecycle
385         //	    LookupViewHelperService lookupViewHelperService = (LookupViewHelperService) getViewHelperService();
386         //		Set<String> readOnlyFields = lookupViewHelperService.getConditionallyReadOnlyPropertyNames();
387         //		Set<String> requiredFields = lookupViewHelperService.getConditionallyRequiredPropertyNames();
388         //		Set<String> hiddenFields = lookupViewHelperService.getConditionallyHiddenPropertyNames();
389         //		if ( (readOnlyFields != null && !readOnlyFields.isEmpty()) ||
390         //			 (requiredFields != null && !requiredFields.isEmpty()) ||
391         //			 (hiddenFields != null && !hiddenFields.isEmpty())
392         //			) {
393         //			for (Field field : getResultsGroup().getItems()) {
394         //				if (InputField.class.isAssignableFrom(field.getClass())) {
395         //					InputField attributeField = (InputField) field;
396         //					if (readOnlyFields != null && readOnlyFields.contains(attributeField.getBindingInfo().getBindingName())) {
397         //						attributeField.setReadOnly(true);
398         //					}
399         //					if (requiredFields != null && requiredFields.contains(attributeField.getBindingInfo().getBindingName())) {
400         //						attributeField.setRequired(Boolean.TRUE);
401         //					}
402         //					if (hiddenFields != null && hiddenFields.contains(attributeField.getBindingInfo().getBindingName())) {
403         //						attributeField.setControl(LookupInquiryUtils.generateCustomLookupControlFromExisting(HiddenControl.class, null));
404         //					}
405         //				}
406         //	        }
407         //		}
408     }
409 
410     /**
411      * Class name for the object the lookup applies to
412      *
413      * <p>
414      * The object class name is used to pick up a dictionary entry which will
415      * feed the attribute field definitions and other configuration. In addition
416      * it is to configure the <code>Lookupable</code> which will carry out the
417      * lookup action
418      * </p>
419      *
420      * @return lookup data object class
421      */
422     @BeanTagAttribute(name="dataObjectClassName")
423     public Class<?> getDataObjectClassName() {
424         return this.dataObjectClassName;
425     }
426 
427     /**
428      * Setter for the object class name
429      *
430      * @param dataObjectClassName
431      */
432     public void setDataObjectClassName(Class<?> dataObjectClassName) {
433         this.dataObjectClassName = dataObjectClassName;
434     }
435 
436     /**
437      * @return the hideReturnLinks
438      */
439     @BeanTagAttribute(name="hideReturnLinks")
440     public boolean isHideReturnLinks() {
441         return this.hideReturnLinks;
442     }
443 
444     /**
445      * @param hideReturnLinks the hideReturnLinks to set
446      */
447     public void setHideReturnLinks(boolean hideReturnLinks) {
448         this.hideReturnLinks = hideReturnLinks;
449     }
450 
451     /**
452      * @return the suppressActions
453      */
454     @BeanTagAttribute(name="isSuppressActions")
455     public boolean isSuppressActions() {
456         return this.suppressActions;
457     }
458 
459     /**
460      * @param suppressActions the suppressActions to set
461      */
462     public void setSuppressActions(boolean suppressActions) {
463         this.suppressActions = suppressActions;
464     }
465 
466     /**
467      * @return the showMaintenanceLinks
468      */
469     @BeanTagAttribute(name="showMaintenanceLinks")
470     public boolean isShowMaintenanceLinks() {
471         return this.showMaintenanceLinks;
472     }
473 
474     /**
475      * @param showMaintenanceLinks the showMaintenanceLinks to set
476      */
477     public void setShowMaintenanceLinks(boolean showMaintenanceLinks) {
478         this.showMaintenanceLinks = showMaintenanceLinks;
479     }
480 
481     /**
482      * Indicates whether multiple values select should be enabled for the lookup
483      *
484      * <p>
485      * When set to true, the select field is enabled for the lookup results group that allows the user
486      * to select one or more rows for returning
487      * </p>
488      *
489      * @return true if multiple values should be enabled, false otherwise
490      */
491     @BeanTagAttribute(name="multipleValueSelect")
492     public boolean isMultipleValuesSelect() {
493         return multipleValuesSelect;
494     }
495 
496     /**
497      * Setter for the multiple values select indicator
498      *
499      * @param multipleValuesSelect
500      */
501     public void setMultipleValuesSelect(boolean multipleValuesSelect) {
502         this.multipleValuesSelect = multipleValuesSelect;
503     }
504 
505     @BeanTagAttribute(name="criteriaGroup",type = BeanTagAttribute.AttributeType.SINGLEBEAN)
506     public Group getCriteriaGroup() {
507         return this.criteriaGroup;
508     }
509 
510     public void setCriteriaGroup(Group criteriaGroup) {
511         this.criteriaGroup = criteriaGroup;
512     }
513 
514     @BeanTagAttribute(name="resultsGroup",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
515     public CollectionGroup getResultsGroup() {
516         return this.resultsGroup;
517     }
518 
519     public void setResultsGroup(CollectionGroup resultsGroup) {
520         this.resultsGroup = resultsGroup;
521     }
522 
523     @BeanTagAttribute(name="criteriaFields",type= BeanTagAttribute.AttributeType.LISTBEAN)
524     public List<Component> getCriteriaFields() {
525         return this.criteriaFields;
526     }
527 
528     public void setCriteriaFields(List<Component> criteriaFields) {
529         this.criteriaFields = criteriaFields;
530     }
531 
532     @BeanTagAttribute(name="resultFields",type= BeanTagAttribute.AttributeType.LISTBEAN)
533     public List<Component> getResultFields() {
534         return this.resultFields;
535     }
536 
537     public void setResultFields(List<Component> resultFields) {
538         this.resultFields = resultFields;
539     }
540 
541     @BeanTagAttribute(name="defaultSortAttributeNames",type= BeanTagAttribute.AttributeType.LISTVALUE)
542     public List<String> getDefaultSortAttributeNames() {
543         return this.defaultSortAttributeNames;
544     }
545 
546     public void setDefaultSortAttributeNames(List<String> defaultSortAttributeNames) {
547         this.defaultSortAttributeNames = defaultSortAttributeNames;
548     }
549 
550     @BeanTagAttribute(name="defaultSortAscending")
551     public boolean isDefaultSortAscending() {
552         return this.defaultSortAscending;
553     }
554 
555     public void setDefaultSortAscending(boolean defaultSortAscending) {
556         this.defaultSortAscending = defaultSortAscending;
557     }
558 
559     /**
560      * Retrieves the maximum number of records that will be listed
561      * as a result of the lookup search
562      *
563      * @return Integer result set limit
564      */
565     @BeanTagAttribute(name="resultSetLimit")
566     public Integer getResultSetLimit() {
567         return resultSetLimit;
568     }
569 
570     /**
571      * Setter for the result list limit
572      *
573      * @param resultSetLimit Integer specifying limit
574      */
575     public void setResultSetLimit(Integer resultSetLimit) {
576         this.resultSetLimit = resultSetLimit;
577     }
578 
579     /**
580      * Indicates whether a result set limit has been specified for the
581      * view
582      *
583      * @return true if this instance has a result set limit
584      */
585     public boolean hasResultSetLimit() {
586         return (resultSetLimit != null);
587     }
588 
589     /**
590      * Retrieves the maximum number of records that will be listed
591      * as a result of the multiple values select lookup search
592      *
593      * @return multiple values select result set limit
594      */
595     @BeanTagAttribute(name="multipleValuesSelectResultSetLimit")
596     public Integer getMultipleValuesSelectResultSetLimit() {
597         return multipleValuesSelectResultSetLimit;
598     }
599 
600     /**
601      * Setter for the multiple values select result set limit
602      *
603      * @param multipleValuesSelectResultSetLimit Integer specifying limit
604      */
605     public void setMultipleValuesSelectResultSetLimit(Integer multipleValuesSelectResultSetLimit) {
606         this.multipleValuesSelectResultSetLimit = multipleValuesSelectResultSetLimit;
607     }
608 
609     /**
610      * Indicates whether a multiple values select result
611      * set limit has been specified for the view
612      *
613      * @return true if this instance has a multiple values select result set limit
614      */
615     public boolean hasMultipleValuesSelectResultSetLimit() {
616         return (multipleValuesSelectResultSetLimit != null);
617     }
618 
619     /**
620      * @param returnTarget the returnTarget to set
621      */
622     public void setReturnTarget(String returnTarget) {
623         this.returnTarget = returnTarget;
624     }
625 
626     /**
627      * @return the returnTarget
628      */
629     @BeanTagAttribute(name="returnTarget")
630     public String getReturnTarget() {
631         return returnTarget;
632     }
633 
634     /**
635      * @return the returnByScript
636      */
637     @BeanTagAttribute(name="returnByScript")
638     public boolean isReturnByScript() {
639         return returnByScript;
640     }
641 
642     /**
643      * Setter for the flag to indicate that lookups will return the value
644      * by script and not a post
645      *
646      * @param returnByScript the returnByScript flag
647      */
648     public void setReturnByScript(boolean returnByScript) {
649         this.returnByScript = returnByScript;
650     }
651 
652     /**
653      * String that maps to the maintenance controller for the maintenance document (if any) associated with the
654      * lookup data object class
655      *
656      * <p>
657      * Mapping will be used to build the maintenance action links (such as edit, copy, and new). If not given, the
658      * default maintenance mapping will be used
659      * </p>
660      *
661      * @return mapping string
662      */
663     @BeanTagAttribute(name="maintenanceUrlMapping")
664     public String getMaintenanceUrlMapping() {
665         return maintenanceUrlMapping;
666     }
667 
668     /**
669      * Setter for the URL mapping string that will be used to build up maintenance action URLs
670      *
671      * @param maintenanceUrlMapping
672      */
673     public void setMaintenanceUrlMapping(String maintenanceUrlMapping) {
674         this.maintenanceUrlMapping = maintenanceUrlMapping;
675     }
676 
677     /**
678      * Indicates that the action buttons like search in the criteria section should be rendered
679      *
680      * @return boolean
681      */
682     public boolean isRenderSearchButtons() {
683         return renderSearchButtons;
684     }
685 
686     /**
687      * Setter for the render search buttons flag
688      *
689      * @param renderSearchButtons
690      */
691     public void setRenderSearchButtons(boolean renderSearchButtons) {
692         this.renderSearchButtons = renderSearchButtons;
693     }
694 
695     /**
696      * Indicates whether the lookup criteria group should be rendered
697      *
698      * <p>
699      * Defaults to true. Can be set as bean property or passed as a request parameter in the lookup url.
700      * </p>
701      *
702      * @return boolean
703      */
704     public boolean isRenderLookupCriteria() {
705         return renderLookupCriteria;
706     }
707 
708     /**
709      * Setter for the lookup criteria group render flag
710      *
711      * @param renderLookupCriteria
712      */
713     public void setRenderLookupCriteria(boolean renderLookupCriteria) {
714         this.renderLookupCriteria = renderLookupCriteria;
715     }
716 
717     /**
718      * Indicates whether the lookup header should be rendered
719      *
720      * <p>
721      * Defaults to true. Can be set as bean property or passed as a request parameter in the lookup url.
722      * </p>
723      *
724      * @return boolean
725      */
726     public boolean isRenderHeader() {
727         return renderHeader;
728     }
729 
730     /**
731      * Setter for the header render flag
732      *
733      * @param renderHeader
734      */
735     public void setRenderHeader(boolean renderHeader) {
736         this.renderHeader = renderHeader;
737     }
738 
739     /**
740      * Indicates that the search must execute on changing of a value in all lookup input fields
741      *
742      * @return boolean
743      */
744     public boolean isTriggerOnChange() {
745         return triggerOnChange;
746     }
747 
748     /**
749      * Setter for the trigger search on change flag
750      *
751      * @param triggerOnChange
752      */
753     public void setTriggerOnChange(boolean triggerOnChange) {
754         this.triggerOnChange = triggerOnChange;
755     }
756 
757     /**
758      * The field group prototype that will be copied and used for range fields
759      *
760      * @return FieldGroup
761      */
762     public FieldGroup getRangeFieldGroupPrototype() {
763         return rangeFieldGroupPrototype;
764     }
765 
766     /**
767      * Setter for the range FieldGroup prototype
768      *
769      * @param rangeFieldGroupPrototype
770      */
771     public void setRangeFieldGroupPrototype(FieldGroup rangeFieldGroupPrototype) {
772         this.rangeFieldGroupPrototype = rangeFieldGroupPrototype;
773     }
774 
775     /**
776      * Indicates whether the 'active' criteria field must be added automatically for Inactivatable BO's
777      *
778      * @return boolean
779      */
780     public boolean isAutoAddActiveCriteria() {
781         return autoAddActiveCriteria;
782     }
783 
784     /**
785      * Setter for the flag that indicates whether the 'active' criteria field must be added automatically for
786      * Inactivatable BO's
787      *
788      * @param autoAddActiveCriteria
789      */
790     public void setAutoAddActiveCriteria(boolean autoAddActiveCriteria) {
791         this.autoAddActiveCriteria = autoAddActiveCriteria;
792     }
793 
794     /**
795      * The Message to render between the two range fields for ranged criteria fields
796      *
797      * @return
798      */
799     public Message getRangedToMessage() {
800         return rangedToMessage;
801     }
802 
803     /**
804      * Setter for the Message rendered between the two range fields for ranged criteria fields
805      *
806      * @param rangedToMessage
807      */
808     public void setRangedToMessage(Message rangedToMessage) {
809         this.rangedToMessage = rangedToMessage;
810     }
811 
812     /**
813      * @see org.kuali.rice.krad.uif.component.ComponentBase#copy()
814      */
815     @Override
816     protected <T> void copyProperties(T component) {
817         super.copyProperties(component);
818 
819         LookupView lookupViewCopy = (LookupView) component;
820 
821         if (this.dataObjectClassName != null) {
822             lookupViewCopy.setDataObjectClassName(this.getDataObjectClassName());
823         }
824 
825         if (this.criteriaGroup != null) {
826             lookupViewCopy.setCriteriaGroup((Group) this.getCriteriaGroup().copy());
827         }
828 
829         if (this.resultsGroup != null) {
830             lookupViewCopy.setResultsGroup((CollectionGroup) this.getResultsGroup().copy());
831         }
832 
833         if (this.criteriaFields != null) {
834             List<Component> criteriaFieldsCopy = Lists.newArrayListWithExpectedSize(criteriaFields.size());
835             for (Component criteriaField : criteriaFields) {
836                 criteriaFieldsCopy.add((Component) criteriaField.copy());
837             }
838             lookupViewCopy.setCriteriaFields(criteriaFieldsCopy);
839         }
840 
841         if (this.resultFields != null) {
842             List<Component> resultFieldsCopy = Lists.newArrayListWithExpectedSize(resultFields.size());
843             for (Component resultField : resultFields) {
844                 resultFieldsCopy.add((Component) resultField.copy());
845             }
846             lookupViewCopy.setResultFields(resultFieldsCopy);
847         }
848 
849         if (this.defaultSortAttributeNames != null) {
850             lookupViewCopy.setDefaultSortAttributeNames(new ArrayList<String>(defaultSortAttributeNames));
851         }
852 
853         lookupViewCopy.setDefaultSortAscending(this.isDefaultSortAscending());
854         lookupViewCopy.setHideReturnLinks(this.hideReturnLinks);
855         lookupViewCopy.setSuppressActions(this.suppressActions);
856         lookupViewCopy.setShowMaintenanceLinks(this.showMaintenanceLinks);
857         lookupViewCopy.setMaintenanceUrlMapping(this.maintenanceUrlMapping);
858         lookupViewCopy.setMultipleValuesSelect(this.multipleValuesSelect);
859         lookupViewCopy.setRenderLookupCriteria(this.renderLookupCriteria);
860         lookupViewCopy.setRenderSearchButtons(this.renderSearchButtons);
861         lookupViewCopy.setRenderHeader(this.renderHeader);
862         lookupViewCopy.setResultSetLimit(this.resultSetLimit);
863         lookupViewCopy.setReturnTarget(this.returnTarget);
864         lookupViewCopy.setTriggerOnChange(this.triggerOnChange);
865         lookupViewCopy.setResultSetLimit(this.resultSetLimit);
866         lookupViewCopy.setMultipleValuesSelectResultSetLimit(this.multipleValuesSelectResultSetLimit);
867         lookupViewCopy.setMaintenanceUrlMapping(this.maintenanceUrlMapping);
868 
869         if (this.rangeFieldGroupPrototype != null) {
870             lookupViewCopy.setRangeFieldGroupPrototype((FieldGroup) this.rangeFieldGroupPrototype.copy());
871         }
872 
873         if (this.rangedToMessage != null) {
874             lookupViewCopy.setRangedToMessage((Message) this.rangedToMessage.copy());
875         }
876 
877         lookupViewCopy.setAutoAddActiveCriteria(this.autoAddActiveCriteria);
878     }
879 
880 }