001/**
002 * Copyright 2005-2016 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.view;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.krad.uif.UifConstants.ViewType;
020import org.kuali.rice.krad.uif.UifPropertyPaths;
021import org.kuali.rice.krad.uif.container.CollectionGroup;
022import org.kuali.rice.krad.uif.container.Group;
023import org.kuali.rice.krad.uif.component.Component;
024import org.kuali.rice.krad.uif.component.RequestParameter;
025import org.kuali.rice.krad.uif.field.Field;
026import org.kuali.rice.krad.web.form.LookupForm;
027
028import java.util.Arrays;
029import java.util.List;
030
031/**
032 * View type for Maintenance documents
033 *
034 * <p>
035 * Supports doing a search against a data object class or performing a more advanced query. The view
036 * type is primarily made up of two groups, the search (or criteria) group and the results group. Many
037 * options are supported on the view to enable/disable certain features, like what actions are available
038 * on the search results.
039 * </p>
040 *
041 * <p>
042 * Works in conjunction with <code>LookupableImpl</code> which customizes the view and carries out the
043 * business functionality
044 * </p>
045 *
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 */
048public class LookupView extends FormView {
049    private static final long serialVersionUID = 716926008488403616L;
050
051    private Class<?> dataObjectClassName;
052
053    private Group criteriaGroup;
054    private CollectionGroup resultsGroup;
055
056    private Field resultsActionsField;
057    private Field resultsReturnField;
058
059    private List<Component> criteriaFields;
060    private List<Component> resultFields;
061    private List<String> defaultSortAttributeNames;
062
063    protected boolean defaultSortAscending = true;
064
065    @RequestParameter
066    private boolean hideReturnLinks = false;
067    @RequestParameter
068    private boolean suppressActions = false;
069    @RequestParameter
070    private boolean showMaintenanceLinks = false;
071    @RequestParameter
072    private boolean multipleValuesSelect = false;
073
074    @RequestParameter
075    private String returnTarget;
076
077    @RequestParameter
078    private boolean returnByScript;
079
080    private boolean lookupCriteriaEnabled = true;
081    private boolean supplementalActionsEnabled = false;
082    private boolean disableSearchButtons = false;
083
084    private Integer resultSetLimit = null;
085
086    private String maintenanceUrlMapping;
087
088    public LookupView() {
089        super();
090        setViewTypeName(ViewType.LOOKUP);
091        setValidateDirty(false);
092    }
093
094    /**
095     * The following initialization is performed:
096     *
097     * <ul>
098     * <li>Set the abstractTypeClasses map for the lookup object path</li>
099     * </ul>
100     *
101     * @see org.kuali.rice.krad.uif.container.ContainerBase#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
102     */
103    @Override
104    public void performInitialization(View view, Object model) {
105        initializeGroups();
106        if (getItems().isEmpty()) {
107            setItems(Arrays.asList(getCriteriaGroup(), getResultsGroup()));
108        }
109        super.performInitialization(view, model);
110
111        // if this is a multi-value lookup, don't show return column
112        if (multipleValuesSelect) {
113            hideReturnLinks = true;
114        }
115
116        getAbstractTypeClasses().put(UifPropertyPaths.CRITERIA_FIELDS, getDataObjectClassName());
117        if (StringUtils.isNotBlank(getDefaultBindingObjectPath())) {
118            getAbstractTypeClasses().put(getDefaultBindingObjectPath(), getDataObjectClassName());
119        }
120    }
121
122    protected void initializeGroups() {
123        if ((getCriteriaGroup() != null) && (getCriteriaGroup().getItems().isEmpty())) {
124            getCriteriaGroup().setItems(getCriteriaFields());
125        }
126        if (getResultsGroup() != null) {
127            if ((getResultsGroup().getItems().isEmpty()) && (getResultFields() != null)) {
128                getResultsGroup().setItems(getResultFields());
129            }
130            if (getResultsGroup().getCollectionObjectClass() == null) {
131                getResultsGroup().setCollectionObjectClass(getDataObjectClassName());
132            }
133        }
134    }
135
136    /**
137     * @see org.kuali.rice.krad.uif.container.ContainerBase#performApplyModel(org.kuali.rice.krad.uif.view.View,
138     *      java.lang.Object)
139     */
140    @Override
141    public void performApplyModel(View view, Object model, Component parent) {
142        LookupForm lookupForm = (LookupForm) model;
143
144        // TODO: need to check lookupForm.isAtLeastOneRowHasActions() somewhere
145        if (!isSuppressActions() && isShowMaintenanceLinks()) {
146            ((List<Field>) getResultsGroup().getItems()).add(0, getResultsActionsField());
147        }
148
149        if (StringUtils.isNotBlank(lookupForm.getReturnFormKey()) &&
150                StringUtils.isNotBlank(lookupForm.getReturnLocation()) && !isHideReturnLinks()) {
151            ((List<Field>) getResultsGroup().getItems()).add(0, getResultsReturnField());
152        }
153
154        super.performApplyModel(view, model, parent);
155    }
156
157    /**
158     * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes()
159     */
160    @Override
161    public List<Component> getComponentPrototypes() {
162        List<Component> components = super.getComponentPrototypes();
163
164        components.add(criteriaGroup);
165        components.add(resultsGroup);
166        components.add(resultsActionsField);
167        components.add(resultsReturnField);
168        components.addAll(criteriaFields);
169        components.addAll(resultFields);
170
171        return components;
172    }
173
174    public void applyConditionalLogicForFieldDisplay() {
175        // TODO: work into view lifecycle
176//          LookupViewHelperService lookupViewHelperService = (LookupViewHelperService) getViewHelperService();
177//              Set<String> readOnlyFields = lookupViewHelperService.getConditionallyReadOnlyPropertyNames();
178//              Set<String> requiredFields = lookupViewHelperService.getConditionallyRequiredPropertyNames();
179//              Set<String> hiddenFields = lookupViewHelperService.getConditionallyHiddenPropertyNames();
180//              if ( (readOnlyFields != null && !readOnlyFields.isEmpty()) ||
181//                       (requiredFields != null && !requiredFields.isEmpty()) ||
182//                       (hiddenFields != null && !hiddenFields.isEmpty())
183//                      ) {
184//                      for (Field field : getResultsGroup().getItems()) {
185//                              if (InputField.class.isAssignableFrom(field.getClass())) {
186//                                      InputField attributeField = (InputField) field;
187//                                      if (readOnlyFields != null && readOnlyFields.contains(attributeField.getBindingInfo().getBindingName())) {
188//                                              attributeField.setReadOnly(true);
189//                                      }
190//                                      if (requiredFields != null && requiredFields.contains(attributeField.getBindingInfo().getBindingName())) {
191//                                              attributeField.setRequired(Boolean.TRUE);
192//                                      }
193//                                      if (hiddenFields != null && hiddenFields.contains(attributeField.getBindingInfo().getBindingName())) {
194//                                              attributeField.setControl(LookupInquiryUtils.generateCustomLookupControlFromExisting(HiddenControl.class, null));
195//                                      }
196//                              }
197//              }
198//              }
199    }
200
201    /**
202     * Class name for the object the lookup applies to
203     *
204     * <p>
205     * The object class name is used to pick up a dictionary entry which will
206     * feed the attribute field definitions and other configuration. In addition
207     * it is to configure the <code>Lookupable</code> which will carry out the
208     * lookup action
209     * </p>
210     *
211     * @return Class<?> lookup data object class
212     */
213    public Class<?> getDataObjectClassName() {
214        return this.dataObjectClassName;
215    }
216
217    /**
218     * Setter for the object class name
219     *
220     * @param dataObjectClassName
221     */
222    public void setDataObjectClassName(Class<?> dataObjectClassName) {
223        this.dataObjectClassName = dataObjectClassName;
224    }
225
226    /**
227     * @return the hideReturnLinks
228     */
229    public boolean isHideReturnLinks() {
230        return this.hideReturnLinks;
231    }
232
233    /**
234     * @param hideReturnLinks the hideReturnLinks to set
235     */
236    public void setHideReturnLinks(boolean hideReturnLinks) {
237        this.hideReturnLinks = hideReturnLinks;
238    }
239
240    /**
241     * @return the suppressActions
242     */
243    public boolean isSuppressActions() {
244        return this.suppressActions;
245    }
246
247    /**
248     * @param suppressActions the suppressActions to set
249     */
250    public void setSuppressActions(boolean suppressActions) {
251        this.suppressActions = suppressActions;
252    }
253
254    /**
255     * @return the showMaintenanceLinks
256     */
257    public boolean isShowMaintenanceLinks() {
258        return this.showMaintenanceLinks;
259    }
260
261    /**
262     * @param showMaintenanceLinks the showMaintenanceLinks to set
263     */
264    public void setShowMaintenanceLinks(boolean showMaintenanceLinks) {
265        this.showMaintenanceLinks = showMaintenanceLinks;
266    }
267
268    /**
269     * Indicates whether multiple values select should be enabled for the lookup
270     *
271     * <p>
272     * When set to true, the select field is enabled for the lookup results group that allows the user
273     * to select one or more rows for returning
274     * </p>
275     *
276     * @return boolean true if multiple values should be enabled, false otherwise
277     */
278    public boolean isMultipleValuesSelect() {
279        return multipleValuesSelect;
280    }
281
282    /**
283     * Setter for the multiple values select indicator
284     *
285     * @param multipleValuesSelect
286     */
287    public void setMultipleValuesSelect(boolean multipleValuesSelect) {
288        this.multipleValuesSelect = multipleValuesSelect;
289    }
290
291    /**
292     * @return the resultsActionsField
293     */
294    public Field getResultsActionsField() {
295        return this.resultsActionsField;
296    }
297
298    /**
299     * @param resultsActionsField the resultsActionsField to set
300     */
301    public void setResultsActionsField(Field resultsActionsField) {
302        this.resultsActionsField = resultsActionsField;
303    }
304
305    /**
306     * @return the resultsReturnField
307     */
308    public Field getResultsReturnField() {
309        return this.resultsReturnField;
310    }
311
312    /**
313     * @param resultsReturnField the resultsReturnField to set
314     */
315    public void setResultsReturnField(Field resultsReturnField) {
316        this.resultsReturnField = resultsReturnField;
317    }
318
319    public Group getCriteriaGroup() {
320        return this.criteriaGroup;
321    }
322
323    public void setCriteriaGroup(Group criteriaGroup) {
324        this.criteriaGroup = criteriaGroup;
325    }
326
327    public CollectionGroup getResultsGroup() {
328        return this.resultsGroup;
329    }
330
331    public void setResultsGroup(CollectionGroup resultsGroup) {
332        this.resultsGroup = resultsGroup;
333    }
334
335    public List<Component> getCriteriaFields() {
336        return this.criteriaFields;
337    }
338
339    public void setCriteriaFields(List<Component> criteriaFields) {
340        this.criteriaFields = criteriaFields;
341    }
342
343    public List<Component> getResultFields() {
344        return this.resultFields;
345    }
346
347    public void setResultFields(List<Component> resultFields) {
348        this.resultFields = resultFields;
349    }
350
351    public List<String> getDefaultSortAttributeNames() {
352        return this.defaultSortAttributeNames;
353    }
354
355    public void setDefaultSortAttributeNames(List<String> defaultSortAttributeNames) {
356        this.defaultSortAttributeNames = defaultSortAttributeNames;
357    }
358
359    public boolean isDefaultSortAscending() {
360        return this.defaultSortAscending;
361    }
362
363    public void setDefaultSortAscending(boolean defaultSortAscending) {
364        this.defaultSortAscending = defaultSortAscending;
365    }
366
367    /**
368     * Retrieves the maximum number of records that will be listed
369     * as a result of the lookup search
370     *
371     * @return Integer result set limit
372     */
373    public Integer getResultSetLimit() {
374        return resultSetLimit;
375    }
376
377    /**
378     * Setter for the result list limit
379     *
380     * @param resultSetLimit Integer specifying limit
381     */
382    public void setResultSetLimit(Integer resultSetLimit) {
383        this.resultSetLimit = resultSetLimit;
384    }
385
386    /**
387     * Indicates whether a result set limit has been specified for the
388     * view
389     *
390     * @return true if this instance has a result set limit
391     */
392    public boolean hasResultSetLimit() {
393        return (resultSetLimit != null);
394    }
395
396    /**
397     * @param returnTarget the returnTarget to set
398     */
399    public void setReturnTarget(String returnTarget) {
400        this.returnTarget = returnTarget;
401    }
402
403    /**
404     * @return the returnTarget
405     */
406    public String getReturnTarget() {
407        return returnTarget;
408    }
409
410    /**
411     * @return the returnByScript
412     */
413    public boolean isReturnByScript() {
414        return returnByScript;
415    }
416
417    /**
418     * Setter for the flag to indicate that lookups will return the value
419     * by script and not a post
420     *
421     * @param returnByScript the returnByScript flag
422     */
423    public void setReturnByScript(boolean returnByScript) {
424        this.returnByScript = returnByScript;
425    }
426
427    /**
428     * String that maps to the maintenance controller for the maintenance document (if any) associated with the
429     * lookup data object class
430     *
431     * <p>
432     * Mapping will be used to build the maintenance action links (such as edit, copy, and new). If not given, the
433     * default maintenance mapping will be used
434     * </p>
435     *
436     * @return String mapping string
437     */
438    public String getMaintenanceUrlMapping() {
439        return maintenanceUrlMapping;
440    }
441
442    /**
443     * Setter for the URL mapping string that will be used to build up maintenance action URLs
444     *
445     * @param maintenanceUrlMapping
446     */
447    public void setMaintenanceUrlMapping(String maintenanceUrlMapping) {
448        this.maintenanceUrlMapping = maintenanceUrlMapping;
449    }
450}