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.kns.web.ui;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.util.ClassLoaderUtils;
020import org.kuali.rice.core.api.util.KeyValue;
021import org.kuali.rice.core.web.format.Formatter;
022import org.kuali.rice.kns.datadictionary.CollectionDefinitionI;
023import org.kuali.rice.kns.datadictionary.FieldDefinition;
024import org.kuali.rice.kns.datadictionary.FieldDefinitionI;
025import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
026import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
027import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
028import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
029import org.kuali.rice.kns.lookup.LookupUtils;
030import org.kuali.rice.kns.maintenance.Maintainable;
031import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
032import org.kuali.rice.kns.service.KNSServiceLocator;
033import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
034import org.kuali.rice.kns.util.FieldUtils;
035import org.kuali.rice.kns.util.MaintenanceUtils;
036import org.kuali.rice.kns.util.WebUtils;
037import org.kuali.rice.krad.bo.BusinessObject;
038import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
039import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
040import org.kuali.rice.krad.keyvalues.PersistableBusinessObjectValuesFinder;
041import org.kuali.rice.krad.service.DataDictionaryService;
042import org.kuali.rice.krad.service.KRADServiceLocator;
043import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
044import org.kuali.rice.krad.service.PersistenceStructureService;
045import org.kuali.rice.krad.util.KRADConstants;
046import org.kuali.rice.krad.util.ObjectUtils;
047
048import java.util.ArrayList;
049import java.util.Collection;
050import java.util.List;
051import java.util.Set;
052
053/**
054 * @deprecated KNS Struts deprecated, use KRAD and the Spring MVC framework.
055 */
056@Deprecated
057public class FieldBridge {
058    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(FieldBridge.class);
059    private static DataDictionaryService dataDictionaryService;
060    private static PersistenceStructureService persistenceStructureService;
061    private static BusinessObjectDictionaryService businessObjectDictionaryService;
062    private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
063
064    /**
065     * Sets additional properties for MaintainableField(s)
066     *
067     * @param field The field to populate.
068     * @param definition The DD specification for the field.
069     */
070    public static final void setupField(Field field, FieldDefinitionI definition, Set<String> conditionallyRequiredMaintenanceFields) {
071        if (definition instanceof MaintainableFieldDefinition) {
072            MaintainableFieldDefinition maintainableFieldDefinition = ((MaintainableFieldDefinition) definition);
073            
074            field.setFieldRequired(maintainableFieldDefinition.isRequired());
075            field.setReadOnly(maintainableFieldDefinition.isUnconditionallyReadOnly());
076            if (maintainableFieldDefinition.isLookupReadOnly()) {
077                field.setFieldType(Field.LOOKUP_READONLY);
078            }
079
080            // set onblur and callback functions
081            if (StringUtils.isNotBlank(maintainableFieldDefinition.getWebUILeaveFieldFunction())) {
082                field.setWebOnBlurHandler(maintainableFieldDefinition.getWebUILeaveFieldFunction());
083            }
084
085            if (StringUtils.isNotBlank(maintainableFieldDefinition.getWebUILeaveFieldCallbackFunction())) {
086                field.setWebOnBlurHandlerCallback(maintainableFieldDefinition.getWebUILeaveFieldCallbackFunction());
087            }
088
089            if (maintainableFieldDefinition.getWebUILeaveFieldFunctionParameters()!=null) {
090                field.setWebUILeaveFieldFunctionParameters(maintainableFieldDefinition.getWebUILeaveFieldFunctionParameters());
091            }
092            
093                        if (StringUtils.isNotBlank(maintainableFieldDefinition.getAlternateDisplayAttributeName())) {
094                                field.setAlternateDisplayPropertyName(maintainableFieldDefinition.getAlternateDisplayAttributeName());
095                        }
096
097                        if (StringUtils.isNotBlank(maintainableFieldDefinition.getAdditionalDisplayAttributeName())) {
098                                field.setAdditionalDisplayPropertyName(maintainableFieldDefinition.getAdditionalDisplayAttributeName());
099                        }
100            
101            if (conditionallyRequiredMaintenanceFields != null && conditionallyRequiredMaintenanceFields.contains(field.getPropertyName())) {
102                field.setFieldRequired(true);
103            }
104            
105            if (((MaintainableFieldDefinition) definition).isTriggerOnChange()) {
106                field.setTriggerOnChange(true);
107            }
108        }
109    }
110
111    /**
112         * Uses reflection to populate the rows of the inquiry from the business
113         * object value. Also formats if needed.
114     *
115         * @param field
116         *            The Field to populate.
117         * @param bo
118         *            The BusinessObject from which the Field will be popualated.
119     */
120    public static final void populateFieldFromBusinessObject(Field field, BusinessObject bo) {
121        if (bo == null) {
122            throw new RuntimeException("Inquiry Business object is null.");
123        }
124
125        field.setReadOnly(true); // inquiry fields are always read only
126
127        Formatter formatter = field.getFormatter();
128        String propertyName = field.getPropertyName();
129
130        // get the field type for the property
131                ControlDefinition fieldControl = getDataDictionaryService().getAttributeControlDefinition(bo.getClass(),
132                                propertyName);
133        try {
134            Object prop = ObjectUtils.getPropertyValue(bo, field.getPropertyName());
135
136                        // for select fields, display the associated label (unless we are
137                        // already display an additonal attribute)
138                        String propValue = KRADConstants.EMPTY_STRING;
139                        if (fieldControl != null && fieldControl.isSelect()
140                                        && StringUtils.isBlank(field.getAdditionalDisplayPropertyName())
141                                        && StringUtils.isBlank(field.getAlternateDisplayPropertyName())) {
142                                Class<? extends KeyValuesFinder> keyValuesFinderName = ClassLoaderUtils.getClass(fieldControl.getValuesFinderClass(), KeyValuesFinder.class);
143                KeyValuesFinder finder = keyValuesFinderName.newInstance();
144                if(formatter != null){
145                    prop = ObjectUtils.getFormattedPropertyValue(bo,propertyName,formatter);
146                }
147                propValue = lookupFinderValue(fieldControl, prop, finder);
148            } else {
149                                propValue = ObjectUtils.getFormattedPropertyValue(bo, field.getPropertyName(), formatter);
150                    }
151                        field.setPropertyValue(propValue);
152                        
153                        // set additional or alternate display property values if property
154                        // name is specified
155                        if (StringUtils.isNotBlank(field.getAlternateDisplayPropertyName())) {
156                                String alternatePropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, field
157                                                .getAlternateDisplayPropertyName());
158                                field.setAlternateDisplayPropertyValue(alternatePropertyValue);
159                }
160
161                        if (StringUtils.isNotBlank(field.getAdditionalDisplayPropertyName())) {
162                                String additionalPropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, field
163                                                .getAdditionalDisplayPropertyName());
164                                field.setAdditionalDisplayPropertyValue(additionalPropertyValue);
165            }
166
167                        // for user fields, attempt to pull the principal ID and person's
168                        // name from the source object
169            if ( fieldControl != null && fieldControl.isKualiUser() ) {
170                // this is supplemental, so catch and log any errors 
171                try {
172                        if ( StringUtils.isNotBlank(field.getUniversalIdAttributeName()) ) {
173                                Object principalId = ObjectUtils.getNestedValue(bo, field.getUniversalIdAttributeName());
174                                if ( principalId != null ) {
175                                        field.setUniversalIdValue(principalId.toString());
176                                }
177                        }
178                        if ( StringUtils.isNotBlank(field.getPersonNameAttributeName()) ) {
179                                Object personName = ObjectUtils.getNestedValue(bo, field.getPersonNameAttributeName());
180                                if ( personName != null ) {
181                                        field.setPersonNameValue( personName.toString() );
182                                }
183                        }
184                } catch ( Exception ex ) {
185                        LOG.warn( "Unable to get principal ID or person name property in FieldBridge.", ex );
186                }
187            }
188            if (fieldControl != null && fieldControl.isFile()) {
189                if (Field.FILE.equals(field.getFieldType())) {
190                    Object fileName = ObjectUtils.getNestedValue(bo, KRADConstants.BO_ATTACHMENT_FILE_NAME);
191                    Object fileType = ObjectUtils.getNestedValue(bo, KRADConstants.BO_ATTACHMENT_FILE_CONTENT_TYPE);
192                    field.setImageSrc(WebUtils.getAttachmentImageForUrl((String) fileType));
193                    field.setPropertyValue(fileName);
194                }
195            }
196            FieldUtils.setInquiryURL(field, bo, propertyName);
197                } catch (InstantiationException e) {
198            LOG.error("Unable to get instance of KeyValuesFinder: " + e.getMessage());
199            throw new RuntimeException("Unable to get instance of KeyValuesFinder: " + e.getMessage());
200                } catch (ClassNotFoundException e) {
201                        LOG.error("Unable to get instance of KeyValuesFinder: " + e.getMessage());
202            throw new RuntimeException("Unable to get instance of KeyValuesFinder: " + e.getMessage());
203                } catch (IllegalAccessException e) {
204            LOG.error("Unable to set columns: " + e.getMessage());
205            throw new RuntimeException("Unable to set columns: " + e.getMessage());
206        }
207
208    }
209
210    /**
211     * This method looks up a value in a finder class.
212     * @param fieldControl the type of web control that is associated with this field.
213     * @param prop the property to look up - either a property name as a String, or a referenced object
214     * @param finder finder to look the value up in
215     * @return the value that was returned from the lookup
216     */
217    private static String lookupFinderValue(ControlDefinition fieldControl, Object prop, KeyValuesFinder finder) {
218        String propValue = null;
219
220        // KULRICE-1808 : PersistableBusinessObjectValuesFinder is not working for inquiries that have child objects with ValuesFinder populated select lists
221        if (finder instanceof PersistableBusinessObjectValuesFinder) {
222            ((PersistableBusinessObjectValuesFinder) finder).setBusinessObjectClass(ClassLoaderUtils.getClass(fieldControl.getBusinessObjectClass()));
223            ((PersistableBusinessObjectValuesFinder) finder).setKeyAttributeName(fieldControl.getKeyAttribute());
224            ((PersistableBusinessObjectValuesFinder) finder).setLabelAttributeName(fieldControl.getLabelAttribute());
225            if (fieldControl.getIncludeBlankRow() != null) {
226                ((PersistableBusinessObjectValuesFinder) finder).setIncludeBlankRow(fieldControl.getIncludeBlankRow());
227            }
228            ((PersistableBusinessObjectValuesFinder) finder).setIncludeKeyInDescription(fieldControl.getIncludeKeyInLabel());
229        }
230        List<KeyValue> keyValues = finder.getKeyValues();
231        propValue = getPropertyValueFromList(prop, keyValues);
232        if(propValue==null) {
233                        propValue = lookupInactiveFinderValue(prop, finder);
234                }
235        return propValue;
236    }
237    
238    private static String lookupInactiveFinderValue(Object property, KeyValuesFinder finder){
239        List<KeyValue> keyValues = finder.getKeyValues(false);
240        return getPropertyValueFromList(property, keyValues);
241        
242    }
243    
244    private static String getPropertyValueFromList(Object property, List<KeyValue> keyValues){
245        String propertyValue = null;
246        if (property != null) {
247            for (Object element2 : keyValues) {
248                KeyValue element = (KeyValue) element2;
249                if (element.getKey().toString().equals(property.toString())) {
250                    propertyValue = element.getValue();
251                    break;
252                }
253            }
254        }
255        return propertyValue;
256    }
257    
258    /**
259     * Determines whether field level help is enabled for the field corresponding to the dataObjectClass and attribute name
260     *
261     * If this value is true, then the field level help will be enabled.
262     * If false, then whether a field is enabled is determined by the value returned by {@link #isMaintenanceFieldLevelHelpDisabled(Maintainable, MaintainableFieldDefinition)}
263     * and the system-wide parameter setting.  Note that if a field is read-only, that may cause field-level help to not be rendered.
264     *
265     * @param businessObjectClass the looked up class
266     * @param attributeName the attribute for the field
267     * @return true if field level help is enabled, false if the value of this method should NOT be used to determine whether this method's return value
268     * affects the enablement of field level help
269     */
270    protected static boolean isMaintenanceFieldLevelHelpEnabled(Maintainable m, MaintainableFieldDefinition fieldDefinition) {
271        if ( fieldDefinition != null ) {
272            if ( fieldDefinition.isShowFieldLevelHelp() != null && fieldDefinition.isShowFieldLevelHelp() ) {
273                return true;
274            }
275        }
276        return false;
277    }
278
279    /**
280     * Determines whether field level help is disabled for the field corresponding to the dataObjectClass and attribute name
281     *
282     * If this value is true and {@link #isMaintenanceFieldLevelHelpEnabled(Maintainable, MaintainableFieldDefinition)} returns false,
283     * then the field level help will not be rendered.  If both this and {@link #isMaintenanceFieldLevelHelpEnabled(Maintainable, MaintainableFieldDefinition)} return false,
284     * then the system-wide setting will determine whether field level help is enabled.  Note that if a field is read-only, that may cause
285     * field-level help to not be rendered.
286     *
287     * @param businessObjectClass the looked up class
288     * @param attributeName the attribute for the field
289     * @return true if field level help is disabled, false if the value of this method should NOT be used to determine whether this method's return value
290     * affects the enablement of field level help
291     */
292    protected static boolean isMaintenanceFieldLevelHelpDisabled(Maintainable m, MaintainableFieldDefinition fieldDefinition) {
293        if ( fieldDefinition != null ) {
294            if ( fieldDefinition.isShowFieldLevelHelp() != null && !fieldDefinition.isShowFieldLevelHelp() ) {
295                return true;
296            }
297        }
298        return false;
299    }
300
301    /**
302     * This method creates a Field for display on a Maintenance Document.
303     *
304     * @param id The DD definition for the Field (can be a Collection).
305     * @param sd The DD definition for the Section in which the field will be displayed.
306     * @param o The BusinessObject will be populated from this BO.
307     * @param m
308     * @param s The Section in which the Field will be displayed.
309     * @param autoFillDefaultValues Should default values be filled in?
310     * @param autoFillBlankRequiredValues Should values be filled in for fields that are required but which were left blank when submitting the form from the UI?
311     * @param displayedFieldNames What fields are being displayed on the form in the UI?
312     *
313     * @return
314     *
315     * @throws InstantiationException
316     * @throws IllegalAccessException
317     */
318    public static final Field toField(MaintainableItemDefinition id, MaintainableSectionDefinition sd, BusinessObject o, Maintainable m, Section s, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields) throws InstantiationException, IllegalAccessException {
319        Field field = new Field();
320
321        // if FieldDefiniton, simply add a Field UI object
322        if (id instanceof MaintainableFieldDefinition) {
323            MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) id;
324            field = FieldUtils.getPropertyField(o.getClass(), maintainableFieldDefinition.getName(), false);
325
326                        boolean translateCodes = getMaintenanceDocumentDictionaryService().translateCodes(o.getClass());
327                        if (translateCodes) {
328                                FieldUtils.setAdditionalDisplayPropertyForCodes(o.getClass(), field.getPropertyName(), field);
329                        }
330
331            setupField(field, maintainableFieldDefinition, conditionallyRequiredMaintenanceFields);
332
333            MaintenanceUtils.setFieldQuickfinder(o, field.getPropertyName(), maintainableFieldDefinition, field, displayedFieldNames, m);
334            MaintenanceUtils.setFieldDirectInquiry(o, field.getPropertyName(), maintainableFieldDefinition, field, displayedFieldNames);
335
336            // set default value
337            //TODO St. Ailish says review this. A question was raised on 11-16-2006 Tuscon meeting as to why this is done here and not in the formatter.
338            /*if (autoFillDefaultValues) {
339                Object defaultValue = maintainableFieldDefinition.getDefaultValue();
340                if (defaultValue != null) {
341                    if (defaultValue.toString().equals("true")) {
342                        defaultValue = "Yes";
343                    }
344                    else if (defaultValue.toString().equals("false")) {
345                        defaultValue = "No";
346                    }
347                    field.setPropertyValue(defaultValue);
348                }
349
350                Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
351                if (defaultValueFinderClass != null) {
352                    field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
353                }
354            }
355
356            // if this flag is set, and the current field is required, and readonly, and blank, use the
357            // defaultValueFinder if one exists
358            if (autoFillBlankRequiredValues) {
359                if ( maintainableFieldDefinition.isRequired() && maintainableFieldDefinition.isUnconditionallyReadOnly() ) {
360                    if ( StringUtils.isBlank( field.getPropertyValue() ) ) {
361                        Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
362                        if (defaultValueFinderClass != null) {
363                            field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
364                        }
365                    }
366                }
367            }
368                        */
369            field.setFieldLevelHelpEnabled(isMaintenanceFieldLevelHelpEnabled(m, maintainableFieldDefinition));
370            field.setFieldLevelHelpDisabled(isMaintenanceFieldLevelHelpDisabled(m, maintainableFieldDefinition));
371            field.setFieldLevelHelpUrl(maintainableFieldDefinition.getFieldLevelHelpUrl());
372        }
373
374        return field;
375
376    }
377
378    /**
379     * This method will return a new form for adding in a BO for a collection.
380     * This should be customized in a subclass so the default behavior is to return nothing.
381     *
382     * @param collectionDefinition The DD definition for the Collection.
383     * @param o The BusinessObject form which the new Fields will be populated.
384     * @param document MaintenanceDocument instance which we ar building fields for
385     * @param m
386     * @param displayedFieldNames What Fields are being displayed on the form in the UI?
387     * @param containerRowErrorKey The error key for the Container/Collection used for displaying error messages.
388     * @param parents
389     * @param hideAdd Should the add line be hidden when displaying this Collection/Container in the UI?
390     * @param numberOfColumns How many columns the Fields in the Collection will be split into when displaying them in the UI.
391     *
392     * @return The List of new Fields.
393     */
394    public static final List<Field> getNewFormFields(CollectionDefinitionI collectionDefinition, BusinessObject o, Maintainable m, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields, StringBuffer containerRowErrorKey, String parents, boolean hideAdd, int numberOfColumns) {
395        LOG.debug( "getNewFormFields" );
396        String collName = collectionDefinition.getName();
397
398        List<Field> collFields = new ArrayList<Field>();
399        Collection<? extends FieldDefinitionI> collectionFields;
400        //Class boClass = collectionDefinition.getDataObjectClass();
401        BusinessObject collBO = null;
402        try {
403            collectionFields = collectionDefinition.getFields();
404            collBO = m.getNewCollectionLine(parents + collName);
405
406            if ( LOG.isDebugEnabled() ) {
407                LOG.debug( "newBO for add line: " + collBO );
408            }
409
410            for ( FieldDefinitionI fieldDefinition : collectionFields  ) {
411                // construct Field UI object from definition
412                Field collField = FieldUtils.getPropertyField(collectionDefinition.getBusinessObjectClass(), fieldDefinition.getName(), false);
413
414                if (fieldDefinition instanceof MaintainableFieldDefinition) {
415                    setupField(collField, fieldDefinition, conditionallyRequiredMaintenanceFields);
416                }
417                //generate the error key for the add row
418                String[] nameParts = StringUtils.split(collField.getPropertyName(), ".");
419                String fieldErrorKey = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + KRADConstants.ADD_PREFIX + ".";
420                fieldErrorKey += collName + ".";
421                for (int i = 0; i < nameParts.length; i++) {
422                    fieldErrorKey += nameParts[i];
423                    containerRowErrorKey.append(fieldErrorKey);
424                    if (i < nameParts.length) {
425                        fieldErrorKey += ".";
426                        containerRowErrorKey.append(",");
427                    }
428                }
429
430                //  set the QuickFinderClass
431                BusinessObject collectionBoInstance = collectionDefinition.getBusinessObjectClass().newInstance();
432                FieldUtils.setInquiryURL(collField, collectionBoInstance, fieldDefinition.getName());
433                if (collectionDefinition instanceof MaintainableCollectionDefinition) {
434                    MaintenanceUtils.setFieldQuickfinder(collectionBoInstance, parents+collectionDefinition.getName(), true, 0, fieldDefinition.getName(), collField, displayedFieldNames, m, (MaintainableFieldDefinition) fieldDefinition);
435                    MaintenanceUtils
436                            .setFieldDirectInquiry(collectionBoInstance, parents + collectionDefinition.getName(), true,
437                                    0, fieldDefinition.getName(), collField, displayedFieldNames, m,
438                                    (MaintainableFieldDefinition) fieldDefinition);
439                }
440                else {
441                    LookupUtils.setFieldQuickfinder(collectionBoInstance, parents+collectionDefinition.getName(), true, 0, fieldDefinition.getName(), collField, displayedFieldNames, m);
442                    LookupUtils.setFieldDirectInquiry(collectionBoInstance, fieldDefinition.getName(), collField);
443                }
444
445                collFields.add(collField);
446            }
447
448        } catch (InstantiationException e) {
449            LOG.error("Unable to create instance of object class" + e.getMessage());
450            throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
451        } catch (IllegalAccessException e) {
452            LOG.error("Unable to create instance of object class" + e.getMessage());
453            throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
454        }
455
456        // populate field values from business object
457        collFields = FieldUtils.populateFieldsFromBusinessObject(collFields,collBO);
458
459        // need to append the prefix afterwards since the population command (above)
460        // does not handle the prefixes on the property names
461        for ( Field field : collFields ) {
462            // prefix name for add line
463            field.setPropertyName(KRADConstants.MAINTENANCE_ADD_PREFIX + parents + collectionDefinition.getName() + "." + field.getPropertyName());
464        }
465        LOG.debug("Error Key for section " + collectionDefinition.getName() + " : " + containerRowErrorKey.toString());
466
467        
468        collFields = constructContainerField(collectionDefinition, parents, o, hideAdd, numberOfColumns, collName, collFields);
469
470        return collFields;
471    }
472
473    /**
474     * 
475     * This method handles setting up a container field not including the add fields
476     * 
477     * @param collectionDefinition
478     * @param parents
479     * @param o
480     * @param hideAdd
481     * @param numberOfColumns
482     * @param collName
483     * @param collFields
484     * @return
485     */
486    public static List<Field> constructContainerField(CollectionDefinitionI collectionDefinition, String parents, BusinessObject o, boolean hideAdd, int numberOfColumns, String collName, List<Field> collFields) {
487        // get label for collection
488        String collectionLabel = getDataDictionaryService().getCollectionLabel(o.getClass(), collectionDefinition.getName());
489
490        // retrieve the summary label either from the override or from the DD
491        String collectionElementLabel = collectionDefinition.getSummaryTitle();
492        if(StringUtils.isEmpty(collectionElementLabel)){
493            collectionElementLabel = getDataDictionaryService().getCollectionElementLabel(o.getClass().getName(), collectionDefinition.getName(),collectionDefinition.getBusinessObjectClass());
494        }
495
496        // container field
497        Field containerField;
498        containerField = FieldUtils.constructContainerField(collName, collectionLabel, collFields, numberOfColumns);
499        if(StringUtils.isNotEmpty(collectionElementLabel)) {
500            containerField.setContainerElementName(collectionElementLabel);
501        }
502        collFields = new ArrayList();
503        collFields.add(containerField);
504
505        // field button for adding lines
506        if(!hideAdd  && collectionDefinition.getIncludeAddLine()) {
507            Field field = new Field();
508
509            String addButtonName = KRADConstants.DISPATCH_REQUEST_PARAMETER + "." + KRADConstants.ADD_LINE_METHOD + "." + parents + collectionDefinition.getName() + "." + KRADConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL + collectionDefinition.getBusinessObjectClass().getName() + KRADConstants.METHOD_TO_CALL_BOPARM_RIGHT_DEL;
510            field.setPropertyName(addButtonName);
511            field.setFieldType(Field.IMAGE_SUBMIT);
512            field.setPropertyValue("images/tinybutton-add1.gif");
513            // collFields.add(field);
514            containerField.getContainerRows().add(new Row(field));
515        }
516
517        if (collectionDefinition instanceof MaintainableCollectionDefinition) {
518            if (FieldUtils.isCollectionMultipleLookupEnabled((MaintainableCollectionDefinition) collectionDefinition)) {
519                FieldUtils.modifyFieldToSupportMultipleValueLookups(containerField, parents, (MaintainableCollectionDefinition) collectionDefinition);
520            }
521        }
522
523        return collFields;
524    }
525
526    /**
527     * Call getNewFormFields with no parents.
528     *
529     * @see #getNewFormFields(org.kuali.rice.kns.datadictionary.CollectionDefinitionI, BusinessObject, Maintainable, List, StringBuffer, String, boolean, int)
530     */
531    public static final List<Field> getNewFormFields(MaintainableCollectionDefinition collectionDefinition, BusinessObject o, Maintainable m, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields, StringBuffer containerRowErrorKey, int numberOfColumns) {
532        String parent = "";
533        return getNewFormFields(collectionDefinition, o, m, displayedFieldNames, conditionallyRequiredMaintenanceFields, containerRowErrorKey, parent, false, numberOfColumns);
534    }
535
536    /**
537     * Create a Field for display on an Inquiry screen.
538     *
539     * @param d The DD definition for the Field.
540     * @param o The BusinessObject from which the Field will be populated.
541     * @param s The Section in which the Field will be displayed.
542     *
543     * @return The populated Field.
544     */
545    public static Field toField(FieldDefinition d, BusinessObject o, Section s) {
546        Field field = FieldUtils.getPropertyField(o.getClass(), d.getAttributeName(), false);
547        
548        FieldUtils.setInquiryURL(field, o, field.getPropertyName());
549
550                String alternateDisplayPropertyName = getBusinessObjectDictionaryService()
551                                .getInquiryFieldAlternateDisplayAttributeName(o.getClass(), d.getAttributeName());
552                if (StringUtils.isNotBlank(alternateDisplayPropertyName)) {
553                        field.setAlternateDisplayPropertyName(alternateDisplayPropertyName);
554                }
555
556                String additionalDisplayPropertyName = getBusinessObjectDictionaryService()
557                                .getInquiryFieldAdditionalDisplayAttributeName(o.getClass(), d.getAttributeName());
558                if (StringUtils.isNotBlank(additionalDisplayPropertyName)) {
559                        field.setAdditionalDisplayPropertyName(additionalDisplayPropertyName);
560                }
561                else {
562                        boolean translateCodes = getBusinessObjectDictionaryService().tranlateCodesInInquiry(o.getClass());
563                        if (translateCodes) {
564                                FieldUtils.setAdditionalDisplayPropertyForCodes(o.getClass(), d.getAttributeName(), field);
565                        }
566                }
567
568        populateFieldFromBusinessObject(field, o);
569
570        return field;
571    }
572
573        public static DataDictionaryService getDataDictionaryService() {
574        if (dataDictionaryService == null) {
575                dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
576        }
577                return dataDictionaryService;
578        }
579
580        public static PersistenceStructureService getPersistenceStructureService() {
581        if (persistenceStructureService == null) {
582                persistenceStructureService = KNSServiceLocator.getPersistenceStructureService();
583        }
584                return persistenceStructureService;
585        }
586
587        public static BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
588        if (businessObjectDictionaryService == null) {
589                businessObjectDictionaryService = KNSServiceLocator.getBusinessObjectDictionaryService();
590        }
591                return businessObjectDictionaryService; 
592        }
593        
594        public static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
595        if (maintenanceDocumentDictionaryService == null) {
596                maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
597        }
598                return maintenanceDocumentDictionaryService; 
599        }
600
601}
602