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