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 }