001/**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.uif.widget;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.commons.lang.StringUtils;
024import org.kuali.rice.krad.bo.DataObjectRelationship;
025import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
026import org.kuali.rice.krad.datadictionary.parse.BeanTag;
027import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
028import org.kuali.rice.krad.datadictionary.parse.BeanTags;
029import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
030import org.kuali.rice.krad.service.ModuleService;
031import org.kuali.rice.krad.uif.UifConstants;
032import org.kuali.rice.krad.uif.UifParameters;
033import org.kuali.rice.krad.uif.component.BindingInfo;
034import org.kuali.rice.krad.uif.component.Component;
035import org.kuali.rice.krad.uif.component.MethodInvokerConfig;
036import org.kuali.rice.krad.uif.container.CollectionGroup;
037import org.kuali.rice.krad.uif.element.Action;
038import org.kuali.rice.krad.uif.field.InputField;
039import org.kuali.rice.krad.uif.lifecycle.LifecycleEventListener;
040import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
041import org.kuali.rice.krad.uif.util.LifecycleElement;
042import org.kuali.rice.krad.uif.util.ViewModelUtils;
043import org.kuali.rice.krad.uif.view.View;
044import org.kuali.rice.krad.util.KRADConstants;
045import org.kuali.rice.krad.util.KRADUtils;
046
047/**
048 * Widget for navigating to a lookup from a field (called a quickfinder).
049 *
050 * @author Kuali Rice Team (rice.collab@kuali.org)
051 */
052@BeanTags({@BeanTag(name = "quickFinder", parent = "Uif-QuickFinder"),
053        @BeanTag(name = "quickFinderByScript", parent = "Uif-QuickFinderByScript"),
054        @BeanTag(name = "collectionQuickFinder", parent = "Uif-CollectionQuickFinder")})
055public class QuickFinder extends WidgetBase implements LifecycleEventListener {
056    private static final long serialVersionUID = 3302390972815386785L;
057
058    // lookup configuration
059    private String baseLookupUrl;
060    private String dataObjectClassName;
061    private String viewName;
062
063    private boolean returnByScript;
064    private String readOnlyLookupFields;
065    private String referencesToRefresh;
066    private String lookupCollectionName;
067    private String lookupCollectionId;
068
069    private Map<String, String> fieldConversions;
070    private Map<String, String> lookupParameters;
071    private Map<String, String> additionalLookupParameters;
072
073    private Action quickfinderAction;
074
075    private String lookupDialogId;
076    private boolean openInDialog;
077
078    // lookup view options
079    private Boolean renderReturnLink;
080    private Boolean renderResultActions;
081    private Boolean autoSearch;
082    private Boolean renderLookupCriteria;
083    private Boolean renderCriteriaActions;
084    private Boolean hideCriteriaOnSearch;
085    private Boolean renderMaintenanceLinks;
086    private Boolean multipleValuesSelect;
087
088    private String callbackMethodToCall;
089    private MethodInvokerConfig callbackMethod;
090    private Map<String, String> callbackContext;
091
092    public QuickFinder() {
093        super();
094
095        fieldConversions = new HashMap<String, String>();
096        lookupParameters = new HashMap<String, String>();
097        lookupDialogId = "";
098    }
099
100    /**
101     * The following initialization is performed:
102     *
103     * <ul>
104     * <li>Registers an event on the quickfinder action</li>
105     * </ul>
106     *
107     * {@inheritDoc}
108     */
109    @Override
110    public void performInitialization(Object model) {
111        super.performInitialization(model);
112
113        ViewLifecycle viewLifecycle = ViewLifecycle.getActiveLifecycle();
114        viewLifecycle.registerLifecycleCompleteListener(quickfinderAction, this);
115    }
116
117    /**
118     * Inherits readOnly from parent if not explicitly populated.
119     * 
120     * {@inheritDoc}
121     */
122    @Override
123    public void afterEvaluateExpression() {
124        super.afterEvaluateExpression();
125        
126        if (getReadOnly() == null) {
127            Component parent = ViewLifecycle.getPhase().getParent();
128            setReadOnly(parent == null ? null : parent.getReadOnly());
129        }
130    }
131
132    /**
133     * The following finalization is performed:
134     *
135     * <ul>
136     * <li>Sets up the quickfinder based on whether the parent is an input field or collection group</li>
137     * <li>Adds action parameters to the quickfinder action based on the quickfinder configuration</li>
138     * <li>Adds callback parameters to post data if present</li>
139     * </ul>
140     *
141     * {@inheritDoc}
142     */
143    @Override
144    public void performFinalize(Object model, LifecycleElement parent) {
145        super.performFinalize(model, parent);
146
147        if (parent instanceof Component && Boolean.TRUE.equals(((Component) parent).getReadOnly())) {
148            setRender(false);
149        }
150
151        if (!isRender()) {
152            return;
153        }
154        
155        View view = ViewLifecycle.getActiveLifecycle().getView();
156
157        if (parent instanceof InputField) {
158            setupForInputField(view, model, (InputField) parent);
159
160            // add field conversions as accessible binding paths
161            if (isRender()) {
162                for (String toField : fieldConversions.values()) {
163                    ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(toField);
164                }
165            }
166        } else if (parent instanceof CollectionGroup) {
167            setupForCollectionGroup(view, model, (CollectionGroup) parent);
168        }
169
170        setupQuickfinderAction(view, model, parent);
171
172        addCallbackParametersIfPresent();
173    }
174
175    /**
176     * If quickfinder not manually configured attempts to find a relationship to build the quickfinder on, then also
177     * adjusts the path for any configured field conversions, lookup parameters, and refresh refreshes.
178     *
179     * @param view view instance the quickfinder is associated with
180     * @param model object containing the view data
181     * @param inputField input field instance the quickfinder should apply to
182     */
183    protected void setupForInputField(View view, Object model, InputField inputField) {
184        // if quickfinder class name not specified, attempt to find a relationship to build the quickfinder from
185        if (StringUtils.isBlank(dataObjectClassName)) {
186            DataObjectRelationship relationship = getRelationshipForField(view, model, inputField);
187
188            // if no relationship found cannot have a quickfinder
189            if (relationship == null) {
190                setRender(false);
191
192                return;
193            }
194
195            dataObjectClassName = relationship.getRelatedClass().getName();
196
197            if ((fieldConversions == null) || fieldConversions.isEmpty()) {
198                generateFieldConversions(relationship);
199            }
200
201            if ((lookupParameters == null) || lookupParameters.isEmpty()) {
202                generateLookupParameters(relationship);
203            }
204        }
205
206        // adjust paths based on associated attribute field
207        updateFieldConversions(inputField.getBindingInfo());
208        updateLookupParameters(inputField.getBindingInfo());
209        updateReferencesToRefresh(inputField.getBindingInfo());
210
211        // add the quickfinders action as an input field addon
212        inputField.addPostInputAddon(quickfinderAction);
213    }
214
215    /**
216     * Retrieves any {@link org.kuali.rice.krad.bo.DataObjectRelationship} that is associated with the given
217     * field and has a configured lookup view.
218     *
219     * @param view view instance the quickfinder is associated with
220     * @param model object containing the view data
221     * @param field input field instance the quickfinder should apply to
222     * @return data object relationship for the field, or null if one could not be found
223     */
224    protected DataObjectRelationship getRelationshipForField(View view, Object model, InputField field) {
225        String propertyName = field.getBindingInfo().getBindingName();
226
227        // get object instance and class for parent
228        Object parentObject = ViewModelUtils.getParentObjectForMetadata(view, model, field);
229        Class<?> parentObjectClass = null;
230        if (parentObject != null) {
231            parentObjectClass = parentObject.getClass();
232        }
233
234        // get relationship from metadata service
235        if (parentObjectClass != null) {
236            return KRADServiceLocatorWeb.getLegacyDataAdapter().getDataObjectRelationship(parentObject,
237                    parentObjectClass, propertyName, "", true, true, false);
238        }
239
240        return null;
241    }
242
243    /**
244     * Generates the lookup field conversions based on the references from the given relationship.
245     *
246     * @param relationship relationship field conversions will be generated from
247     */
248    protected void generateFieldConversions(DataObjectRelationship relationship) {
249        fieldConversions = new HashMap<String, String>();
250
251        for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
252            String fromField = entry.getValue();
253            String toField = entry.getKey();
254
255            fieldConversions.put(fromField, toField);
256        }
257    }
258
259    /**
260     * Generates the lookup parameters based on the references from the given relationship.
261     *
262     * @param relationship relationship lookup parameters will be generated from
263     */
264    protected void generateLookupParameters(DataObjectRelationship relationship) {
265        lookupParameters = new HashMap<String, String>();
266
267        for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
268            String fromField = entry.getKey();
269            String toField = entry.getValue();
270
271            if (relationship.getUserVisibleIdentifierKey() == null || relationship.getUserVisibleIdentifierKey().equals(
272                    fromField)) {
273                lookupParameters.put(fromField, toField);
274            }
275        }
276    }
277
278    /**
279     * Adjusts the path on the field conversion to property to match the binding path prefix of the
280     * given {@link org.kuali.rice.krad.uif.component.BindingInfo}.
281     *
282     * @param bindingInfo binding info instance to copy binding path prefix from
283     */
284    protected void updateFieldConversions(BindingInfo bindingInfo) {
285        Map<String, String> adjustedFieldConversions = new HashMap<String, String>();
286        for (String fromField : fieldConversions.keySet()) {
287            String toField = fieldConversions.get(fromField);
288
289            if (!StringUtils.startsWith(toField, bindingInfo.getBindingPathPrefix())) {
290                String adjustedToFieldPath = bindingInfo.getPropertyAdjustedBindingPath(toField);
291                adjustedFieldConversions.put(fromField, adjustedToFieldPath);
292            }  else {
293                adjustedFieldConversions.put(fromField, toField);
294            }
295        }
296
297        this.fieldConversions = adjustedFieldConversions;
298    }
299
300    /**
301     * Adjusts the path on the lookup parameter from property to match the binding path prefix of the
302     * given {@link org.kuali.rice.krad.uif.component.BindingInfo}.
303     *
304     * @param bindingInfo binding info instance to copy binding path prefix from
305     */
306    protected void updateLookupParameters(BindingInfo bindingInfo) {
307        Map<String, String> adjustedLookupParameters = new HashMap<String, String>();
308        for (String fromField : lookupParameters.keySet()) {
309            String toField = lookupParameters.get(fromField);
310            String adjustedFromFieldPath = bindingInfo.getPropertyAdjustedBindingPath(fromField);
311
312            adjustedLookupParameters.put(adjustedFromFieldPath, toField);
313        }
314
315        this.lookupParameters = adjustedLookupParameters;
316    }
317
318    /**
319     * Adjust the path on the referencesToRefresh parameter to match the binding path prefix of the
320     * given {@link org.kuali.rice.krad.uif.component.BindingInfo}.
321     *
322     * @param bindingInfo binding info instance to copy binding path prefix from
323     */
324    protected void updateReferencesToRefresh(BindingInfo bindingInfo) {
325        List<String> adjustedReferencesToRefresh = new ArrayList<String>();
326
327        if (referencesToRefresh == null) {
328            referencesToRefresh = new String();
329        }
330
331        for (String reference : StringUtils.split(referencesToRefresh, KRADConstants.REFERENCES_TO_REFRESH_SEPARATOR)) {
332            adjustedReferencesToRefresh.add(bindingInfo.getPropertyAdjustedBindingPath(reference));
333        }
334
335        this.referencesToRefresh = StringUtils.join(adjustedReferencesToRefresh,
336                KRADConstants.REFERENCES_TO_REFRESH_SEPARATOR);
337    }
338
339    /**
340     * Configures the quickfinder for the given collection group instance by setting the data object class,
341     * field conversions, and lookup collection name (if necessary).
342     *
343     * @param view view instance the quickfinder is associated with
344     * @param model object containing the view data
345     * @param collectionGroup collection group instance to build quickfinder for
346     */
347    protected void setupForCollectionGroup(View view, Object model, CollectionGroup collectionGroup) {
348        // check to see if data object class is configured for lookup, if so we will assume it should be enabled
349        // if not and the class configured for the collection group is lookupable, use that
350        if (StringUtils.isBlank(getDataObjectClassName())) {
351            Class<?> collectionObjectClass = collectionGroup.getCollectionObjectClass();
352
353            boolean isCollectionClassLookupable = KRADServiceLocatorWeb.getViewDictionaryService().isLookupable(
354                    collectionObjectClass);
355            if (isCollectionClassLookupable) {
356                setDataObjectClassName(collectionObjectClass.getName());
357
358                // use PK fields for collection class as default field conversions
359                if ((fieldConversions == null) || fieldConversions.isEmpty()) {
360                    List<String> collectionObjectPKFields =
361                            KRADServiceLocatorWeb.getLegacyDataAdapter().listPrimaryKeyFieldNames(
362                                    collectionObjectClass);
363
364                    fieldConversions = new HashMap<String, String>();
365                    for (String pkField : collectionObjectPKFields) {
366                        fieldConversions.put(pkField, pkField);
367                    }
368                }
369            } else {
370                // no available data object class to lookup so disable quickfinder
371                setRender(false);
372            }
373        }
374
375        // set the lookup return collection name to this collection path
376        if (isRender() && StringUtils.isBlank(getLookupCollectionName())) {
377            setLookupCollectionName(collectionGroup.getBindingInfo().getBindingPath());
378        }
379
380        if (isRender() && StringUtils.isBlank(getLookupCollectionId())) {
381            setLookupCollectionId(collectionGroup.getId());
382        }
383    }
384
385    /**
386     * Adjusts the id for the quickfinder action, and then adds action parameters for passing along the
387     * quickfinder configuration to the lookup view.
388     *
389     * @param view view instance the quickfinder is associated with
390     * @param model object containing the view data
391     * @param parent component instance the quickfinder is associated with
392     */
393    protected void setupQuickfinderAction(View view, Object model, LifecycleElement parent) {
394        quickfinderAction.setId(getId() + UifConstants.IdSuffixes.ACTION);
395
396        if (openInDialog) {
397            String lightboxScript = UifConstants.JsFunctions.SHOW_LOOKUP_DIALOG + "(\"" + quickfinderAction.getId()
398                    + "\"," + returnByScript + ",\"" + lookupDialogId + "\");";
399
400            quickfinderAction.setActionScript(lightboxScript);
401        }
402
403        quickfinderAction.addActionParameter(UifParameters.BASE_LOOKUP_URL, baseLookupUrl);
404
405        Class dataObjectClass = getDataObjectClass(dataObjectClassName);
406        ModuleService responsibleModuleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(dataObjectClass);
407        if (responsibleModuleService != null && responsibleModuleService.isExternalizable(dataObjectClass)) {
408            if (ExternalizableBusinessObject.class.isAssignableFrom(dataObjectClass)) {
409                Class implementationClass = responsibleModuleService.getExternalizableBusinessObjectImplementation(dataObjectClass.asSubclass(
410                        ExternalizableBusinessObject.class));
411                if (implementationClass != null) {
412                    dataObjectClassName = implementationClass.getName();
413                }
414            }
415        }
416
417        quickfinderAction.addActionParameter(UifParameters.DATA_OBJECT_CLASS_NAME, dataObjectClassName);
418
419        if (!fieldConversions.isEmpty()) {
420            quickfinderAction.addActionParameter(UifParameters.CONVERSION_FIELDS, KRADUtils.buildMapParameterString(
421                    fieldConversions));
422        }
423
424        if (!lookupParameters.isEmpty()) {
425            quickfinderAction.addActionParameter(UifParameters.LOOKUP_PARAMETERS, KRADUtils.buildMapParameterString(
426                    lookupParameters));
427        }
428
429        addActionParameterIfNotNull(UifParameters.VIEW_NAME, viewName);
430        addActionParameterIfNotNull(UifParameters.READ_ONLY_FIELDS, readOnlyLookupFields);
431        addActionParameterIfNotNull(UifParameters.RENDER_RETURN_LINK, renderReturnLink);
432        addActionParameterIfNotNull(UifParameters.RENDER_RESULT_ACTIONS, renderResultActions);
433        addActionParameterIfNotNull(UifParameters.REFERENCES_TO_REFRESH, referencesToRefresh);
434        addActionParameterIfNotNull(UifParameters.AUTO_SEARCH, autoSearch);
435        addActionParameterIfNotNull(UifParameters.RENDER_LOOKUP_CRITERIA, renderLookupCriteria);
436        addActionParameterIfNotNull(UifParameters.RENDER_CRITERIA_ACTIONS, renderCriteriaActions);
437        addActionParameterIfNotNull(UifParameters.HIDE_CRITERIA_ON_SEARCH, hideCriteriaOnSearch);
438        addActionParameterIfNotNull(UifParameters.RENDER_MAINTENANCE_LINKS, renderMaintenanceLinks);
439        addActionParameterIfNotNull(UifParameters.MULTIPLE_VALUES_SELECT, multipleValuesSelect);
440        addActionParameterIfNotNull(UifParameters.LOOKUP_COLLECTION_NAME, lookupCollectionName);
441        addActionParameterIfNotNull(UifParameters.LOOKUP_COLLECTION_ID, lookupCollectionId);
442        addActionParameterIfNotNull(UifParameters.QUICKFINDER_ID, getId());
443
444        //insert additional lookup parameters.
445        if (additionalLookupParameters != null) {
446            //copy additional parameters to actionParameters
447            Map<String, String> actionParameters = quickfinderAction.getActionParameters();
448            actionParameters.putAll(additionalLookupParameters);
449            quickfinderAction.setActionParameters(actionParameters);
450        }
451    }
452
453    private Class<?> getDataObjectClass(String className) {
454        Class<?> dataObjectClass;
455
456        try {
457            dataObjectClass = Class.forName(className);
458        } catch (ClassNotFoundException e) {
459            throw new RuntimeException("Unable to get class for name: " + className, e);
460        }
461
462        return dataObjectClass;
463    }
464
465    /**
466     * Utility method to add an action parameter to the quickfinder action if the given parameter value
467     * is non blank.
468     *
469     * @param parameterName name of the parameter to add
470     * @param parameterValue value for the parameter to add
471     */
472    protected void addActionParameterIfNotNull(String parameterName, Object parameterValue) {
473        if ((parameterValue != null) && StringUtils.isNotBlank(parameterValue.toString())) {
474            quickfinderAction.addActionParameter(parameterName, parameterValue.toString());
475        }
476    }
477
478    /**
479     * Adds post context data for the quickfinder so when the lookup return occurs the focus and jump point
480     * of the quickfinder action can be retrieved.
481     *
482     * {@inheritDoc}
483     */
484    @Override
485    public void processEvent(ViewLifecycle.LifecycleEvent lifecycleEvent, View view, Object model,
486            LifecycleElement eventComponent) {
487        Action finalQuickfinderAction = (Action) eventComponent;
488
489        // add post metadata for focus point when the associated lookup returns
490        ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
491                UifConstants.PostMetadata.QUICKFINDER_FOCUS_ID, finalQuickfinderAction.getFocusOnIdAfterSubmit());
492        ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
493                UifConstants.PostMetadata.QUICKFINDER_JUMP_TO_ID, finalQuickfinderAction.getJumpToIdAfterSubmit());
494    }
495
496    /**
497     * Adds callback method and its parameters to post data so that when a refresh occurs it knows
498     * which view is returned from and possibly which collection line the quickfinder was on.
499     */
500    protected void addCallbackParametersIfPresent() {
501        if (StringUtils.isNotBlank(callbackMethodToCall)) {
502            ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
503                    UifConstants.PostMetadata.QUICKFINDER_CALLBACK_METHOD_TO_CALL, callbackMethodToCall);
504        }
505
506        if (callbackMethod != null) {
507            ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
508                    UifConstants.PostMetadata.QUICKFINDER_CALLBACK_METHOD, callbackMethod);
509        }
510
511        if (callbackContext != null && !callbackContext.isEmpty()) {
512            ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
513                    UifConstants.PostMetadata.QUICKFINDER_CALLBACK_CONTEXT, callbackContext);
514        }
515    }
516
517    /**
518     * Returns the URL for the lookup for which parameters will be added.
519     *
520     * <p>The base URL includes the domain, context, and controller mapping for the lookup invocation. Parameters are
521     * then added based on configuration to complete the URL. This is generally defaulted to the application URL and
522     * internal KRAD servlet mapping, but can be changed to invoke another application such as the Rice standalone
523     * server</p>
524     *
525     * @return lookup base URL
526     */
527    @BeanTagAttribute
528    public String getBaseLookupUrl() {
529        return this.baseLookupUrl;
530    }
531
532    /**
533     * @see QuickFinder#getBaseLookupUrl()
534     */
535    public void setBaseLookupUrl(String baseLookupUrl) {
536        this.baseLookupUrl = baseLookupUrl;
537    }
538
539    /**
540     * Full class name the lookup should be provided for.
541     *
542     * <p>This is passed on to the lookup request for the data object the lookup should be rendered for. This is then
543     * used by the lookup framework to select the lookup view (if more than one lookup view exists for the same
544     * data object class name, the {@link #getViewName()} property should be specified to select the view to
545     * render).</p>
546     *
547     * @return lookup class name
548     */
549    @BeanTagAttribute
550    public String getDataObjectClassName() {
551        return this.dataObjectClassName;
552    }
553
554    /**
555     * @see QuickFinder#getDataObjectClassName()
556     */
557    public void setDataObjectClassName(String dataObjectClassName) {
558        this.dataObjectClassName = dataObjectClassName;
559    }
560
561    /**
562     * When multiple target lookup views exists for the same data object class, the view name can be set to
563     * determine which one to use.
564     *
565     * <p>When creating multiple lookup views for the same data object class, the view name can be specified for the
566     * different versions (for example 'simple' and 'advanced'). When multiple lookup views exist the view name must
567     * be sent with the data object class for the request. Note the view id can be alternatively used to uniquely
568     * identify the lookup view</p>
569     *
570     * @return String name of lookup view
571     */
572    @BeanTagAttribute
573    public String getViewName() {
574        return this.viewName;
575    }
576
577    /**
578     * @see QuickFinder#getViewName()
579     */
580    public void setViewName(String viewName) {
581        this.viewName = viewName;
582    }
583
584    /**
585     * Indicates whether the lookup return should occur through script, or by refresing the page (making server
586     * request).
587     *
588     * <p>For quickfinders that do not need any additional server side action, return through script can be
589     * much faster and prevents a page refresh.</p>
590     *
591     * @return boolean true if the return should occur through script, false if not (default)
592     */
593    @BeanTagAttribute
594    public boolean isReturnByScript() {
595        return returnByScript;
596    }
597
598    /**
599     * @see QuickFinder#isReturnByScript()
600     */
601    public void setReturnByScript(boolean returnByScript) {
602        this.returnByScript = returnByScript;
603    }
604
605    /**
606     * Comma delimited String of property names on the lookup view that should be read only.
607     *
608     * <p>When requesting a lookup view, property names for fields that are rendered as search criteria can be marked
609     * as read-only. This is usually done when a lookup parameter for that property is sent in and the user should
610     * not be allowed to change the value</p>
611     *
612     * @return property names (delimited by a comma) whose criteria fields should be read-only on the
613     *         lookup view
614     */
615    @BeanTagAttribute
616    public String getReadOnlyLookupFields() {
617        return this.readOnlyLookupFields;
618    }
619
620    /**
621     * @see QuickFinder#setReadOnlyLookupFields(java.lang.String)
622     */
623    public void setReadOnlyLookupFields(String readOnlyLookupFields) {
624        this.readOnlyLookupFields = readOnlyLookupFields;
625    }
626
627    /**
628     * List of property names on the model that should be refreshed when the lookup returns.
629     *
630     * <p>Note this is only relevant when the return by script option is not enabled (meaning the server will be
631     * invoked
632     * on the lookup return call)</p>
633     *
634     * <p>When a lookup return call is made (to return a result value) the controller refresh method will be invoked.
635     * If
636     * refresh properties are configured, a call to refresh those references from the database will be made. This is
637     * useful if the lookup returns a foreign key field and the related record is needed.</p>
638     *
639     * @return list of property names to refresh
640     */
641    @BeanTagAttribute
642    public String getReferencesToRefresh() {
643        return this.referencesToRefresh;
644    }
645
646    /**
647     * @see QuickFinder#getReferencesToRefresh()
648     */
649    public void setReferencesToRefresh(String referencesToRefresh) {
650        this.referencesToRefresh = referencesToRefresh;
651    }
652
653    /**
654     * Map that determines what properties from a result lookup row (if selected) will be returned to properties on
655     * the calling view.
656     *
657     * <p>The purpose of using the lookup is to search for a particular value and return that value to the form being
658     * completed. In order for the lookup framework to return the field back to us, we must specify the name of the
659     * field on the data object class whose value we need, and the name of the field on the calling view. Furthermore,
660     * we can choose to have the lookup return additional fields that populate other form fields or informational
661     * properties (see ‘Field Queries and Informational Properties’). These pairs of fields are known as
662     * ‘field conversions’.</p>
663     *
664     * <p>The fieldConversions property is a Map. Each entry represents a field that will be returned back from the
665     * lookup, with the entry key being the field name on the data object class, and the entry value being the field
666     * name on the calling view. It is helpful to think of this as a from-to mapping. Pulling from the data object
667     * field (map key) to the calling view field (map value).</p>
668     *
669     * @return mapping of lookup data object property names to view property names
670     */
671    @BeanTagAttribute
672    public Map<String, String> getFieldConversions() {
673        return this.fieldConversions;
674    }
675
676    /**
677     * @see QuickFinder#getFieldConversions()
678     */
679    public void setFieldConversions(Map<String, String> fieldConversions) {
680        this.fieldConversions = fieldConversions;
681    }
682
683    /**
684     * Map that determines what properties from a calling view will be sent to properties on that are rendered
685     * for the lookup view's search fields (they can be hidden).
686     *
687     * <p> When invoking a lookup view, we can pre-populate search fields on the lookup view with data from the view
688     * that called the lookup. The user can then perform the search with these values, or (if edited is allowed or
689     * the fields are not hidden) change the passed in values. When the lookup is invoked, the values for the
690     * properties configured within the lookup parameters Map will be pulled and passed along as values for the
691     * lookup view properties</p>
692     *
693     * @return mapping of calling view properties to lookup view search fields
694     */
695    @BeanTagAttribute
696    public Map<String, String> getLookupParameters() {
697        return this.lookupParameters;
698    }
699
700    /**
701     * @see QuickFinder#getLookupParameters()
702     */
703    public void setLookupParameters(Map<String, String> lookupParameters) {
704        this.lookupParameters = lookupParameters;
705    }
706
707    /**
708     * Indicates whether the return links for lookup results should be rendered.
709     *
710     * <p>A lookup view can be invoked to allow the user to select a value (or set of values) to return back to the
711     * calling view. For single value lookups this is done with a return link that is rendered for each row. This
712     * return link can be disabled by setting this property to false</p>
713     *
714     * @return true if the return link should not be shown, false if it should be
715     */
716    @BeanTagAttribute
717    public Boolean getRenderReturnLink() {
718        return this.renderReturnLink;
719    }
720
721    /**
722     * @see QuickFinder#getRenderReturnLink()
723     */
724    public void setRenderReturnLink(Boolean renderReturnLink) {
725        this.renderReturnLink = renderReturnLink;
726    }
727
728    /**
729     * Indicates whether the maintenance actions (or others) are rendered on the invoked lookup view.
730     *
731     * <p>By default a lookup view will add an actions column for the result table that display maintenance links (in
732     * addition to a new link at the top of the page) if a maintenance action is available. Custom links can also be
733     * added to the action column as necessary. This flag can be set to true to suppress the rendering of the actions
734     * for the lookup call.</p>
735     *
736     * @return true if actions should be rendered, false if not
737     */
738    @BeanTagAttribute
739    public Boolean getRenderResultActions() {
740        return renderResultActions;
741    }
742
743    /**
744     * @see QuickFinder#getRenderResultActions()
745     */
746    public void setRenderResultActions(Boolean renderResultActions) {
747        this.renderResultActions = renderResultActions;
748    }
749
750    /**
751     * Indicates whether the search should be executed when first rendering the lookup view.
752     *
753     * <p>By default the lookup view is rendered, the user enters search values and executes the results. This flag can
754     * be set to true to indicate the search should be performed before showing the screen to the user. This is
755     * generally used when search criteria is being passed in as well</p>
756     *
757     * @return true if the search should be performed initially, false if not
758     */
759    @BeanTagAttribute
760    public Boolean getAutoSearch() {
761        return this.autoSearch;
762    }
763
764    /**
765     * @see org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute#name()
766     */
767    public void setAutoSearch(Boolean autoSearch) {
768        this.autoSearch = autoSearch;
769    }
770
771    /**
772     * Indicates whether the lookup criteria (search group) should be enabled on the invoked lookup view.
773     *
774     * <p> Setting the this to false will not display the lookup criteria but only the results. Therefore this is only
775     * useful when setting {@link #getAutoSearch()} to true and passing in criteria</p>
776     *
777     * @return true if lookup criteria should be displayed, false if not
778     */
779    @BeanTagAttribute
780    public Boolean getRenderLookupCriteria() {
781        return this.renderLookupCriteria;
782    }
783
784    /**
785     * @see QuickFinder#getRenderLookupCriteria()
786     */
787    public void setRenderLookupCriteria(Boolean renderLookupCriteria) {
788        this.renderLookupCriteria = renderLookupCriteria;
789    }
790
791    /**
792     * Indicates whether the criteria actions (footer) should be rendered on the invoked lookup view.
793     *
794     * @return boolean true if actions should be rendered (default), false if not
795     */
796    @BeanTagAttribute
797    public Boolean getRenderCriteriaActions() {
798        return this.renderCriteriaActions;
799    }
800
801    /**
802     * @see QuickFinder#getRenderCriteriaActions()
803     */
804    public void setRenderCriteriaActions(Boolean renderCriteriaActions) {
805        this.renderCriteriaActions = renderCriteriaActions;
806    }
807
808    /**
809     * Indicates whether the lookup criteria should be hidden when a search is executed.
810     *
811     * @return boolean true if criteria should be hidden, false if not
812     */
813    @BeanTagAttribute
814    public Boolean getHideCriteriaOnSearch() {
815        return hideCriteriaOnSearch;
816    }
817
818    /**
819     * @see QuickFinder#getHideCriteriaOnSearch()
820     */
821    public void setHideCriteriaOnSearch(Boolean hideCriteriaOnSearch) {
822        this.hideCriteriaOnSearch = hideCriteriaOnSearch;
823    }
824
825    /**
826     * Indicates whether the maintenance action links should be rendered for the invoked lookup view.
827     *
828     * <p>If a maintenance view exists for the data object associated with the lookup view, the framework will add
829     * links to initiate a new maintenance document. This flag can be used to disable the rendering of these links</p>
830     *
831     * <p> Note this serves similar purpose to {@link #getRenderResultActions()} but the intent is to only remove the
832     * maintenance links in this situation, not the complete actions column</p>
833     *
834     * @return true if maintenance links should be shown on the lookup view, false if not
835     */
836    @BeanTagAttribute
837    public Boolean getRenderMaintenanceLinks() {
838        return this.renderMaintenanceLinks;
839    }
840
841    /**
842     * @see QuickFinder#getRenderMaintenanceLinks()
843     */
844    public void setRenderMaintenanceLinks(Boolean renderMaintenanceLinks) {
845        this.renderMaintenanceLinks = renderMaintenanceLinks;
846    }
847
848    /**
849     * Action component that is used to rendered for the field for invoking the quickfinder action (bringing up the
850     * lookup).
851     *
852     * <p>Through the action configuration the image (or link, button) rendered for the quickfinder can be modified. In
853     * addition to other action component settings</p>
854     *
855     * @return Action instance rendered for quickfinder
856     */
857    @BeanTagAttribute(type = BeanTagAttribute.AttributeType.BYTYPE)
858    public Action getQuickfinderAction() {
859        return this.quickfinderAction;
860    }
861
862    /**
863     * @see QuickFinder#getQuickfinderAction()
864     */
865    public void setQuickfinderAction(Action quickfinderAction) {
866        this.quickfinderAction = quickfinderAction;
867    }
868
869    /**
870     * The id of the DialogGroup to use when the openInDialog property is true.
871     *
872     * <p>The DialogGroup should only contain an iframe for its items.  When not set, a default dialog
873     * will be used.</p>
874     *
875     * @return the id of the dialog to use for this quickfinder
876     */
877    @BeanTagAttribute
878    public String getLookupDialogId() {
879        return lookupDialogId;
880    }
881
882    /**
883     * @see QuickFinder#getLookupDialogId()
884     */
885    public void setLookupDialogId(String lookupDialogId) {
886        this.lookupDialogId = lookupDialogId;
887    }
888
889    /**
890     * True if the quickfinder's lookup should be opened in a dialog; true is the default setting for the
891     * bean.
892     *
893     * @return true if the lookup should be opened in a dialog, false to open in a new window
894     */
895    @BeanTagAttribute
896    public boolean isOpenInDialog() {
897        return openInDialog;
898    }
899
900    /**
901     * @see QuickFinder#isOpenInDialog()
902     */
903    public void setOpenInDialog(boolean openInDialog) {
904        this.openInDialog = openInDialog;
905    }
906
907    /**
908     * Indicates whether the invoked lookup view should allow multiple values to be selected and returned.
909     *
910     * @return true if multi-value lookup should be requested, false for normal lookup
911     */
912    @BeanTagAttribute
913    public Boolean getMultipleValuesSelect() {
914        return multipleValuesSelect;
915    }
916
917    /**
918     * @see QuickFinder#getMultipleValuesSelect()
919     */
920    public void setMultipleValuesSelect(Boolean multipleValuesSelect) {
921        this.multipleValuesSelect = multipleValuesSelect;
922    }
923
924    /**
925     * For the case of multi-value lookup, indicates the collection that should be populated with
926     * the return results.
927     *
928     * <p>Note when the quickfinder is associated with a {@link CollectionGroup}, this property is
929     * set automatically from the collection name associated with the group</p>
930     *
931     * @return collection name (must be full binding path)
932     */
933    @BeanTagAttribute
934    public String getLookupCollectionName() {
935        return lookupCollectionName;
936    }
937
938    /**
939     * @see QuickFinder#getLookupCollectionName()
940     */
941    public void setLookupCollectionName(String lookupCollectionName) {
942        this.lookupCollectionName = lookupCollectionName;
943    }
944
945    /**
946     * For the case of multi-value lookup, indicates the collection id that should be populated with
947     * the return results.
948     *
949     * <p>Note when the quickfinder is associated with a {@link CollectionGroup}, this property is
950     * set automatically from the collection id associated with the group</p>
951     *
952     * @return collection id
953     */
954    @BeanTagAttribute
955    public String getLookupCollectionId() {
956        return lookupCollectionId;
957    }
958
959    /**
960     * @see QuickFinder#getLookupCollectionId()
961     */
962    public void setLookupCollectionId(String lookupCollectionId) {
963        this.lookupCollectionId = lookupCollectionId;
964    }
965
966    /**
967     * The additional parameters that were passed to the quickFinder.
968     *
969     * @return additionalLookupParameters - map of additional lookup parameters
970     */
971    @BeanTagAttribute
972    public Map<String, String> getAdditionalLookupParameters() {
973        return additionalLookupParameters;
974    }
975
976    /**
977     * @see QuickFinder#getAdditionalLookupParameters()
978     */
979    public void setAdditionalLookupParameters(Map<String, String> additionalLookupParameters) {
980        this.additionalLookupParameters = additionalLookupParameters;
981    }
982
983    /**
984     * The name of the callback method to invoke in the view helper service that checks
985     * request parameters to indicate what view is being returned from.
986     *
987     * @return callbackMethodToCall - the name of the callback method
988     */
989    public String getCallbackMethodToCall() {
990        return callbackMethodToCall;
991    }
992
993    /**
994     * @see QuickFinder#getCallbackMethodToCall()
995     */
996    public void setCallbackMethodToCall(String callbackMethodToCall) {
997        this.callbackMethodToCall = callbackMethodToCall;
998    }
999
1000    /**
1001     * The specific method invoker to use to invoke the callback method to call.
1002     *
1003     * @return callbackMethod - the method invoker
1004     */
1005    public MethodInvokerConfig getCallbackMethod() {
1006        return callbackMethod;
1007    }
1008
1009    /**
1010     * @see QuickFinder#getCallbackMethod()
1011     */
1012    public void setCallbackMethod(MethodInvokerConfig callbackMethod) {
1013        this.callbackMethod = callbackMethod;
1014    }
1015
1016    /**
1017     * The context of parameters to be provided to the callback method to call.
1018     *
1019     * @return callbackContext - map of parameters
1020     */
1021    public Map<String, String> getCallbackContext() {
1022        return callbackContext;
1023    }
1024
1025    /**
1026     * @see QuickFinder#getCallbackContext()
1027     */
1028    public void setCallbackContext(Map<String, String> callbackContext) {
1029        this.callbackContext = callbackContext;
1030    }
1031}