/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.sys.document.web; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.sys.businessobject.AccountingLine; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.document.AccountingDocument; import org.kuali.kfs.sys.document.authorization.AccountingLineAuthorizer; import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.kns.util.FieldUtils; import org.kuali.rice.kns.web.ui.Field; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; /** * A container which holds a single accounting line and the elements which will render it */ public class RenderableAccountingLineContainer implements AccountingLineRenderingContext { private List<AccountingLineTableRow> rows; private List<AccountingLineViewAction> actions; private AccountingLine accountingLine; private String accountingLineProperty; private List<Field> fields; private List<String> fieldNames; private KualiAccountingDocumentFormBase form; private String groupLabel; private Integer lineCount; private List errors; private AccountingLineAuthorizer accountingLineAuthorizer; private boolean editableLine; private boolean deletable = false; /** * Constructs a RenderableAccountingLineContainer * @param form the form being rendered * @param accountingLine the accounting line this container will render * @param accountingLineProperty the property to that accounting line * @param rows the rows to render * @param newLine whether this is a new accounting line or not * @param groupLabel the label for the group this accounting line is being rendered part of * @param errors the set of errors currently on the document * @param accountingLineAuthorizer the accounting line authorizer for the document * @param editableLine whether this line, as a whole _line_ is editable */ public RenderableAccountingLineContainer(KualiAccountingDocumentFormBase form, AccountingLine accountingLine, String accountingLineProperty, List<AccountingLineTableRow> rows, Integer lineCount, String groupLabel, List errors, AccountingLineAuthorizer accountingLineAuthorizer, boolean editableLine) { this.form = form; this.accountingLine = accountingLine; this.accountingLineProperty = accountingLineProperty; this.rows = rows; this.lineCount = lineCount; this.groupLabel = groupLabel; this.errors = errors; this.accountingLineAuthorizer = accountingLineAuthorizer; this.editableLine = editableLine; } /** * Gets the accountingLine attribute. * @return Returns the accountingLine. */ public AccountingLine getAccountingLine() { return accountingLine; } /** * Gets the accountingLineProperty attribute. * @return Returns the accountingLineProperty. */ public String getAccountingLineProperty() { return accountingLineProperty; } /** * Gets the actions attribute. * @return Returns the actions. */ public List<AccountingLineViewAction> getActionsForLine() { if (actions == null) { actions = accountingLineAuthorizer.getActions(form.getFinancialDocument(), this, accountingLineProperty, lineCount, GlobalVariables.getUserSession().getPerson(), groupLabel); } return actions; } /** * Gets the newLine attribute. * @return Returns the newLine. */ public boolean isNewLine() { return lineCount == null; } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getCurrentLineCount() */ public Integer getCurrentLineCount() { return lineCount; } /** * Gets the rows attribute. * @return Returns the rows. */ public List<AccountingLineTableRow> getRows() { return rows; } /** * @return the number of cells this accounting line container will render */ public int getCellCount() { int maxCells = 0; for (AccountingLineTableRow row : rows) { final int maxRowCellCount = row.getChildCellCount(); if (maxCells < maxRowCellCount) { maxCells = maxRowCellCount; } } return maxCells; } /** * Determines how many cells this container will say it wants to render * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getRenderableCellCount() */ public int getRenderableCellCount() { int maxCells = 0; for (AccountingLineTableRow row : rows) { final int maxRowCellCount = row.getChildRenderableCount(); if (maxCells < maxRowCellCount) { maxCells = maxRowCellCount; } } return maxCells; } /** * Adds empty cells to a table row * @param cellCount the number of cells we should be rendering * @param row the row to pad out */ protected void padOutRow(int cellCount, AccountingLineTableRow row) { while ((cellCount - row.getChildCellCount()) > 0) { row.addCell(new AccountingLineTableCell()); } } /** * While holding an action block, this is not an action block * @see org.kuali.kfs.sys.document.web.RenderableElement#isActionBlock() */ public boolean isActionBlock() { return false; } /** * This is never empty * @see org.kuali.kfs.sys.document.web.RenderableElement#isEmpty() */ public boolean isEmpty() { return false; } /** * This is not hidden * @see org.kuali.kfs.sys.document.web.RenderableElement#isHidden() */ public boolean isHidden() { return false; } /** * Renders all the rows * @see org.kuali.kfs.sys.document.web.RenderableElement#renderElement(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag, org.kuali.kfs.sys.document.web.AccountingLineRenderingContext) */ public void renderElement(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException { for (AccountingLineTableRow row : rows) { row.renderElement(pageContext, parentTag, renderingContext); } } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getAccountingLinePropertyPath() */ public String getAccountingLinePropertyPath() { return accountingLineProperty; } /** * Appends all fields from rows that this contains * @see org.kuali.kfs.sys.document.web.RenderableElement#appendFieldNames(java.util.List) */ public void appendFields(List<Field> fields) { for (AccountingLineTableRow row : rows) { row.appendFields(fields); } } /** * Returns all of the field names within the accounting line to render * @return a List of field names with the accounting line property prefixed * * KRAD Conversion: Customization of getting the fields - No use of data dictionary */ public List<Field> getFieldsForAccountingLine() { if (fields == null) { fields = new ArrayList<Field>(); appendFields(fields); } return fields; } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getFieldNamesForAccountingLine() * * KRAD Conversion: Customization of the fields - No use of data dictionary */ public List<String> getFieldNamesForAccountingLine() { if (fieldNames == null) { fieldNames = new ArrayList<String>(); for (Field field : getFieldsForAccountingLine()) { fieldNames.add(accountingLineProperty+"."+field.getPropertyName()); } } return fieldNames; } /** * @see org.kuali.kfs.sys.document.web.RenderableElement#populateWithTabIndexIfRequested(int[], int) */ public void populateWithTabIndexIfRequested( int reallyHighIndex) { for (AccountingLineTableRow row : rows) { row.populateWithTabIndexIfRequested(reallyHighIndex); } } /** * Returns the unconvertedValues for the current form * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getUnconvertedValues() */ public Map getUnconvertedValues() { return form.getUnconvertedValues(); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#populateValuesForFields() * * KRAD Conversion: Customization of populating the field values - Use of data dictionary */ public void populateValuesForFields() { FieldUtils.populateFieldsFromBusinessObject(getFieldsForAccountingLine(), accountingLine); org.kuali.rice.krad.datadictionary.BusinessObjectEntry boDDEntry = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(getAccountingLine().getClass().getName()); for (Field field : getFieldsForAccountingLine()) { setUnconvertedValueIfNecessary(field); setShouldShowSecure(field, boDDEntry); } } /** * Sees if the given field has an unconverted value living in the unconverted value map and if so, * changes the value to that * @param field the field to possibly set an unconverted value on * * KRAD Conversion: Customization of the fields - No use of data dictionary */ protected void setUnconvertedValueIfNecessary(Field field) { String propertyName = accountingLineProperty+"."+field.getPropertyName(); if (getUnconvertedValues().get(propertyName) != null) { field.setPropertyValue((String)getUnconvertedValues().get(propertyName)); } } /** * Sets the masked value equal to the value if the current user can see the unmasked value for a secure field * @param field the field to possible change the value for * @param boDDEntry the data dictionary entry for the accounting line * * KRAD Conversion: Customization of the fields - No use of data dictionary */ protected void setShouldShowSecure(Field field, org.kuali.rice.krad.datadictionary.BusinessObjectEntry boDDEntry) { // TODO: FIX // from Warren: k... org.kuali.rice.kns.service.BusinessObjectAuthorizationService.getMaintenanceDocumentRestrictions(MaintenanceDocument, Person) has the determination of what restrictions there should be // org.kuali.rice.kns.util.FieldUtils.applyAuthorization(Field, String, MaintenanceDocumentRestrictions) applies those restrictions } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getAccountingDocument() */ public AccountingDocument getAccountingDocument() { return form.getFinancialDocument(); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#fieldsCanRenderDynamicLabels() */ public boolean fieldsCanRenderDynamicLabels() { return !form.isHideDetails(); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#fieldsShouldRenderHelp() */ public boolean fieldsShouldRenderHelp() { return form.isFieldLevelHelpEnabled(); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getTabState(java.lang.String) */ public String getTabState(String tabKey) { return form.getTabState(tabKey); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#incrementTabIndex() */ public void incrementTabIndex() { form.incrementTabIndex(); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getGroupLabel() */ public String getGroupLabel() { return this.groupLabel; } /** * Gets the errors attribute. * @return Returns the errors. */ public List getErrors() { return errors; } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getForm() */ public KualiAccountingDocumentFormBase getForm() { return form; } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getAccountingLineContainingObjectPropertyName() */ public String getAccountingLineContainingObjectPropertyName() { return StringUtils.substringBeforeLast(this.getAccountingLinePropertyPath(), String.valueOf(PropertyUtils.NESTED_DELIM)); } /** * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#isFieldModifyable(org.kuali.kfs.sys.document.web.AccountingLineViewField) */ public boolean isFieldModifyable(String fieldName) { Person currentUser = GlobalVariables.getUserSession().getPerson(); final boolean pageIsEditable = getForm().getDocumentActions().containsKey(KRADConstants.KUALI_ACTION_CAN_EDIT); return accountingLineAuthorizer.hasEditPermissionOnField(getAccountingDocument(), accountingLine, this.accountingLineProperty, fieldName, editableLine, pageIsEditable, currentUser); } /** * Gets the editableLine attribute. * @return Returns the editableLine. */ public boolean isEditableLine() { return editableLine; } /** * Sets the editableLine attribute value. * * @param editableLine The editableLine to set. */ public void setEditableLine(boolean editableLine) { this.editableLine = editableLine; } /** * Determines whether the line within this rendering context can be deleted. * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#allowDelete() */ public boolean allowDelete() { return deletable; } /** * Makes the line within this accounting line context deletable */ public void makeDeletable() { deletable = true; } }