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