0001: /*
0002: * Copyright 2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.kuali.core.web.ui;
0017:
0018: import java.util.ArrayList;
0019: import java.util.Collection;
0020: import java.util.HashMap;
0021: import java.util.Iterator;
0022: import java.util.List;
0023: import java.util.Map;
0024:
0025: import org.apache.commons.beanutils.PropertyUtils;
0026: import org.apache.commons.lang.StringUtils;
0027: import org.kuali.RiceConstants;
0028: import org.kuali.core.bo.BusinessObject;
0029: import org.kuali.core.bo.Inactivateable;
0030: import org.kuali.core.bo.PersistableBusinessObject;
0031: import org.kuali.core.datadictionary.CollectionDefinitionI;
0032: import org.kuali.core.datadictionary.FieldDefinition;
0033: import org.kuali.core.datadictionary.FieldDefinitionI;
0034: import org.kuali.core.datadictionary.InquiryCollectionDefinition;
0035: import org.kuali.core.datadictionary.InquirySectionDefinition;
0036: import org.kuali.core.datadictionary.InquirySubSectionHeaderDefinition;
0037: import org.kuali.core.datadictionary.MaintainableCollectionDefinition;
0038: import org.kuali.core.datadictionary.MaintainableFieldDefinition;
0039: import org.kuali.core.datadictionary.MaintainableItemDefinition;
0040: import org.kuali.core.datadictionary.MaintainableSectionDefinition;
0041: import org.kuali.core.datadictionary.MaintainableSubSectionHeaderDefinition;
0042: import org.kuali.core.datadictionary.SubSectionHeaderDefinitionI;
0043: import org.kuali.core.datadictionary.mask.Mask;
0044: import org.kuali.core.inquiry.Inquirable;
0045: import org.kuali.core.lookup.LookupUtils;
0046: import org.kuali.core.maintenance.Maintainable;
0047: import org.kuali.core.util.FieldUtils;
0048: import org.kuali.core.util.GlobalVariables;
0049: import org.kuali.core.util.ObjectUtils;
0050: import org.kuali.rice.KNSServiceLocator;
0051:
0052: public class SectionBridge {
0053: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0054: .getLogger(SectionBridge.class);
0055:
0056: /**
0057: * This method creates a Section for display on an Inquiry Screen.
0058: *
0059: * @param sd The DD definition from which to construct the Section.
0060: * @param o The BusinessObject from which to populate the Section values.
0061: * @return A populated Section.
0062: */
0063: public static final Section toSection(Inquirable inquirable,
0064: InquirySectionDefinition sd, BusinessObject o) {
0065: Section section = new Section();
0066: section.setSectionTitle(sd.getTitle());
0067: section.setRows(new ArrayList());
0068: if (StringUtils.isNotBlank(sd.getNumberOfColumns())) {
0069: section.setNumberOfColumns(Integer.parseInt(sd
0070: .getNumberOfColumns()));
0071: } else {
0072: section
0073: .setNumberOfColumns(RiceConstants.DEFAULT_NUM_OF_COLUMNS);
0074: }
0075:
0076: List<Field> sectionFields = new ArrayList();
0077: for (FieldDefinition fieldDefinition : sd.getInquiryFields()) {
0078: List row = new ArrayList();
0079:
0080: Field f = null;
0081: if (fieldDefinition instanceof InquiryCollectionDefinition) {
0082: InquiryCollectionDefinition inquiryCollectionDefinition = (InquiryCollectionDefinition) fieldDefinition;
0083:
0084: List<Row> sectionRows = new ArrayList();
0085: sectionRows = getContainerRows(section,
0086: inquiryCollectionDefinition, o, null, null,
0087: new ArrayList(), new StringBuffer(section
0088: .getErrorKey()), Integer
0089: .parseInt(inquiryCollectionDefinition
0090: .getNumberOfColumns()),
0091: inquirable);
0092: section.setRows(sectionRows);
0093: } else if (fieldDefinition instanceof InquirySubSectionHeaderDefinition) {
0094: f = createMaintainableSubSectionHeader((InquirySubSectionHeaderDefinition) fieldDefinition);
0095: } else {
0096: f = FieldBridge.toField(fieldDefinition, o, section);
0097: }
0098:
0099: if (null != f) {
0100: sectionFields.add(f);
0101: }
0102:
0103: }
0104:
0105: if (!sectionFields.isEmpty()) {
0106: section.setRows(FieldUtils.wrapFields(sectionFields,
0107: section.getNumberOfColumns()));
0108: }
0109:
0110: return section;
0111: }
0112:
0113: /**
0114: * This method creates a Section for a MaintenanceDocument.
0115: *
0116: * @param sd The DD definition of the Section.
0117: * @param o The BusinessObject from which the Section will be populated.
0118: * @param maintainable
0119: * @param maintenanceAction The action (new, newwithexisting, copy, edit, etc) requested from the UI.
0120: * @param autoFillDefaultValues Should default values be auto-filled?
0121: * @param autoFillBlankRequiredValues Should required values left blank on the UI be auto-filled?
0122: * @param displayedFieldNames What fields are displayed on the UI?
0123: * @return A populated Section.
0124: * @throws InstantiationException
0125: * @throws IllegalAccessException
0126: */
0127: public static final Section toSection(
0128: MaintainableSectionDefinition sd, BusinessObject o,
0129: Maintainable maintainable, Maintainable oldMaintainable,
0130: String maintenanceAction, boolean autoFillDefaultValues,
0131: boolean autoFillBlankRequiredValues,
0132: List<String> displayedFieldNames)
0133: throws InstantiationException, IllegalAccessException {
0134: Section section = new Section();
0135:
0136: section.setSectionTitle(sd.getTitle());
0137: section.setSectionClass(o.getClass());
0138:
0139: // iterate through section maint items and contruct Field UI objects
0140: Collection maintItems = sd.getMaintainableItems();
0141: List<Row> sectionRows = new ArrayList<Row>();
0142: List<Field> sectionFields = new ArrayList<Field>();
0143:
0144: for (Iterator iterator = maintItems.iterator(); iterator
0145: .hasNext();) {
0146: MaintainableItemDefinition item = (MaintainableItemDefinition) iterator
0147: .next();
0148: Field field = FieldBridge.toField(item, sd, o,
0149: maintainable, section, autoFillDefaultValues,
0150: autoFillBlankRequiredValues, displayedFieldNames);
0151: boolean skipAdd = false;
0152:
0153: // if CollectionDefiniton, then have a many section
0154: if (item instanceof MaintainableCollectionDefinition) {
0155: MaintainableCollectionDefinition definition = (MaintainableCollectionDefinition) item;
0156: section.getContainedCollectionNames().add(
0157: ((MaintainableCollectionDefinition) item)
0158: .getName());
0159:
0160: StringBuffer containerRowErrorKey = new StringBuffer();
0161: sectionRows = getContainerRows(section, definition, o,
0162: maintainable, oldMaintainable,
0163: displayedFieldNames, containerRowErrorKey,
0164: RiceConstants.DEFAULT_NUM_OF_COLUMNS, null);
0165: } else if (item instanceof MaintainableSubSectionHeaderDefinition) {
0166: MaintainableSubSectionHeaderDefinition definition = (MaintainableSubSectionHeaderDefinition) item;
0167: field = createMaintainableSubSectionHeader(definition);
0168: }
0169:
0170: if (!skipAdd) {
0171: sectionFields.add(field);
0172: }
0173: }
0174:
0175: // populate field values from business object
0176: if (o != null && !autoFillDefaultValues) {
0177: sectionFields = FieldUtils
0178: .populateFieldsFromBusinessObject(sectionFields, o);
0179:
0180: /* if maintenance action is copy, clear out secure fields */
0181: if (RiceConstants.MAINTENANCE_COPY_ACTION
0182: .equals(maintenanceAction)) {
0183: for (Iterator iterator = sectionFields.iterator(); iterator
0184: .hasNext();) {
0185: Field element = (Field) iterator.next();
0186: if (element.isSecure()) {
0187: element.setPropertyValue("");
0188: }
0189: }
0190: }
0191: }
0192:
0193: sectionRows.addAll(FieldUtils.wrapFields(sectionFields));
0194: section.setRows(sectionRows);
0195:
0196: return section;
0197:
0198: }
0199:
0200: /**
0201: * @see #getContainerRows(Section, CollectionDefinitionI, BusinessObject, Maintainable, List<String>, StringBuffer, String,
0202: * boolean, int)
0203: */
0204: public static final List<Row> getContainerRows(Section s,
0205: CollectionDefinitionI collectionDefinition,
0206: BusinessObject o, Maintainable m,
0207: Maintainable oldMaintainable,
0208: List<String> displayedFieldNames,
0209: StringBuffer containerRowErrorKey, int numberOfColumns,
0210: Inquirable inquirable) {
0211: return getContainerRows(s, collectionDefinition, o, m,
0212: oldMaintainable, displayedFieldNames,
0213: containerRowErrorKey, "", false, numberOfColumns,
0214: inquirable);
0215: }
0216:
0217: /**
0218: * Builds a list of Rows with Fields of type containers for a many section.
0219: *
0220: * @param s The Section containing the Collection/Container.
0221: * @param collectionDefinition The DD definition of the Collection.
0222: * @param o The BusinessObject from which the Container/Collection will be populated.
0223: * @param m The Maintainable for the BO (needed by some methods called on FieldBridge, FieldUtils etc.)
0224: * @param displayedFieldNames
0225: * @param containerRowErrorKey The error key for the Container/Collection.
0226: * @param parents
0227: * @param hideAdd Should the add line be added to the Container/Collection?
0228: * @param numberOfColumns In how many columns in the UI will the fields in the Container/Collection be shown?
0229: * @return
0230: */
0231: public static final List<Row> getContainerRows(Section s,
0232: CollectionDefinitionI collectionDefinition,
0233: BusinessObject o, Maintainable m,
0234: Maintainable oldMaintainable,
0235: List<String> displayedFieldNames,
0236: StringBuffer containerRowErrorKey, String parents,
0237: boolean hideAdd, int numberOfColumns, Inquirable inquirable) {
0238: List<Row> containerRows = new ArrayList<Row>();
0239: List<Field> collFields = new ArrayList<Field>();
0240:
0241: String collectionName = collectionDefinition.getName();
0242:
0243: // add the toggle inactive record display button for the collection
0244: if (m != null
0245: && Inactivateable.class
0246: .isAssignableFrom(collectionDefinition
0247: .getBusinessObjectClass())
0248: && StringUtils.isBlank(parents)) {
0249: addShowInactiveButtonField(s, collectionName, !m
0250: .getShowInactiveRecords(collectionName));
0251: }
0252: if (inquirable != null
0253: && Inactivateable.class
0254: .isAssignableFrom(collectionDefinition
0255: .getBusinessObjectClass())
0256: && StringUtils.isBlank(parents)) {
0257: addShowInactiveButtonField(s, collectionName, !inquirable
0258: .getShowInactiveRecords(collectionName));
0259: }
0260:
0261: // first need to populate the containerRows with the "new" form if available
0262: if (collectionDefinition.getIncludeAddLine()) {
0263: List<Field> newFormFields = new ArrayList<Field>();
0264: if (!hideAdd) {
0265: newFormFields = FieldBridge.getNewFormFields(
0266: collectionDefinition, o, m,
0267: displayedFieldNames, containerRowErrorKey,
0268: parents, hideAdd, numberOfColumns);
0269: }
0270: if (null != newFormFields) {
0271: containerRows.add(new Row(newFormFields));
0272: }
0273: }
0274:
0275: Collection collections = collectionDefinition.getCollections();
0276: for (Iterator iterator = collections.iterator(); iterator
0277: .hasNext();) {
0278: CollectionDefinitionI subCollectionDefinition = (CollectionDefinitionI) iterator
0279: .next();
0280: int subCollectionNumberOfColumn = numberOfColumns;
0281: if (collectionDefinition instanceof InquiryCollectionDefinition) {
0282: InquiryCollectionDefinition icd = (InquiryCollectionDefinition) subCollectionDefinition;
0283: if (StringUtils.isNotBlank(icd.getNumberOfColumns())) {
0284: subCollectionNumberOfColumn = Integer.parseInt(icd
0285: .getNumberOfColumns());
0286: }
0287: }
0288: // no colNum for add rows
0289: containerRows.addAll(getContainerRows(s,
0290: subCollectionDefinition, o, m, oldMaintainable,
0291: displayedFieldNames, containerRowErrorKey, parents
0292: + collectionDefinition.getName() + ".",
0293: true, subCollectionNumberOfColumn, inquirable));
0294: }
0295:
0296: // then we need to loop through the existing collection and add those fields
0297: Collection collectionFields = collectionDefinition.getFields();
0298: // get label for collection
0299: String collectionLabel = KNSServiceLocator
0300: .getDataDictionaryService().getCollectionLabel(
0301: o.getClass(), collectionDefinition.getName());
0302:
0303: // retrieve the summary label either from the override or from the DD
0304: String collectionElementLabel = collectionDefinition
0305: .getSummaryTitle();
0306: if (StringUtils.isEmpty(collectionElementLabel)) {
0307: collectionElementLabel = KNSServiceLocator
0308: .getDataDictionaryService()
0309: .getCollectionElementLabel(
0310: o.getClass().getName(),
0311: collectionDefinition.getName(),
0312: collectionDefinition
0313: .getBusinessObjectClass());
0314: }
0315:
0316: if (o != null) {
0317: if (PropertyUtils.isWriteable(o, collectionDefinition
0318: .getName())
0319: && ObjectUtils.getPropertyValue(o,
0320: collectionDefinition.getName()) != null) {
0321: Object obj = ObjectUtils.getPropertyValue(o,
0322: collectionName);
0323:
0324: Object oldObj = null;
0325: if (oldMaintainable != null
0326: && oldMaintainable.getBusinessObject() != null) {
0327: oldObj = ObjectUtils.getPropertyValue(
0328: oldMaintainable.getBusinessObject(),
0329: collectionName);
0330: }
0331:
0332: if (obj instanceof List) {
0333: Map summaryFields = new HashMap();
0334: boolean hidableRowsPresent = false;
0335: for (int i = 0; i < ((List) obj).size(); i++) {
0336: BusinessObject lineBusinessObject = (BusinessObject) ((List) obj)
0337: .get(i);
0338:
0339: /*
0340: * Handle display of inactive records. The old maintainable is used to compare the old side (if it exists). If the row should not be displayed, it is set as
0341: * hidden and will be handled in the maintenance rowDisplay.tag.
0342: */
0343: boolean setRowHidden = false;
0344: BusinessObject oldLineBusinessObject = null;
0345: if (oldObj != null) {
0346: oldLineBusinessObject = (BusinessObject) ((List) oldObj)
0347: .get(i);
0348: }
0349:
0350: if (lineBusinessObject instanceof Inactivateable
0351: && !((Inactivateable) lineBusinessObject)
0352: .isActive()) {
0353: if (m != null) {
0354: // rendering a maint doc
0355: if (!hidableRowsPresent) {
0356: hidableRowsPresent = isRowHideableForMaintenanceDocument(
0357: lineBusinessObject,
0358: oldLineBusinessObject);
0359: }
0360: setRowHidden = isRowHiddenForMaintenanceDocument(
0361: lineBusinessObject,
0362: oldLineBusinessObject, m,
0363: collectionName);
0364: }
0365: if (inquirable != null) {
0366: // rendering an inquiry screen
0367: if (!hidableRowsPresent) {
0368: hidableRowsPresent = isRowHideableForInquiry(lineBusinessObject);
0369: }
0370: setRowHidden = isRowHiddenForInquiry(
0371: lineBusinessObject, inquirable,
0372: collectionName);
0373: }
0374: }
0375:
0376: collFields = new ArrayList<Field>();
0377: List<String> duplicateIdentificationFieldNames = new ArrayList<String>();
0378: //We only need to do this if the collection definition is a maintainable collection definition,
0379: //don't need it for inquiry collection definition.
0380: if (collectionDefinition instanceof MaintainableCollectionDefinition) {
0381: Collection<MaintainableFieldDefinition> duplicateFieldDefs = ((MaintainableCollectionDefinition) collectionDefinition)
0382: .getDuplicateIdentificationFields();
0383: for (MaintainableFieldDefinition eachFieldDef : duplicateFieldDefs) {
0384: duplicateIdentificationFieldNames
0385: .add(eachFieldDef.getName());
0386: }
0387: }
0388:
0389: for (Iterator iterator = collectionFields
0390: .iterator(); iterator.hasNext();) {
0391: FieldDefinitionI fieldDefinition = (FieldDefinitionI) iterator
0392: .next();
0393:
0394: // construct Field UI object from definition
0395: Field collField = FieldUtils
0396: .getPropertyField(
0397: collectionDefinition
0398: .getBusinessObjectClass(),
0399: fieldDefinition.getName(),
0400: false);
0401:
0402: FieldBridge.setupField(collField,
0403: fieldDefinition);
0404: setPrimaryKeyFieldsReadOnly(
0405: collectionDefinition
0406: .getBusinessObjectClass(),
0407: collField);
0408:
0409: //If the duplicateIdentificationFields were specified in the maint. doc. DD, we'll need
0410: //to set the fields to be read only as well, in addition to the primary key fields.
0411: if (duplicateIdentificationFieldNames
0412: .size() > 0) {
0413: setDuplicateIdentificationFieldsReadOnly(
0414: collField,
0415: duplicateIdentificationFieldNames);
0416: }
0417:
0418: FieldUtils.setInquiryURL(collField,
0419: lineBusinessObject, fieldDefinition
0420: .getName());
0421: // save the simple property name
0422: String name = collField.getPropertyName();
0423:
0424: // prefix name for multi line (indexed)
0425: collField
0426: .setPropertyName(collectionDefinition
0427: .getName()
0428: + "["
0429: + (new Integer(i))
0430: .toString()
0431: + "]."
0432: + collField
0433: .getPropertyName());
0434:
0435: // commenting out codes for sub-collections show/hide for now
0436: // subCollField.setContainerName(collectionDefinition.getName() + "["+i+"]" +"." +
0437: // subCollectionDefinition.getName() + "[" + j + "]");
0438:
0439: LookupUtils.setFieldQuickfinder(
0440: lineBusinessObject,
0441: collectionDefinition.getName(),
0442: false, i, name, collField,
0443: displayedFieldNames, m);
0444:
0445: Object propertyValue = ObjectUtils
0446: .getPropertyValue(
0447: lineBusinessObject,
0448: fieldDefinition.getName());
0449: // set field value from business object
0450: // check if field contains sensitive data and user is authorized to see value
0451: boolean viewAuthorized = KNSServiceLocator
0452: .getAuthorizationService()
0453: .isAuthorizedToViewAttribute(
0454: GlobalVariables
0455: .getUserSession()
0456: .getUniversalUser(),
0457: lineBusinessObject
0458: .getClass()
0459: .getName(), name);
0460: if (!viewAuthorized) {
0461:
0462: // set mask as field value
0463: Mask propertyMask = KNSServiceLocator
0464: .getDataDictionaryService()
0465: .getAttributeDisplayMask(
0466: lineBusinessObject
0467: .getClass(),
0468: name);
0469: if (propertyMask == null) {
0470: throw new RuntimeException(
0471: "No mask specified for secure field.");
0472: }
0473:
0474: collField.setPropertyValue(propertyMask
0475: .maskValue(propertyValue));
0476: collField
0477: .setDisplayMaskValue(propertyMask
0478: .maskValue(propertyValue));
0479:
0480: } else {
0481: collField
0482: .setPropertyValue(propertyValue);
0483: }
0484:
0485: // the the field as read only (if appropriate)
0486: if (fieldDefinition.isReadOnlyAfterAdd()) {
0487: collField.setReadOnly(true);
0488: }
0489:
0490: // check if this is a summary field
0491: if (collectionDefinition
0492: .hasSummaryField(fieldDefinition
0493: .getName())) {
0494: summaryFields.put(fieldDefinition
0495: .getName(), collField);
0496: }
0497:
0498: collFields.add(collField);
0499: }
0500:
0501: Field containerField;
0502: containerField = FieldUtils
0503: .constructContainerField(
0504: RiceConstants.EDIT_PREFIX
0505: + "["
0506: + (new Integer(i))
0507: .toString()
0508: + "]", collectionLabel
0509: + " " + (i + 1),
0510: collFields, numberOfColumns);
0511: // why is this only on collections and not subcollections any significance or just oversight?
0512: containerField
0513: .setContainerName(collectionDefinition
0514: .getName()
0515: + "["
0516: + (new Integer(i)).toString()
0517: + "].");
0518:
0519: /* If the collection line is pending (meaning added by this document) the isNewCollectionRecord will be set to true. In this
0520: case we give an option to delete the line. The parameters for the delete action method are embedded into the button name. */
0521: if (lineBusinessObject instanceof PersistableBusinessObject
0522: && ((PersistableBusinessObject) lineBusinessObject)
0523: .isNewCollectionRecord()) {
0524: containerField
0525: .getContainerRows()
0526: .add(
0527: new Row(
0528: getDeleteRowButtonField(
0529: parents
0530: + collectionDefinition
0531: .getName(),
0532: (new Integer(
0533: i))
0534: .toString())));
0535: }
0536:
0537: if (StringUtils
0538: .isNotEmpty(collectionElementLabel)) {
0539: //We don't want to associate any indexes to the containerElementName anymore so that
0540: //when the element is deleted, the currentTabIndex won't be associated with the
0541: //wrong tab for the remaining tab.
0542: //containerField.setContainerElementName(collectionElementLabel + " " + (i + 1));
0543: containerField
0544: .setContainerElementName(collectionElementLabel);
0545: // reorder summaryFields to make sure they are in the order specified in the summary section
0546: List orderedSummaryFields = getSummaryFields(
0547: summaryFields, collectionDefinition);
0548: containerField
0549: .setContainerDisplayFields(orderedSummaryFields);
0550: }
0551:
0552: Row containerRow = new Row(containerField);
0553: if (setRowHidden) {
0554: containerRow.setHidden(true);
0555: }
0556: containerRows.add(containerRow);
0557:
0558: Collection subCollections = collectionDefinition
0559: .getCollections();
0560: List<Field> subCollFields = new ArrayList<Field>();
0561:
0562: summaryFields = new HashMap();
0563: // iterate over the subCollections directly on this collection
0564: for (Iterator iter = subCollections.iterator(); iter
0565: .hasNext();) {
0566: CollectionDefinitionI subCollectionDefinition = (CollectionDefinitionI) iter
0567: .next();
0568: Collection subCollectionFields = subCollectionDefinition
0569: .getFields();
0570: int subCollectionNumberOfColumns = numberOfColumns;
0571:
0572: if (!s
0573: .getContainedCollectionNames()
0574: .contains(
0575: collectionDefinition
0576: .getName()
0577: + "."
0578: + subCollectionDefinition
0579: .getName())) {
0580: s
0581: .getContainedCollectionNames()
0582: .add(
0583: collectionDefinition
0584: .getName()
0585: + "."
0586: + subCollectionDefinition
0587: .getName());
0588: }
0589:
0590: if (subCollectionDefinition instanceof InquiryCollectionDefinition) {
0591: InquiryCollectionDefinition icd = (InquiryCollectionDefinition) subCollectionDefinition;
0592: if (StringUtils.isNotBlank(icd
0593: .getNumberOfColumns())) {
0594: subCollectionNumberOfColumns = Integer
0595: .parseInt(icd
0596: .getNumberOfColumns());
0597: }
0598: }
0599: // get label for collection
0600: String subCollectionLabel = KNSServiceLocator
0601: .getDataDictionaryService()
0602: .getCollectionLabel(
0603: o.getClass(),
0604: subCollectionDefinition
0605: .getName());
0606:
0607: // retrieve the summary label either from the override or from the DD
0608: String subCollectionElementLabel = subCollectionDefinition
0609: .getSummaryTitle();
0610: if (StringUtils
0611: .isEmpty(subCollectionElementLabel)) {
0612: subCollectionElementLabel = KNSServiceLocator
0613: .getDataDictionaryService()
0614: .getCollectionElementLabel(
0615: o.getClass().getName(),
0616: subCollectionDefinition
0617: .getName(),
0618: subCollectionDefinition
0619: .getBusinessObjectClass());
0620: }
0621: // make sure it's really a collection (i.e. list)
0622:
0623: String subCollectionName = subCollectionDefinition
0624: .getName();
0625: Object subObj = ObjectUtils
0626: .getPropertyValue(
0627: lineBusinessObject,
0628: subCollectionName);
0629:
0630: Object oldSubObj = null;
0631: if (oldLineBusinessObject != null) {
0632: oldSubObj = ObjectUtils
0633: .getPropertyValue(
0634: oldLineBusinessObject,
0635: subCollectionName);
0636: }
0637:
0638: if (subObj instanceof List) {
0639: /* recursively call this method to get the add row and exisiting members of the subCollections subcollections containerRows.addAll(getContainerRows(subCollectionDefinition,
0640: displayedFieldNames,containerRowErrorKey, parents+collectionDefinition.getName()+"["+i+"]"+".","[0]",false, subCollectionNumberOfColumn)); */
0641: containerField
0642: .getContainerRows()
0643: .addAll(
0644: getContainerRows(
0645: s,
0646: subCollectionDefinition,
0647: o,
0648: m,
0649: oldMaintainable,
0650: displayedFieldNames,
0651: containerRowErrorKey,
0652: parents
0653: + collectionDefinition
0654: .getName()
0655: + "["
0656: + i
0657: + "]"
0658: + ".",
0659: false,
0660: subCollectionNumberOfColumns,
0661: inquirable));
0662:
0663: // iterate over the fields
0664: for (int j = 0; j < ((List) subObj)
0665: .size(); j++) {
0666: BusinessObject lineSubBusinessObject = (BusinessObject) ((List) subObj)
0667: .get(j);
0668:
0669: // determine if sub collection line is inactive and should be hidden
0670: boolean setSubRowHidden = false;
0671: if (lineSubBusinessObject instanceof Inactivateable
0672: && !((Inactivateable) lineSubBusinessObject)
0673: .isActive()) {
0674: if (oldSubObj != null) {
0675: // get corresponding elements in both the new list and the old list
0676: BusinessObject oldLineSubBusinessObject = (BusinessObject) ((List) oldSubObj)
0677: .get(j);
0678: if (m != null) {
0679: if (!hidableRowsPresent) {
0680: hidableRowsPresent = isRowHideableForMaintenanceDocument(
0681: lineSubBusinessObject,
0682: oldLineSubBusinessObject);
0683: }
0684: setSubRowHidden = isRowHiddenForMaintenanceDocument(
0685: lineSubBusinessObject,
0686: oldLineSubBusinessObject,
0687: m,
0688: collectionName);
0689: }
0690: }
0691: if (inquirable != null) {
0692: if (!hidableRowsPresent) {
0693: hidableRowsPresent = isRowHideableForInquiry(lineSubBusinessObject);
0694: }
0695: setSubRowHidden = isRowHiddenForInquiry(
0696: lineSubBusinessObject,
0697: inquirable,
0698: collectionName);
0699: }
0700: }
0701:
0702: subCollFields = new ArrayList<Field>();
0703: // construct field objects based on fields
0704: for (Iterator iterator = subCollectionFields
0705: .iterator(); iterator
0706: .hasNext();) {
0707: FieldDefinitionI fieldDefinition = (FieldDefinitionI) iterator
0708: .next();
0709:
0710: // construct Field UI object from definition
0711: Field subCollField = FieldUtils
0712: .getPropertyField(
0713: subCollectionDefinition
0714: .getBusinessObjectClass(),
0715: fieldDefinition
0716: .getName(),
0717: false);
0718:
0719: FieldBridge.setupField(
0720: subCollField,
0721: fieldDefinition);
0722: setPrimaryKeyFieldsReadOnly(
0723: subCollectionDefinition
0724: .getBusinessObjectClass(),
0725: subCollField);
0726:
0727: // save the simple property name
0728: String name = subCollField
0729: .getPropertyName();
0730:
0731: // prefix name for multi line (indexed)
0732: subCollField
0733: .setPropertyName(collectionDefinition
0734: .getName()
0735: + "["
0736: + i
0737: + "]"
0738: + "."
0739: + subCollectionDefinition
0740: .getName()
0741: + "["
0742: + j
0743: + "]."
0744: + subCollField
0745: .getPropertyName());
0746:
0747: // commenting out codes for sub-collections show/hide for now
0748: LookupUtils
0749: .setFieldQuickfinder(
0750: lineSubBusinessObject,
0751: collectionDefinition
0752: .getName()
0753: + "["
0754: + i
0755: + "]"
0756: + "."
0757: + subCollectionDefinition
0758: .getName()
0759: + "["
0760: + j
0761: + "].",
0762: false, i, name,
0763: subCollField,
0764: displayedFieldNames);
0765:
0766: Object propertyValue = ObjectUtils
0767: .getPropertyValue(
0768: lineSubBusinessObject,
0769: fieldDefinition
0770: .getName());
0771: // set field value from business object
0772: // check if field contains sensitive data and user is authorized to see value
0773: boolean viewAuthorized = KNSServiceLocator
0774: .getAuthorizationService()
0775: .isAuthorizedToViewAttribute(
0776: GlobalVariables
0777: .getUserSession()
0778: .getUniversalUser(),
0779: lineSubBusinessObject
0780: .getClass()
0781: .getName(),
0782: name);
0783: if (!viewAuthorized) {
0784:
0785: // set mask as field value
0786: Mask propertyMask = KNSServiceLocator
0787: .getDataDictionaryService()
0788: .getAttributeDisplayMask(
0789: lineSubBusinessObject
0790: .getClass(),
0791: name);
0792: if (propertyMask == null) {
0793: throw new RuntimeException(
0794: "No mask specified for secure field.");
0795: }
0796:
0797: subCollField
0798: .setPropertyValue(propertyMask
0799: .maskValue(propertyValue));
0800: subCollField
0801: .setDisplayMaskValue(propertyMask
0802: .maskValue(propertyValue));
0803:
0804: } else {
0805: subCollField
0806: .setPropertyValue(propertyValue);
0807: }
0808:
0809: // check if this is a summary field
0810: if (subCollectionDefinition
0811: .hasSummaryField(fieldDefinition
0812: .getName())) {
0813: summaryFields.put(
0814: fieldDefinition
0815: .getName(),
0816: subCollField);
0817: }
0818:
0819: subCollFields.add(subCollField);
0820: }
0821:
0822: Field subContainerField = FieldUtils
0823: .constructContainerField(
0824: RiceConstants.EDIT_PREFIX
0825: + "["
0826: + (new Integer(
0827: j))
0828: .toString()
0829: + "]",
0830: subCollectionLabel,
0831: subCollFields);
0832: if (lineSubBusinessObject instanceof PersistableBusinessObject
0833: && ((PersistableBusinessObject) lineSubBusinessObject)
0834: .isNewCollectionRecord()) {
0835: subContainerField
0836: .getContainerRows()
0837: .add(
0838: new Row(
0839: getDeleteRowButtonField(
0840: parents
0841: + collectionDefinition
0842: .getName()
0843: + "["
0844: + i
0845: + "]"
0846: + "."
0847: + subCollectionName,
0848: (new Integer(
0849: j))
0850: .toString())));
0851: }
0852:
0853: // summary line code
0854: if (StringUtils
0855: .isNotEmpty(subCollectionElementLabel)) {
0856: //We don't want to associate any indexes to the containerElementName anymore so that
0857: //when the element is deleted, the currentTabIndex won't be associated with the
0858: //wrong tab for the remaining tab.
0859: //subContainerField.setContainerElementName(subCollectionElementLabel + " " + (j + 1));
0860: subContainerField
0861: .setContainerElementName(collectionElementLabel
0862: + "-"
0863: + subCollectionElementLabel);
0864: }
0865: subContainerField
0866: .setContainerName(collectionDefinition
0867: .getName()
0868: + "."
0869: + subCollectionName);
0870: if (!summaryFields.isEmpty()) {
0871: // reorder summaryFields to make sure they are in the order specified in the summary section
0872: List orderedSummaryFields = getSummaryFields(
0873: summaryFields,
0874: subCollectionDefinition);
0875: subContainerField
0876: .setContainerDisplayFields(orderedSummaryFields);
0877: }
0878:
0879: Row subContainerRow = new Row(
0880: subContainerField);
0881: if (setRowHidden || setSubRowHidden) {
0882: subContainerRow.setHidden(true);
0883: }
0884: containerField.getContainerRows()
0885: .add(subContainerRow);
0886: }
0887: }
0888: }
0889: }
0890: if (!hidableRowsPresent) {
0891: s.setExtraButtonSource("");
0892: }
0893: }
0894: }
0895: }
0896:
0897: return containerRows;
0898: }
0899:
0900: /**
0901: * Helper method to build up a Field containing a delete button mapped up to remove the collection record identified by the
0902: * given collection name and index.
0903: *
0904: * @param collectionName - name of the collection
0905: * @param rowIndex - index of the record to associate delete button
0906: * @return Field - of type IMAGE_SUBMIT
0907: */
0908: private static final Field getDeleteRowButtonField(
0909: String collectionName, String rowIndex) {
0910: Field deleteButtonField = new Field();
0911:
0912: String deleteButtonName = RiceConstants.DISPATCH_REQUEST_PARAMETER
0913: + "."
0914: + RiceConstants.DELETE_LINE_METHOD
0915: + "."
0916: + collectionName
0917: + "."
0918: + RiceConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL
0919: + ".line" + rowIndex;
0920: deleteButtonField.setPropertyName(deleteButtonName);
0921: deleteButtonField.setFieldType(Field.IMAGE_SUBMIT);
0922: deleteButtonField
0923: .setPropertyValue("images/tinybutton-delete1.gif");
0924:
0925: return deleteButtonField;
0926: }
0927:
0928: /**
0929: * Helper method to build up the show inactive button source and place in the section.
0930: *
0931: * @param section - section that will display the button
0932: * @param collectionName - name of the collection to toggle setting
0933: * @param showInactive - boolean indicating whether inactive rows should be displayed
0934: * @return Field - of type IMAGE_SUBMIT
0935: */
0936: private static final void addShowInactiveButtonField(
0937: Section section, String collectionName, boolean showInactive) {
0938: String showInactiveButton = "<a name=\"showInactive"
0939: + collectionName + "\"><input type=\"image\" name=\""
0940: + RiceConstants.DISPATCH_REQUEST_PARAMETER + "."
0941: + RiceConstants.TOGGLE_INACTIVE_METHOD + "."
0942: + collectionName.replace('.', '_');
0943: showInactiveButton += "."
0944: + RiceConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL
0945: + showInactive + ".anchorshowInactive" + collectionName
0946: + "\" src=\"";
0947:
0948: if (showInactive) {
0949: showInactiveButton += "images/tinybutton-showinact.gif";
0950: } else {
0951: showInactiveButton += "images/tinybutton-hideinact.gif";
0952: }
0953:
0954: showInactiveButton += "\" alt=\"show(hide) inactive\" class=\"tinybutton\" /></a>";
0955: section.setExtraButtonSource(showInactiveButton);
0956: }
0957:
0958: /**
0959: * Retrieves the primary key property names for the given class. If the field's property is one of those keys, makes the field
0960: * read-only. This is called for collection lines. Since deletion is not allowed for existing lines, the pk fields must be
0961: * read-only, otherwise a user could change the pk value which would be equivalent to deleting the line and adding a new line.
0962: */
0963: private static final void setPrimaryKeyFieldsReadOnly(
0964: Class businessObjectClass, Field field) {
0965: List primaryKeyPropertyNames = KNSServiceLocator
0966: .getPersistenceStructureService().getPrimaryKeys(
0967: businessObjectClass);
0968: if (primaryKeyPropertyNames.contains(field.getPropertyName())) {
0969: field.setReadOnly(true);
0970: }
0971: }
0972:
0973: private static void setDuplicateIdentificationFieldsReadOnly(
0974: Field field, List<String> duplicateIdentificationFieldNames) {
0975: if (duplicateIdentificationFieldNames.contains(field
0976: .getPropertyName())) {
0977: field.setReadOnly(true);
0978: }
0979: }
0980:
0981: /**
0982: * This method returns an ordered list of fields.
0983: *
0984: * @param collSummaryFields
0985: * @param collectionDefinition
0986: * @return
0987: */
0988: private static final List<Field> getSummaryFields(
0989: Map collSummaryFields,
0990: CollectionDefinitionI collectionDefinition) {
0991: List<Field> orderedSummaryFields = new ArrayList<Field>();
0992: for (FieldDefinitionI summaryField : collectionDefinition
0993: .getSummaryFields()) {
0994: String name = summaryField.getName();
0995: boolean found = false;
0996: Field addField = (Field) collSummaryFields.get(name);
0997: if (!(addField == null)) {
0998: orderedSummaryFields.add(addField);
0999: found = true;
1000: }
1001:
1002: if (!found) {
1003: // should we throw a real error here?
1004: LOG.error("summaryField " + summaryField
1005: + " not present in the list");
1006: }
1007:
1008: }
1009: return orderedSummaryFields;
1010: }
1011:
1012: /**
1013: * This is a helper method to create a sub section header
1014: *
1015: * @param definition the MaintainableSubSectionHeaderDefinition that we'll use to create the sub section header
1016: * @return the Field, which is the sub section header
1017: */
1018: private static final Field createMaintainableSubSectionHeader(
1019: SubSectionHeaderDefinitionI definition) {
1020: Field separatorField = new Field();
1021: separatorField.setFieldLabel(definition.getName());
1022: separatorField.setFieldType(Field.SUB_SECTION_SEPARATOR);
1023: separatorField.setReadOnly(true);
1024:
1025: return separatorField;
1026: }
1027:
1028: /**
1029: * Determines whether a business object is hidable on a maintenance document. Hidable means that if the user chose to hide the inactive
1030: * elements in the collection in which the passed in BOs reside, then the BOs would be hidden
1031: *
1032: * @param lineBusinessObject the BO in the new maintainable, should be of type {@link PersistableBusinessObject} and {@link Inquirable}
1033: * @param oldLineBusinessObject the corresponding BO in the old maintainable, should be of type {@link PersistableBusinessObject} and
1034: * {@link Inquirable}
1035: * @return whether the BOs are eligible to be hidden if the user decides to hide them
1036: */
1037: protected static boolean isRowHideableForMaintenanceDocument(
1038: BusinessObject lineBusinessObject,
1039: BusinessObject oldLineBusinessObject) {
1040: if (oldLineBusinessObject != null) {
1041: if (((PersistableBusinessObject) lineBusinessObject)
1042: .isNewCollectionRecord()) {
1043: // new records are never hidden, regardless of active status
1044: return false;
1045: }
1046: if (!((Inactivateable) lineBusinessObject).isActive()
1047: && !((Inactivateable) oldLineBusinessObject)
1048: .isActive()) {
1049: // records with an old and new collection elements of NOT active are eligible to be hidden
1050: return true;
1051: }
1052: }
1053: return false;
1054: }
1055:
1056: /**
1057: * Determines whether a business object is hidden on a maintenance document.
1058: *
1059: * @param lineBusinessObject the BO in the new maintainable, should be of type {@link PersistableBusinessObject}
1060: * @param oldLineBusinessObject the corresponding BO in the old maintainable
1061: * @param newMaintainable the new maintainable from the maintenace document
1062: * @param collectionName the name of the collection from which these BOs come
1063: * @return
1064: */
1065: protected static boolean isRowHiddenForMaintenanceDocument(
1066: BusinessObject lineBusinessObject,
1067: BusinessObject oldLineBusinessObject,
1068: Maintainable newMaintainable, String collectionName) {
1069: if (isRowHideableForMaintenanceDocument(lineBusinessObject,
1070: oldLineBusinessObject)) {
1071: return !newMaintainable
1072: .getShowInactiveRecords(collectionName);
1073: }
1074: return false;
1075: }
1076:
1077: /**
1078: * Determines whether a business object is hidable on an inquiry screen. Hidable means that if the user chose to hide the inactive
1079: * elements in the collection in which the passed in BO resides, then the BO would be hidden
1080: *
1081: * @param lineBusinessObject the collection element BO, should be of type {@link PersistableBusinessObject} and {@link Inquirable}
1082: * @return whether the BO is eligible to be hidden if the user decides to hide them
1083: */
1084: protected static boolean isRowHideableForInquiry(
1085: BusinessObject lineBusinessObject) {
1086: return !((Inactivateable) lineBusinessObject).isActive();
1087: }
1088:
1089: /**
1090: * Determines whether a business object is hidden on an inquiry screen.
1091: *
1092: * @param lineBusinessObject the BO in the collection, should be of type {@link PersistableBusinessObject} and {@link Inquirable}
1093: * @param inquirable the inquirable
1094: * @param collectionName the name of the collection from which the BO comes
1095: * @return true if the business object is to be hidden; false otherwise
1096: */
1097: protected static boolean isRowHiddenForInquiry(
1098: BusinessObject lineBusinessObject, Inquirable inquirable,
1099: String collectionName) {
1100: if (isRowHideableForInquiry(lineBusinessObject)) {
1101: return !inquirable.getShowInactiveRecords(collectionName);
1102: }
1103: return false;
1104: }
1105: }
|