001 /* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.kfs.sys.document.web; 017 018 import java.util.ArrayList; 019 import java.util.List; 020 import java.util.Map; 021 022 import javax.servlet.jsp.JspException; 023 import javax.servlet.jsp.PageContext; 024 import javax.servlet.jsp.tagext.Tag; 025 026 import org.apache.commons.beanutils.PropertyUtils; 027 import org.apache.commons.lang.StringUtils; 028 import org.kuali.kfs.sys.businessobject.AccountingLine; 029 import org.kuali.kfs.sys.context.SpringContext; 030 import org.kuali.kfs.sys.document.AccountingDocument; 031 import org.kuali.kfs.sys.document.authorization.AccountingLineAuthorizer; 032 import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase; 033 import org.kuali.rice.kim.bo.Person; 034 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; 035 import org.kuali.rice.kns.service.DataDictionaryService; 036 import org.kuali.rice.kns.util.FieldUtils; 037 import org.kuali.rice.kns.util.GlobalVariables; 038 import org.kuali.rice.kns.util.KNSConstants; 039 import org.kuali.rice.kns.web.ui.Field; 040 041 /** 042 * A container which holds a single accounting line and the elements which will render it 043 */ 044 public class RenderableAccountingLineContainer implements RenderableElement, AccountingLineRenderingContext { 045 private List<AccountingLineTableRow> rows; 046 private List<AccountingLineViewAction> actions; 047 private AccountingLine accountingLine; 048 private String accountingLineProperty; 049 private List<Field> fields; 050 private List<String> fieldNames; 051 private KualiAccountingDocumentFormBase form; 052 private String groupLabel; 053 private Integer lineCount; 054 private List errors; 055 private AccountingLineAuthorizer accountingLineAuthorizer; 056 private boolean editableLine; 057 private boolean deletable = false; 058 059 /** 060 * Constructs a RenderableAccountingLineContainer 061 * @param form the form being rendered 062 * @param accountingLine the accounting line this container will render 063 * @param accountingLineProperty the property to that accounting line 064 * @param rows the rows to render 065 * @param newLine whether this is a new accounting line or not 066 * @param groupLabel the label for the group this accounting line is being rendered part of 067 * @param errors the set of errors currently on the document 068 * @param accountingLineAuthorizer the accounting line authorizer for the document 069 * @param editableLine whether this line, as a whole _line_ is editable 070 */ 071 public RenderableAccountingLineContainer(KualiAccountingDocumentFormBase form, AccountingLine accountingLine, String accountingLineProperty, List<AccountingLineTableRow> rows, Integer lineCount, String groupLabel, List errors, AccountingLineAuthorizer accountingLineAuthorizer, boolean editableLine) { 072 this.form = form; 073 this.accountingLine = accountingLine; 074 this.accountingLineProperty = accountingLineProperty; 075 this.rows = rows; 076 this.lineCount = lineCount; 077 this.groupLabel = groupLabel; 078 this.errors = errors; 079 this.accountingLineAuthorizer = accountingLineAuthorizer; 080 this.editableLine = editableLine; 081 } 082 083 /** 084 * Gets the accountingLine attribute. 085 * @return Returns the accountingLine. 086 */ 087 public AccountingLine getAccountingLine() { 088 return accountingLine; 089 } 090 091 /** 092 * Gets the accountingLineProperty attribute. 093 * @return Returns the accountingLineProperty. 094 */ 095 public String getAccountingLineProperty() { 096 return accountingLineProperty; 097 } 098 099 /** 100 * Gets the actions attribute. 101 * @return Returns the actions. 102 */ 103 public List<AccountingLineViewAction> getActionsForLine() { 104 if (actions == null) { 105 actions = accountingLineAuthorizer.getActions(form.getFinancialDocument(), this, accountingLineProperty, lineCount, GlobalVariables.getUserSession().getPerson(), groupLabel); 106 } 107 return actions; 108 } 109 110 /** 111 * Gets the newLine attribute. 112 * @return Returns the newLine. 113 */ 114 public boolean isNewLine() { 115 return lineCount == null; 116 } 117 118 /** 119 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getCurrentLineCount() 120 */ 121 public Integer getCurrentLineCount() { 122 return lineCount; 123 } 124 125 /** 126 * Gets the rows attribute. 127 * @return Returns the rows. 128 */ 129 public List<AccountingLineTableRow> getRows() { 130 return rows; 131 } 132 133 /** 134 * @return the number of cells this accounting line container will render 135 */ 136 public int getCellCount() { 137 int maxCells = 0; 138 for (AccountingLineTableRow row : rows) { 139 final int maxRowCellCount = row.getChildCellCount(); 140 if (maxCells < maxRowCellCount) { 141 maxCells = maxRowCellCount; 142 } 143 } 144 return maxCells; 145 } 146 147 /** 148 * Adds empty cells to a table row 149 * @param cellCount the number of cells we should be rendering 150 * @param row the row to pad out 151 */ 152 protected void padOutRow(int cellCount, AccountingLineTableRow row) { 153 while ((cellCount - row.getChildCellCount()) > 0) { 154 row.addCell(new AccountingLineTableCell()); 155 } 156 } 157 158 /** 159 * While holding an action block, this is not an action block 160 * @see org.kuali.kfs.sys.document.web.RenderableElement#isActionBlock() 161 */ 162 public boolean isActionBlock() { 163 return false; 164 } 165 166 /** 167 * This is never empty 168 * @see org.kuali.kfs.sys.document.web.RenderableElement#isEmpty() 169 */ 170 public boolean isEmpty() { 171 return false; 172 } 173 174 /** 175 * This is not hidden 176 * @see org.kuali.kfs.sys.document.web.RenderableElement#isHidden() 177 */ 178 public boolean isHidden() { 179 return false; 180 } 181 182 /** 183 * Renders all the rows 184 * @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) 185 */ 186 public void renderElement(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException { 187 for (AccountingLineTableRow row : rows) { 188 row.renderElement(pageContext, parentTag, renderingContext); 189 } 190 } 191 192 /** 193 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getAccountingLinePropertyPath() 194 */ 195 public String getAccountingLinePropertyPath() { 196 return accountingLineProperty; 197 } 198 199 /** 200 * Appends all fields from rows that this contains 201 * @see org.kuali.kfs.sys.document.web.RenderableElement#appendFieldNames(java.util.List) 202 */ 203 public void appendFields(List<Field> fields) { 204 for (AccountingLineTableRow row : rows) { 205 row.appendFields(fields); 206 } 207 } 208 209 /** 210 * Returns all of the field names within the accounting line to render 211 * @return a List of field names with the accounting line property prefixed 212 */ 213 public List<Field> getFieldsForAccountingLine() { 214 if (fields == null) { 215 fields = new ArrayList<Field>(); 216 appendFields(fields); 217 } 218 return fields; 219 } 220 221 /** 222 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getFieldNamesForAccountingLine() 223 */ 224 public List<String> getFieldNamesForAccountingLine() { 225 if (fieldNames == null) { 226 fieldNames = new ArrayList<String>(); 227 for (Field field : getFieldsForAccountingLine()) { 228 fieldNames.add(accountingLineProperty+"."+field.getPropertyName()); 229 } 230 } 231 return fieldNames; 232 } 233 234 /** 235 * @see org.kuali.kfs.sys.document.web.RenderableElement#populateWithTabIndexIfRequested(int[], int) 236 */ 237 public void populateWithTabIndexIfRequested( int reallyHighIndex) { 238 for (AccountingLineTableRow row : rows) { 239 row.populateWithTabIndexIfRequested(reallyHighIndex); 240 } 241 } 242 243 /** 244 * Returns the unconvertedValues for the current form 245 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getUnconvertedValues() 246 */ 247 public Map getUnconvertedValues() { 248 return form.getUnconvertedValues(); 249 } 250 251 /** 252 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#populateValuesForFields() 253 */ 254 public void populateValuesForFields() { 255 FieldUtils.populateFieldsFromBusinessObject(getFieldsForAccountingLine(), accountingLine); 256 257 BusinessObjectEntry boDDEntry = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(getAccountingLine().getClass().getName()); 258 259 for (Field field : getFieldsForAccountingLine()) { 260 setUnconvertedValueIfNecessary(field); 261 setShouldShowSecure(field, boDDEntry); 262 } 263 } 264 265 /** 266 * Sees if the given field has an unconverted value living in the unconverted value map and if so, 267 * changes the value to that 268 * @param field the field to possibly set an unconverted value on 269 */ 270 protected void setUnconvertedValueIfNecessary(Field field) { 271 String propertyName = accountingLineProperty+"."+field.getPropertyName(); 272 if (getUnconvertedValues().get(propertyName) != null) { 273 field.setPropertyValue((String)getUnconvertedValues().get(propertyName)); 274 } 275 } 276 277 /** 278 * Sets the masked value equal to the value if the current user can see the unmasked value for a secure field 279 * @param field the field to possible change the value for 280 * @param boDDEntry the data dictionary entry for the accounting line 281 */ 282 protected void setShouldShowSecure(Field field, BusinessObjectEntry boDDEntry) { 283 // TODO: FIX 284 285 // from Warren: k... org.kuali.rice.kns.service.BusinessObjectAuthorizationService.getMaintenanceDocumentRestrictions(MaintenanceDocument, Person) has the determination of what restrictions there should be 286 // org.kuali.rice.kns.util.FieldUtils.applyAuthorization(Field, String, MaintenanceDocumentRestrictions) applies those restrictions 287 } 288 /** 289 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getAccountingDocument() 290 */ 291 public AccountingDocument getAccountingDocument() { 292 return form.getFinancialDocument(); 293 } 294 295 /** 296 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#fieldsCanRenderDynamicLabels() 297 */ 298 public boolean fieldsCanRenderDynamicLabels() { 299 return !form.isHideDetails(); 300 } 301 /** 302 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#fieldsShouldRenderHelp() 303 */ 304 public boolean fieldsShouldRenderHelp() { 305 return form.isFieldLevelHelpEnabled(); 306 } 307 /** 308 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getTabState(java.lang.String) 309 */ 310 public String getTabState(String tabKey) { 311 return form.getTabState(tabKey); 312 } 313 /** 314 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#incrementTabIndex() 315 */ 316 public void incrementTabIndex() { 317 form.incrementTabIndex(); 318 } 319 320 /** 321 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getGroupLabel() 322 */ 323 public String getGroupLabel() { 324 return this.groupLabel; 325 } 326 327 /** 328 * Gets the errors attribute. 329 * @return Returns the errors. 330 */ 331 public List getErrors() { 332 return errors; 333 } 334 335 /** 336 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getForm() 337 */ 338 public KualiAccountingDocumentFormBase getForm() { 339 return form; 340 } 341 342 /** 343 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#getAccountingLineContainingObjectPropertyName() 344 */ 345 public String getAccountingLineContainingObjectPropertyName() { 346 return StringUtils.substringBeforeLast(this.getAccountingLinePropertyPath(), String.valueOf(PropertyUtils.NESTED_DELIM)); 347 } 348 349 /** 350 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#isFieldModifyable(org.kuali.kfs.sys.document.web.AccountingLineViewField) 351 */ 352 public boolean isFieldModifyable(String fieldName) { 353 Person currentUser = GlobalVariables.getUserSession().getPerson(); 354 final boolean pageIsEditable = getForm().getDocumentActions().containsKey(KNSConstants.KUALI_ACTION_CAN_EDIT); 355 return accountingLineAuthorizer.hasEditPermissionOnField(getAccountingDocument(), accountingLine, this.accountingLineProperty, fieldName, editableLine, pageIsEditable, currentUser); 356 } 357 358 /** 359 * Gets the editableLine attribute. 360 * @return Returns the editableLine. 361 */ 362 public boolean isEditableLine() { 363 return editableLine; 364 } 365 366 /** 367 * Sets the editableLine attribute value. 368 * 369 * @param editableLine The editableLine to set. 370 */ 371 public void setEditableLine(boolean editableLine) { 372 this.editableLine = editableLine; 373 } 374 375 /** 376 * Determines whether the line within this rendering context can be deleted. 377 * @see org.kuali.kfs.sys.document.web.AccountingLineRenderingContext#allowDelete() 378 */ 379 public boolean allowDelete() { 380 return deletable; 381 } 382 383 /** 384 * Makes the line within this accounting line context deletable 385 */ 386 public void makeDeletable() { 387 deletable = true; 388 } 389 } 390