1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.sys.document.web;
17
18 import java.text.MessageFormat;
19 import java.util.List;
20 import java.util.Map;
21
22 import javax.servlet.jsp.JspException;
23 import javax.servlet.jsp.PageContext;
24 import javax.servlet.jsp.tagext.Tag;
25
26 import org.apache.commons.collections.BidiMap;
27 import org.apache.commons.collections.bidimap.DualHashBidiMap;
28 import org.apache.commons.lang.StringUtils;
29 import org.kuali.ole.coa.service.AccountService;
30 import org.kuali.ole.sys.OLEConstants;
31 import org.kuali.ole.sys.OLEKeyConstants;
32 import org.kuali.ole.sys.businessobject.AccountingLine;
33 import org.kuali.ole.sys.context.SpringContext;
34 import org.kuali.ole.sys.document.AccountingDocument;
35 import org.kuali.ole.sys.document.datadictionary.AccountingLineViewFieldDefinition;
36 import org.kuali.ole.sys.document.service.AccountingLineFieldRenderingTransformation;
37 import org.kuali.ole.sys.document.service.AccountingLineRenderingService;
38 import org.kuali.ole.sys.document.web.renderers.DynamicNameLabelRenderer;
39 import org.kuali.ole.sys.document.web.renderers.FieldRenderer;
40 import org.kuali.rice.core.api.config.property.ConfigurationService;
41 import org.kuali.rice.kns.lookup.LookupUtils;
42 import org.kuali.rice.kns.util.FieldUtils;
43 import org.kuali.rice.kns.web.ui.Field;
44 import org.kuali.rice.krad.bo.PersistableBusinessObject;
45 import org.kuali.rice.krad.service.PersistenceStructureService;
46 import org.kuali.rice.krad.util.ObjectUtils;
47
48
49
50
51 public class AccountingLineViewField extends FieldTableJoiningWithHeader implements HeaderLabelPopulating, ReadOnlyable {
52 public static final String ACCOUNTING_LINE_NAME_PREFIX_PLACE_HOLDER = "${accountingLineName}";
53
54 private Field field;
55 private AccountingLineViewFieldDefinition definition;
56 private int arbitrarilyHighIndex;
57 private List<AccountingLineViewOverrideField> overrideFields;
58 private PersistenceStructureService persistenceStructureService;
59
60
61
62
63
64
65 public AccountingLineViewFieldDefinition getDefinition() {
66 return definition;
67 }
68
69
70
71
72
73
74 public void setDefinition(AccountingLineViewFieldDefinition definition) {
75 this.definition = definition;
76 }
77
78
79
80
81
82
83 private boolean shouldUseShortLabel() {
84 return definition.shouldUseShortLabel();
85 }
86
87
88
89
90
91
92
93
94 public Field getField() {
95 return field;
96 }
97
98
99
100
101
102
103
104
105 public void setField(Field field) {
106 this.field = field;
107 }
108
109
110
111
112
113
114 public List<AccountingLineViewOverrideField> getOverrideFields() {
115 return overrideFields;
116 }
117
118
119
120
121
122
123 public void setOverrideFields(List<AccountingLineViewOverrideField> overrideFields) {
124 this.overrideFields = overrideFields;
125 }
126
127
128
129
130
131
132 public boolean isHidden() {
133 return (field.getFieldType().equals(Field.HIDDEN) || definition.isHidden());
134 }
135
136
137
138
139
140
141
142 public boolean isReadOnly() {
143 return field.isReadOnly() || isHidden();
144 }
145
146
147
148
149 public String getName() {
150 return field.getPropertyName();
151 }
152
153
154
155
156 public void readOnlyize() {
157 if (!isHidden()) {
158 this.field.setReadOnly(true);
159 }
160 }
161
162
163
164
165 public String getHeaderLabelProperty() {
166 return this.field.getPropertyName();
167 }
168
169
170
171
172
173 public void renderElement(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
174 renderField(pageContext, parentTag, renderingContext);
175
176 if (getOverrideFields() != null && getOverrideFields().size() > 0) {
177 renderOverrideFields(pageContext, parentTag, renderingContext);
178 }
179 if (shouldRenderDynamicFeldLabel() && renderingContext.fieldsCanRenderDynamicLabels()) {
180 renderDynamicNameLabel(pageContext, parentTag, renderingContext);
181 }
182 }
183
184
185
186
187
188
189
190
191
192 protected void renderField(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
193 AccountingLine accountingLine = renderingContext.getAccountingLine();
194 String accountingLineProperty = renderingContext.getAccountingLinePropertyPath();
195 List<String> fieldNames = renderingContext.getFieldNamesForAccountingLine();
196 List errors = renderingContext.getErrors();
197
198 this.getField().setPropertyPrefix(accountingLineProperty);
199 boolean chartSetByAccount = getName().equals(OLEConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME) && !SpringContext.getBean(AccountService.class).accountsCanCrossCharts();
200
201 if (!renderingContext.isFieldModifyable(this.getName()) || chartSetByAccount) {
202 this.getField().setReadOnly(true);
203 }
204
205 FieldRenderer renderer = SpringContext.getBean(AccountingLineRenderingService.class).getFieldRendererForField(getField(), accountingLine);
206 if (renderer != null) {
207 prepareFieldRenderer(renderer, getField(), renderingContext.getAccountingDocument(), accountingLine, accountingLineProperty, fieldNames);
208 if (fieldInError(errors)) {
209 renderer.setShowError(true);
210 }
211
212 if (!isHidden()) {
213 renderer.openNoWrapSpan(pageContext, parentTag);
214 }
215
216
217 if (!this.isReadOnly()) {
218 String accessibleTitle = getField().getFieldLabel();
219
220 if (renderingContext.isNewLine()) {
221 String format = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.LABEL_NEW_ACCOUNTING_LINE_FIELD);
222 accessibleTitle = MessageFormat.format(format, accessibleTitle, renderingContext.getGroupLabel());
223 }
224 else {
225 Integer lineNumber = renderingContext.getCurrentLineCount() + 1;
226 String format = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.LABEL_ACCOUNTING_LINE_FIELD);
227 accessibleTitle = MessageFormat.format(format, accessibleTitle, renderingContext.getGroupLabel(), lineNumber);
228 }
229
230 renderer.setAccessibleTitle(accessibleTitle);
231 }
232
233 renderer.render(pageContext, parentTag);
234 if (!isHidden()) {
235 renderer.closeNoWrapSpan(pageContext, parentTag);
236 }
237 renderer.clear();
238 }
239 }
240
241
242
243
244
245
246
247
248
249
250 protected void populateFieldForLookupAndInquiry(AccountingDocument accountingDocument, AccountingLine accountingLine, List<String> fieldNames, String accountingLinePrefix) {
251 if (!isHidden()) {
252 LookupUtils.setFieldQuickfinder(accountingLine, getField().getPropertyName(), getField(), fieldNames);
253
254
255 String overrideLookupParameters = definition.getOverrideLookupParameters();
256 if (StringUtils.isNotBlank(overrideLookupParameters)) {
257 String lookupParameters = getField().getLookupParameters();
258
259 Map<String, String> lookupParametersMap = this.getActualParametersMap(lookupParameters, overrideLookupParameters, accountingLinePrefix);
260
261 getField().setLookupParameters(lookupParametersMap);
262
263
264
265
266 if (!lookupParametersMap.isEmpty()) {
267 if (getDefinition().getOverrideLookupClass() != null) {
268 getField().setQuickFinderClassNameImpl(getDefinition().getOverrideLookupClass().getName());
269 }
270 }
271 }
272
273
274 String overrideFieldConversions = definition.getOverrideFieldConversions();
275 if (StringUtils.isNotBlank(overrideFieldConversions)) {
276 String fieldConversions = getField().getFieldConversions();
277
278 Map<String, String> fieldConversionsMap = this.getActualParametersMap(fieldConversions, overrideFieldConversions, accountingLinePrefix);
279
280 getField().setFieldConversions(fieldConversionsMap);
281 }
282
283 if (isRenderingInquiry(accountingDocument, accountingLine)) {
284 FieldUtils.setInquiryURL(getField(), accountingLine, getField().getPropertyName());
285 }
286 }
287 }
288
289
290
291
292
293
294 protected PersistenceStructureService getPersistenceStructureService() {
295 if (persistenceStructureService == null) {
296 persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
297 }
298 return persistenceStructureService;
299 }
300
301
302
303
304
305
306
307
308
309
310
311 protected void prepareFieldRenderer(FieldRenderer fieldRenderer, Field field, AccountingDocument document, AccountingLine accountingLine, String accountingLineProperty, List<String> fieldNames) {
312 fieldRenderer.setField(field);
313
314 getField().setPropertyPrefix(accountingLineProperty);
315 populateFieldForLookupAndInquiry(document, accountingLine, fieldNames, getField().getPropertyPrefix());
316
317 if (definition.getDynamicNameLabelGenerator() != null) {
318 fieldRenderer.overrideOnBlur(definition.getDynamicNameLabelGenerator().getDynamicNameLabelOnBlur(accountingLine, accountingLineProperty));
319 }
320 else if (!StringUtils.isBlank(definition.getDynamicLabelProperty())) {
321 fieldRenderer.setDynamicNameLabel(accountingLineProperty + "." + definition.getDynamicLabelProperty());
322 }
323
324 fieldRenderer.setArbitrarilyHighTabIndex(arbitrarilyHighIndex);
325 }
326
327
328
329
330
331
332 protected boolean shouldRenderDynamicFeldLabel() {
333 return (!getField().getFieldType().equals(Field.HIDDEN) && ((!StringUtils.isBlank(getField().getWebOnBlurHandler()) && !StringUtils.isBlank(definition.getDynamicLabelProperty())) || definition.getDynamicNameLabelGenerator() != null));
334 }
335
336
337
338
339
340 @Override
341 public void performFieldTransformations(List<AccountingLineFieldRenderingTransformation> fieldTransformations, AccountingLine accountingLine, Map unconvertedValues) {
342 for (AccountingLineFieldRenderingTransformation fieldTransformation : fieldTransformations) {
343 fieldTransformation.transformField(accountingLine, getField(), getDefinition(), unconvertedValues);
344 if (getOverrideFields() != null && getOverrideFields().size() > 0) {
345 transformOverrideFields(fieldTransformation, accountingLine, unconvertedValues);
346 }
347 }
348 }
349
350
351
352
353
354
355
356
357
358 protected void transformOverrideFields(AccountingLineFieldRenderingTransformation fieldTransformation, AccountingLine accountingLine, Map unconvertedValues) {
359 for (AccountingLineViewOverrideField overrideField : getOverrideFields()) {
360 overrideField.transformField(fieldTransformation, accountingLine, unconvertedValues);
361 }
362 }
363
364
365
366
367
368
369
370
371
372
373 public void renderOverrideFields(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
374 for (AccountingLineViewOverrideField overrideField : getOverrideFields()) {
375 overrideField.setAccountingLineProperty(renderingContext.getAccountingLinePropertyPath());
376 overrideField.renderElement(pageContext, parentTag, renderingContext);
377 }
378 }
379
380
381
382
383
384
385
386
387
388 protected void renderDynamicNameLabel(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
389 AccountingLine accountingLine = renderingContext.getAccountingLine();
390 String accountingLinePropertyPath = renderingContext.getAccountingLinePropertyPath();
391
392 DynamicNameLabelRenderer renderer = new DynamicNameLabelRenderer();
393 if (definition.getDynamicNameLabelGenerator() != null) {
394 renderer.setFieldName(definition.getDynamicNameLabelGenerator().getDynamicNameLabelFieldName(accountingLine, accountingLinePropertyPath));
395 renderer.setFieldValue(definition.getDynamicNameLabelGenerator().getDynamicNameLabelValue(accountingLine, accountingLinePropertyPath));
396 }
397 else {
398 if (!StringUtils.isBlank(getField().getPropertyValue())) {
399 if (getField().isSecure()) {
400 renderer.setFieldValue(getField().getDisplayMask().maskValue(getField().getPropertyValue()));
401 }
402 else {
403 renderer.setFieldValue(getDynamicNameLabelDisplayedValue(accountingLine));
404 }
405 }
406 renderer.setFieldName(accountingLinePropertyPath + "." + definition.getDynamicLabelProperty());
407 }
408 renderer.render(pageContext, parentTag);
409 renderer.clear();
410 }
411
412
413
414
415
416
417
418 protected String getDynamicNameLabelDisplayedValue(AccountingLine accountingLine) {
419 String dynamicLabelProperty = definition.getDynamicLabelProperty();
420 Object value = accountingLine;
421 while (!ObjectUtils.isNull(value) && dynamicLabelProperty.indexOf('.') > -1) {
422 String currentProperty = StringUtils.substringBefore(dynamicLabelProperty, ".");
423 dynamicLabelProperty = StringUtils.substringAfter(dynamicLabelProperty, ".");
424 if (value instanceof PersistableBusinessObject) {
425 ((PersistableBusinessObject) value).refreshReferenceObject(currentProperty);
426 }
427 value = ObjectUtils.getPropertyValue(value, currentProperty);
428 }
429 if (!ObjectUtils.isNull(value)) {
430 value = ObjectUtils.getPropertyValue(value, dynamicLabelProperty);
431 if (value != null)
432 return value.toString();
433 }
434 return null;
435 }
436
437
438
439
440 public HeaderLabel createHeaderLabel() {
441 return new FieldHeaderLabel(this);
442 }
443
444
445
446
447
448
449
450 protected void updateTableCellWithColSpanOverride(AccountingLineTableCell cell) {
451 if (definition.getOverrideColSpan() > 1 && cell.getColSpan() == 1) {
452 cell.setColSpan(definition.getOverrideColSpan());
453 }
454 }
455
456
457
458
459
460
461 @Override
462 protected AccountingLineTableCell createHeaderLabelTableCell() {
463 AccountingLineTableCell cell = super.createHeaderLabelTableCell();
464 updateTableCellWithColSpanOverride(cell);
465 return cell;
466 }
467
468
469
470
471
472
473 @Override
474 protected AccountingLineTableCell createTableCell() {
475 AccountingLineTableCell cell = super.createTableCell();
476 updateTableCellWithColSpanOverride(cell);
477 return cell;
478 }
479
480
481
482
483 public int getColSpanOverride() {
484 return definition.getOverrideColSpan();
485 }
486
487
488
489
490
491 public void populateHeaderLabel(HeaderLabel headerLabel, AccountingLineRenderingContext renderingContext) {
492 FieldHeaderLabel label = (FieldHeaderLabel) headerLabel;
493 label.setLabel(getField().getFieldLabel());
494 label.setLabeledFieldEmptyOrHidden(isEmpty() || isHidden());
495 label.setReadOnly(getField().isReadOnly());
496 label.setRequired(getField().isFieldRequired());
497 if (renderingContext.fieldsShouldRenderHelp()) {
498 label.setFullClassNameForHelp(renderingContext.getAccountingLine().getClass().getName());
499 label.setAttributeEntryForHelp(getField().getPropertyName());
500 }
501 }
502
503
504
505
506
507
508
509
510 public void appendFields(List<Field> fields) {
511 fields.add(getField());
512 if (getOverrideFields() != null && getOverrideFields().size() > 0) {
513 for (AccountingLineViewOverrideField field : getOverrideFields()) {
514 field.appendFields(fields);
515 }
516 }
517 }
518
519
520
521
522 public void populateWithTabIndexIfRequested(int reallyHighIndex) {
523 this.arbitrarilyHighIndex = reallyHighIndex;
524 }
525
526
527
528
529
530
531
532
533
534 protected boolean fieldInError(List errors) {
535 if (errors != null) {
536 String fieldName = getField().getPropertyName();
537 if (!StringUtils.isBlank(getField().getPropertyPrefix())) {
538 fieldName = getField().getPropertyPrefix() + "." + fieldName;
539 }
540 for (Object errorKeyAsObject : errors) {
541 final String errorKey = (String) errorKeyAsObject;
542 if (fieldName.equals(errorKey)) {
543 return true;
544 }
545 }
546 }
547 return false;
548 }
549
550
551
552
553 public void setEditable() {
554 if (!isHidden()) {
555 this.field.setReadOnly(false);
556 }
557 }
558
559
560
561
562
563
564
565
566 protected boolean isRenderingInquiry(AccountingDocument document, AccountingLine line) {
567 return isReadOnly();
568 }
569
570
571
572
573
574
575
576
577
578 private Map<String, String> getActualParametersMap(String parameters, String overrideParameters, String accountingLinePrefix) {
579 BidiMap parametersMap = this.buildBidirecionalMapFromParameters(parameters, accountingLinePrefix);
580 BidiMap overrideParametersMap = this.buildBidirecionalMapFromParameters(overrideParameters, accountingLinePrefix);
581 parametersMap.putAll(overrideParametersMap);
582
583 return parametersMap;
584 }
585
586
587
588
589
590
591
592
593 private BidiMap buildBidirecionalMapFromParameters(String parameters, String accountingLinePrefix) {
594 BidiMap parameterMap = new DualHashBidiMap();
595
596
597 if (StringUtils.isBlank(parameters)) {
598 return parameterMap;
599 }
600
601 String[] parameterArray = StringUtils.split(parameters, OLEConstants.FIELD_CONVERSIONS_SEPERATOR);
602
603 for (String parameter : parameterArray) {
604 String[] entrySet = StringUtils.split(parameter, OLEConstants.FIELD_CONVERSION_PAIR_SEPERATOR);
605
606 if (entrySet != null) {
607 String parameterKey = escapeAccountingLineName(entrySet[0], accountingLinePrefix);
608 String parameterValue = escapeAccountingLineName(entrySet[1], accountingLinePrefix);
609
610 parameterMap.put(parameterKey, parameterValue);
611 }
612 }
613
614 return parameterMap;
615 }
616
617
618
619
620
621
622
623
624 protected String escapeAccountingLineName(String propertyName, String accountingLinePrefix) {
625 return StringUtils.replace(propertyName, ACCOUNTING_LINE_NAME_PREFIX_PLACE_HOLDER, accountingLinePrefix + ".");
626 }
627 }