001    /**
002     * Copyright 2005-2012 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     */
016    package org.kuali.rice.krad.uif.view;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.uif.UifConstants.ViewType;
020    import org.kuali.rice.krad.uif.UifPropertyPaths;
021    import org.kuali.rice.krad.uif.container.CollectionGroup;
022    import org.kuali.rice.krad.uif.container.Group;
023    import org.kuali.rice.krad.uif.component.Component;
024    import org.kuali.rice.krad.uif.component.RequestParameter;
025    import org.kuali.rice.krad.uif.field.Field;
026    import org.kuali.rice.krad.web.form.LookupForm;
027    
028    import java.util.Arrays;
029    import 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     */
048    public 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    }