1 /**
2 * Copyright 2005-2012 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.kuali.rice.krad.uif.field;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.config.property.ConfigurationService;
20 import org.kuali.rice.krad.service.KRADServiceLocator;
21 import org.kuali.rice.krad.uif.container.ContainerBase;
22 import org.kuali.rice.krad.uif.container.PageGroup;
23 import org.kuali.rice.krad.uif.view.View;
24 import org.kuali.rice.krad.uif.component.Component;
25 import org.kuali.rice.krad.util.ErrorMessage;
26 import org.kuali.rice.krad.util.GlobalVariables;
27 import org.kuali.rice.krad.util.MessageMap;
28 import org.springframework.util.AutoPopulatingList;
29
30 import java.text.MessageFormat;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.LinkedHashSet;
34 import java.util.List;
35
36 /**
37 * Field that displays error, warning, and info messages for the keys that are
38 * matched. By default, an ErrorsField will match on id and bindingPath (if this
39 * ErrorsField is for an InputField), but can be set to match on
40 * additionalKeys and nested components keys (of the its parentComponent).
41 *
42 * In addition, there are a variety of options which can be toggled to effect
43 * the display of these messages during both client and server side validation
44 * display. See documentation on each get method for more details on the effect
45 * of each option.
46 *
47 * @author Kuali Rice Team (rice.collab@kuali.org)
48 */
49 public class ErrorsField extends FieldBase {
50 private static final long serialVersionUID = 780940788435330077L;
51
52 private List<String> additionalKeysToMatch;
53
54 private boolean fireGrowlsForMessages;
55 private String growlScript = "";
56
57 // Title variables
58 private String errorTitle;
59 private String warningTitle;
60 private String infoTitle;
61
62 private boolean displayErrorTitle;
63 private boolean displayWarningTitle;
64 private boolean displayInfoTitle;
65
66 // Field variables
67 private boolean highlightOnError;
68 private boolean displayFieldErrorIcon;
69
70 // Message construction variables
71 private boolean displayFieldLabelWithMessages;
72 private boolean combineMessages;
73
74 // Message display flags
75 private boolean displayNestedMessages;
76 private boolean allowMessageRepeat;
77
78 private boolean displayMessages;
79 private boolean displayErrorMessages;
80 private boolean displayInfoMessages;
81 private boolean displayWarningMessages;
82 private boolean displayCounts;
83 private boolean alternateContainer;
84
85 // Error messages
86 private List<String> errors;
87 private List<String> warnings;
88 private List<String> infos;
89
90 // Counts
91 private int errorCount;
92 private int warningCount;
93 private int infoCount;
94
95 // not used
96 private boolean displayLockMessages;
97
98 public ErrorsField() {
99 super();
100 alternateContainer = false;
101 }
102
103 /**
104 * PerformFinalize will generate the messages and counts used by the
105 * errorsField based on the keys that were matched from the MessageMap for
106 * this ErrorsField. It will also set up nestedComponents of its
107 * parentComponent correctly based on the flags that were chosen for this
108 * ErrorsField.
109 *
110 * @see org.kuali.rice.krad.uif.field.FieldBase#performFinalize(org.kuali.rice.krad.uif.view.View,
111 * java.lang.Object, org.kuali.rice.krad.uif.component.Component)
112 */
113 @Override
114 public void performFinalize(View view, Object model, Component parent) {
115 super.performFinalize(view, model, parent);
116
117 generateMessages(true, view, model, parent);
118 }
119
120 public void generateMessages(boolean reset, View view, Object model, Component parent) {
121 if (reset) {
122 errors = new ArrayList<String>();
123 warnings = new ArrayList<String>();
124 infos = new ArrayList<String>();
125 errorCount = 0;
126 warningCount = 0;
127 infoCount = 0;
128 }
129
130 List<String> masterKeyList = getKeys(parent);
131 MessageMap messageMap = GlobalVariables.getMessageMap();
132
133 // TODO: need constants
134 if (!displayFieldLabelWithMessages) {
135 this.addStyleClass("noLabels");
136 }
137 if (!highlightOnError) {
138 this.addStyleClass("noHighlight");
139 }
140 if (displayFieldErrorIcon) {
141 this.addStyleClass("addFieldIcon");
142 }
143
144 if (displayMessages) {
145 if (displayNestedMessages) {
146 this.addNestedKeys(masterKeyList, parent);
147 }
148
149 for (String key : masterKeyList) {
150 if (displayErrorMessages) {
151 errors.addAll(getMessages(view, key, messageMap.getErrorMessagesForProperty(key, true)));
152 }
153 if (displayWarningMessages) {
154 warnings.addAll(getMessages(view, key, messageMap.getWarningMessagesForProperty(key, true)));
155 }
156 if (displayInfoMessages) {
157 infos.addAll(getMessages(view, key, messageMap.getInfoMessagesForProperty(key, true)));
158 }
159 }
160 } else if (displayFieldErrorIcon) {
161 // Checks to see if any errors exist for this field, if they do set
162 // errorCount as positive
163 // so the jsp will call the corresponding js to show the icon
164 // messages do not need to be generated because they are not being shown
165 for (String key : masterKeyList) {
166 if (!messageMap.getErrorMessagesForProperty(key, true).isEmpty()) {
167 errorCount = 1;
168 break;
169 }
170 }
171 }
172
173 //Check for errors that are not matched on the page(only applies when parent is page)
174 if (parent instanceof PageGroup) {
175 if (errorCount < messageMap.getErrorCount()) {
176 List<String> diff = messageMap.getPropertiesWithErrors();
177 diff.removeAll(masterKeyList);
178 for (String key : diff) {
179 errors.addAll(getMessages(view, key, messageMap.getErrorMessagesForProperty(key, true)));
180 }
181
182 }
183 if (warningCount < messageMap.getWarningCount()) {
184 List<String> diff = messageMap.getPropertiesWithWarnings();
185 diff.removeAll(masterKeyList);
186 for (String key : diff) {
187 warnings.addAll(getMessages(view, key, messageMap.getWarningMessagesForProperty(key, true)));
188 }
189 }
190 if (infoCount < messageMap.getInfoCount()) {
191 List<String> diff = messageMap.getPropertiesWithInfo();
192 diff.removeAll(masterKeyList);
193 for (String key : diff) {
194 infos.addAll(getMessages(view, key, messageMap.getInfoMessagesForProperty(key, true)));
195 }
196 }
197
198 // TODO: need constant
199 this.setId("errorsFieldForPage");
200 }
201
202 if (fireGrowlsForMessages) {
203 //set up growl script
204 growlScript = getGrowlScript(view);
205 }
206
207 //Remove any textual duplicates that may have snuck in, by converting to set and back to list
208 errors = new ArrayList<String>(new LinkedHashSet<String>(errors));
209 warnings = new ArrayList<String>(new LinkedHashSet<String>(warnings));
210 infos = new ArrayList<String>(new LinkedHashSet<String>(infos));
211
212 errorCount = errors.size();
213 warningCount = warnings.size();
214 infoCount = infos.size();
215
216 // dont display anything if there are no messages
217 if (errorCount + warningCount + infoCount == 0 || !displayMessages) {
218 // TODO: CSS constant
219 this.setStyle("display: none;");
220 } else {
221 this.setStyle("display: visible");
222 }
223 }
224
225 /**
226 * Gets all the messages from the list of lists passed in (which are
227 * lists of ErrorMessages associated to the key) and uses the configuration
228 * service to get the message String associated. This will also combine
229 * error messages per a field if that option is turned on. If
230 * displayFieldLabelWithMessages is turned on, it will also find the label
231 * by key passed in.
232 *
233 * @param view
234 * @param key
235 * @param lists
236 * @return
237 */
238 private List<String> getMessages(View view, String key, List<AutoPopulatingList<ErrorMessage>> lists) {
239 List<String> result = new ArrayList<String>();
240 for (List<ErrorMessage> errorList : lists) {
241 if (errorList != null && StringUtils.isNotBlank(key)) {
242 ConfigurationService configService = KRADServiceLocator.getKualiConfigurationService();
243 String comboMessage = "";
244 String label = "";
245
246 for (ErrorMessage e : errorList) {
247 String message = configService.getPropertyValueAsString(e.getErrorKey());
248 if (message == null) {
249 message = "Intended message with key: " + e.getErrorKey() + " not found.";
250 }
251 if (e.getMessageParameters() != null) {
252 message = message.replace("'", "''");
253 message = MessageFormat.format(message, (Object[]) e.getMessageParameters());
254 }
255 if (displayFieldLabelWithMessages) {
256 InputField field = (InputField) view.getViewIndex().getDataFieldByPath(key);
257 if (field != null && field.getLabel() != null) {
258 label = field.getLabel();
259 }
260 }
261
262 // adding them to combo string instead of the list
263 if (combineMessages) {
264 if (comboMessage.isEmpty()) {
265 comboMessage = message;
266 } else {
267 comboMessage = comboMessage + ", " + message;
268 }
269 } else {
270 // add it directly to the list - non combined messages
271 if (StringUtils.isNotEmpty(label)) {
272 result.add(label + " - " + message);
273 } else {
274 result.add(message);
275 }
276
277 }
278 }
279 // add the single combo string to the returned list
280 // combineMessages will also be checked in the template to
281 // further
282 // combine them
283 if (StringUtils.isNotEmpty(comboMessage)) {
284 if (StringUtils.isNotEmpty(label)) {
285 result.add(label + " - " + comboMessage);
286 } else {
287 result.add(comboMessage);
288 }
289 }
290 }
291 }
292
293 return result;
294 }
295
296 /**
297 * Gets all the keys associated to this ErrorsField. This includes the id of
298 * the parent component, additional keys to match, and the bindingPath if
299 * this is an ErrorsField for an InputField. These are the keys that are
300 * used to match errors with their component and display them as part of its
301 * ErrorsField.
302 *
303 * @return
304 */
305 protected List<String> getKeys(Component parent) {
306 List<String> keyList = new ArrayList<String>();
307 if (additionalKeysToMatch != null) {
308 keyList.addAll(additionalKeysToMatch);
309 }
310 if (StringUtils.isNotBlank(parent.getId())) {
311 keyList.add(parent.getId());
312 }
313 if (parent instanceof InputField) {
314 if (((InputField) parent).getBindingInfo() != null && StringUtils.isNotEmpty(
315 ((InputField) parent).getBindingInfo().getBindingPath())) {
316 keyList.add(((InputField) parent).getBindingInfo().getBindingPath());
317 }
318 }
319 // Will there be additional components to check beyond InputField?
320
321 return keyList;
322 }
323
324 /**
325 * Adds all the nestedKeys of this component by calling getKeys on each of
326 * its nestedComponents' ErrorsFields and adding them to the list. If
327 * allowMessageRepeat is false, it will also turn off error display for its
328 * parent's nestedComponents' ErrorsFields.
329 *
330 * @param keyList
331 * @param component
332 */
333 private void addNestedKeys(List<String> keyList, Component component) {
334 for (Component c : component.getComponentsForLifecycle()) {
335 ErrorsField ef = null;
336 if (c instanceof InputField) {
337 ef = ((InputField) c).getErrorsField();
338 } else if (c instanceof ContainerBase) {
339 ef = ((ContainerBase) c).getErrorsField();
340 }
341 if (ef != null) {
342 if (!allowMessageRepeat) {
343 ef.setDisplayMessages(false);
344 }
345 keyList.addAll(ef.getKeys(c));
346 addNestedKeys(keyList, c);
347 }
348 }
349 }
350
351 /**
352 * ErrorTitle is the title that will be shown before any error
353 * messages/error counts are displayed
354 *
355 * @return
356 */
357 public String getErrorTitle() {
358 return this.errorTitle;
359 }
360
361 public void setErrorTitle(String errorTitle) {
362 this.errorTitle = errorTitle;
363 }
364
365 /**
366 * WarningTitle is the title that will be shown before any warning
367 * messages/warning counts are displayed
368 *
369 * @return
370 */
371 public String getWarningTitle() {
372 return this.warningTitle;
373 }
374
375 public void setWarningTitle(String warningTitle) {
376 this.warningTitle = warningTitle;
377 }
378
379 /**
380 * InfoTitle is the title that will be shown before any info messages/info
381 * counts are displayed
382 *
383 * @return
384 */
385 public String getInfoTitle() {
386 return this.infoTitle;
387 }
388
389 public void setInfoTitle(String infoTitle) {
390 this.infoTitle = infoTitle;
391 }
392
393 /**
394 * If displayErrorMessages is true, error messages will be displayed,
395 * otherwise they will not. Unlike many of the options contained on
396 * ErrorsField, this will not effect client side validations; ie this will
397 * not turn off errorMessage display for client side validation, as it may
398 * prevent a user from completing a form. To turn off client side validation
399 * AND its messaging use the applyClientSide flag on the Constraint itself.
400 *
401 * TODO this may be changed to: if this is set on a field it will attempt
402 * show client side validation errors in the closest parent container error
403 * container
404 *
405 * @return
406 */
407 public boolean isDisplayErrorMessages() {
408 return this.displayErrorMessages;
409 }
410
411 public void setDisplayErrorMessages(boolean displayErrorMessages) {
412 this.displayErrorMessages = displayErrorMessages;
413 }
414
415 /**
416 * If displayInfoMessages is true, info messages will be displayed,
417 * otherwise they will not. Client side validation has no concept of warning
418 * or info messages, so this will not effect client side functionality.
419 *
420 * @return
421 */
422 public boolean isDisplayInfoMessages() {
423 return this.displayInfoMessages;
424 }
425
426 public void setDisplayInfoMessages(boolean displayInfoMessages) {
427 this.displayInfoMessages = displayInfoMessages;
428 }
429
430 public boolean isDisplayLockMessages() {
431 return this.displayLockMessages;
432 }
433
434 /**
435 * This has no use - needs to be removed(?)
436 *
437 * @param displayLockMessages
438 */
439 public void setDisplayLockMessages(boolean displayLockMessages) {
440 this.displayLockMessages = displayLockMessages;
441 }
442
443 /**
444 * If displayWarningMessages is true, warning messages will be displayed,
445 * otherwise they will not. Client side validation has no concept of warning
446 * or info messages, so this will not effect client side functionality.
447 *
448 * @return
449 */
450 public boolean isDisplayWarningMessages() {
451 return this.displayWarningMessages;
452 }
453
454 public void setDisplayWarningMessages(boolean displayWarningMessages) {
455 this.displayWarningMessages = displayWarningMessages;
456 }
457
458 /**
459 * AdditionalKeysToMatch is an additional list of keys outside of the
460 * default keys that will be matched when messages are returned after a form
461 * is submitted. These keys are only used for displaying messages generated
462 * by the server and have no effect on client side validation error display.
463 *
464 * @return the additionalKeysToMatch
465 */
466 public List<String> getAdditionalKeysToMatch() {
467 return this.additionalKeysToMatch;
468 }
469
470 /**
471 * Convenience setter for additional keys to match that takes a string argument and
472 * splits on comma to build the list
473 *
474 * @param additionalKeysToMatch String to parse
475 */
476 public void setAdditionalKeysToMatch(String additionalKeysToMatch) {
477 if (StringUtils.isNotBlank(additionalKeysToMatch)) {
478 this.additionalKeysToMatch = Arrays.asList(StringUtils.split(additionalKeysToMatch, ","));
479 }
480 }
481
482 /**
483 * @param additionalKeysToMatch the additionalKeysToMatch to set
484 */
485 public void setAdditionalKeysToMatch(List<String> additionalKeysToMatch) {
486 this.additionalKeysToMatch = additionalKeysToMatch;
487 }
488
489 /**
490 * If true, the errorTitle set on this ErrorsField will be displayed along
491 * with the error messages. Otherwise, the title will not be displayed.
492 *
493 * @return the displayErrorTitle
494 */
495 public boolean isDisplayErrorTitle() {
496 return this.displayErrorTitle;
497 }
498
499 /**
500 * @param displayErrorTitle the displayErrorTitle to set
501 */
502 public void setDisplayErrorTitle(boolean displayErrorTitle) {
503 this.displayErrorTitle = displayErrorTitle;
504 }
505
506 /**
507 * If true, the warningTitle set on this ErrorsField will be displayed along
508 * with the warning messages. Otherwise, the title will not be displayed.
509 *
510 * @return the displayWarningTitle
511 */
512 public boolean isDisplayWarningTitle() {
513 return this.displayWarningTitle;
514 }
515
516 /**
517 * @param displayWarningTitle the displayWarningTitle to set
518 */
519 public void setDisplayWarningTitle(boolean displayWarningTitle) {
520 this.displayWarningTitle = displayWarningTitle;
521 }
522
523 /**
524 * If true, the infoTitle set on this ErrorsField will be displayed along
525 * with the info messages. Otherwise, the title will not be displayed.
526 *
527 * @return the displayInfoTitle
528 */
529 public boolean isDisplayInfoTitle() {
530 return this.displayInfoTitle;
531 }
532
533 /**
534 * @param displayInfoTitle the displayInfoTitle to set
535 */
536 public void setDisplayInfoTitle(boolean displayInfoTitle) {
537 this.displayInfoTitle = displayInfoTitle;
538 }
539
540 /**
541 * If true, the error messages will display the an InputField's title
542 * alongside the error, warning, and info messages related to it. This
543 * setting has no effect on messages which do not relate directly to a
544 * single InputField.
545 *
546 * @return the displayFieldLabelWithMessages
547 */
548 public boolean isDisplayFieldLabelWithMessages() {
549 return this.displayFieldLabelWithMessages;
550 }
551
552 /**
553 * @param displayFieldLabelWithMessages the displayFieldLabelWithMessages to set
554 */
555 public void setDisplayFieldLabelWithMessages(boolean displayFieldLabelWithMessages) {
556 this.displayFieldLabelWithMessages = displayFieldLabelWithMessages;
557 }
558
559 /**
560 * If true, error, warning, and info messages will be displayed (provided
561 * they are also set to display). Otherwise, no messages for this
562 * ErrorsField container will be displayed (including ones set to display).
563 * This is a global display on/off switch for all messages.
564 *
565 * @return the displayMessages
566 */
567 public boolean isDisplayMessages() {
568 return this.displayMessages;
569 }
570
571 /**
572 * @param displayMessages the displayMessages to set
573 */
574 public void setDisplayMessages(boolean displayMessages) {
575 this.displayMessages = displayMessages;
576 }
577
578 /**
579 * If true, this ErrorsField will show messages related to the nested
580 * components of its parent component, and not just those related only to
581 * its parent component. Otherwise, it will be up to the individual
582 * components to display their messages, if any, in their ErrorsField.
583 *
584 * @return the displayNestedMessages
585 */
586 public boolean isDisplayNestedMessages() {
587 return this.displayNestedMessages;
588 }
589
590 /**
591 * @param displayNestedMessages the displayNestedMessages to set
592 */
593 public void setDisplayNestedMessages(boolean displayNestedMessages) {
594 this.displayNestedMessages = displayNestedMessages;
595 }
596
597 /**
598 * Combines the messages for a single key into one concatenated message per
599 * key being matched, seperated by a comma
600 *
601 * @return the combineMessages
602 */
603 public boolean isCombineMessages() {
604 return this.combineMessages;
605 }
606
607 /**
608 * @param combineMessages the combineMessages to set
609 */
610 public void setCombineMessages(boolean combineMessages) {
611 this.combineMessages = combineMessages;
612 }
613
614 /**
615 * If true, when this is set on an ErrorsField whose parentComponent has
616 * nested Containers or AttributeFields, it will allow those fields to also
617 * show their ErrorsField messages. Otherwise, it will turn off the the
618 * display of those messages. This can be used to avoid repeating
619 * information to the user per field, if errors are already being displayed
620 * at the parent's level. This flag has no effect if displayNestedMessages
621 * is false on this ErrorsField.
622 *
623 * @return the allowMessageRepeat
624 */
625 public boolean isAllowMessageRepeat() {
626 return this.allowMessageRepeat;
627 }
628
629 /**
630 * @param allowMessageRepeat the allowMessageRepeat to set
631 */
632 public void setAllowMessageRepeat(boolean allowMessageRepeat) {
633 this.allowMessageRepeat = allowMessageRepeat;
634 }
635
636 /**
637 * displayCounts is true if the counts of errors, warning, and info messages
638 * within this ErrorsField should be displayed (includes count of nested
639 * messages if displayNestedMessages is true).
640 *
641 * @return
642 */
643 public boolean isDisplayCounts() {
644 return this.displayCounts;
645 }
646
647 /**
648 * @param displayCounts the displayCounts to set
649 */
650 public void setDisplayCounts(boolean displayCounts) {
651 this.displayCounts = displayCounts;
652 }
653
654 /**
655 * The list of error messages found for the keys that were matched on this
656 * ErrorsField This is generated and cannot be set
657 *
658 * @return the errors
659 */
660 public List<String> getErrors() {
661 return this.errors;
662 }
663
664 /**
665 * The list of warning messages found for the keys that were matched on this
666 * ErrorsField This is generated and cannot be set
667 *
668 * @return the warnings
669 */
670 public List<String> getWarnings() {
671 return this.warnings;
672 }
673
674 /**
675 * The list of info messages found for the keys that were matched on this
676 * ErrorsField This is generated and cannot be set
677 *
678 * @return the infos
679 */
680 public List<String> getInfos() {
681 return this.infos;
682 }
683
684 /**
685 * The count of error messages found for the keys that were matched on this
686 * ErrorsField This is generated and cannot be set
687 *
688 * @return the errorCount
689 */
690 public int getErrorCount() {
691 return this.errorCount;
692 }
693
694 /**
695 * The count of warning messages found for the keys that were matched on
696 * this ErrorsField This is generated and cannot be set
697 *
698 * @return the warningCount
699 */
700 public int getWarningCount() {
701 return this.warningCount;
702 }
703
704 /**
705 * The count of info messages found for the keys that were matched on this
706 * ErrorsField This is generated and cannot be set
707 *
708 * @return the infoCount
709 */
710 public int getInfoCount() {
711 return this.infoCount;
712 }
713
714 /**
715 * If this is true, the display of messages is being handled by another
716 * container. The ErrorsField html generated by the jsp will still be used,
717 * but it will be placed in different location within the page than the
718 * default to accommodate an alternate layout. This flag is used by
719 * BoxLayoutManager.
720 *
721 * This flag only applies to ErrorsFields whose parentComponents are
722 * AttributeFields.
723 *
724 * @return the alternateContainer
725 */
726 public boolean isAlternateContainer() {
727 return this.alternateContainer;
728 }
729
730 /**
731 * @param alternateContainer the alternateContainer to set
732 */
733 public void setAlternateContainer(boolean alternateContainer) {
734 this.alternateContainer = alternateContainer;
735 }
736
737 /**
738 * If true, displays an icon next to each field that has an error (default
739 * KNS look). Otherwise, this icon will not be displayed. Note that any icon
740 * set through css for the message containers will still appear and this
741 * only relates to the icon directly to the right of an input field.
742 *
743 * This flag should only be set on InputField ErrorsFields.
744 *
745 * @return the displayFieldErrorIcon
746 */
747 public boolean isDisplayFieldErrorIcon() {
748 return this.displayFieldErrorIcon;
749 }
750
751 /**
752 * @param displayFieldErrorIcon the displayFieldErrorIcon to set
753 */
754 public void setDisplayFieldErrorIcon(boolean displayFieldErrorIcon) {
755 this.displayFieldErrorIcon = displayFieldErrorIcon;
756 }
757
758 /**
759 * If true, highlights the parentComponent's container when it has an
760 * error/warning/info. Otherwise, this highlighting will not be displayed.
761 * Note that the css can be changed per a type of highlighting, if showing a
762 * different color or no color per type of message is desired.
763 *
764 * @return the highlightOnError
765 */
766 public void setHighlightOnError(boolean highlightOnError) {
767 this.highlightOnError = highlightOnError;
768 }
769
770 /**
771 * @return the highlightOnError
772 */
773 public boolean isHighlightOnError() {
774 return highlightOnError;
775 }
776
777 private String getGrowlScript(View view) {
778 // growls are setup here because they are relevant to the current page, but their
779 // settings are global to the view
780 String growlScript = "";
781 if (view.isGrowlMessagingEnabled()) {
782 ConfigurationService configService = KRADServiceLocator.getKualiConfigurationService();
783 MessageMap messageMap = GlobalVariables.getMessageMap();
784 if (messageMap.hasErrors()) {
785 String message = configService.getPropertyValueAsString("growl.hasErrors");
786 if (StringUtils.isNotBlank(message)) {
787 growlScript =
788 growlScript + "showGrowl('" + message + "', '" + configService.getPropertyValueAsString(
789 "general.error") + "', 'errorGrowl');";
790 }
791 }
792
793 if (messageMap.hasWarnings()) {
794 String message = configService.getPropertyValueAsString("growl.hasWarnings");
795 if (StringUtils.isNotBlank(message)) {
796 growlScript =
797 growlScript + "showGrowl('" + message + "', '" + configService.getPropertyValueAsString(
798 "general.warning") + "', 'warningGrowl');";
799 }
800 }
801
802 if (messageMap.hasInfo()) {
803 List<String> properties = messageMap.getPropertiesWithInfo();
804 String message = "";
805 for (String property : properties) {
806 List<AutoPopulatingList<ErrorMessage>> lists = messageMap.getInfoMessagesForProperty(property,
807 true);
808 for (List<ErrorMessage> errorList : lists) {
809 if (errorList != null) {
810 for (ErrorMessage e : errorList) {
811 if (StringUtils.isBlank(message)) {
812 message = configService.getPropertyValueAsString(e.getErrorKey());
813 } else {
814 message = message + "<br/>" + configService.getPropertyValueAsString(
815 e.getErrorKey());
816 }
817 if (e.getMessageParameters() != null) {
818 message = message.replace("'", "''");
819 message = MessageFormat.format(message, (Object[]) e.getMessageParameters());
820 }
821 }
822 }
823 }
824 }
825
826 if (StringUtils.isNotBlank(message)) {
827 growlScript =
828 growlScript + "showGrowl('" + message + "', '" + configService.getPropertyValueAsString(
829 "general.info") + "', 'infoGrowl');";
830 }
831 }
832 }
833 return growlScript;
834 }
835
836 public boolean isFireGrowlsForMessages() {
837 return fireGrowlsForMessages;
838 }
839
840 public void setFireGrowlsForMessages(boolean fireGrowlsForMessages) {
841 this.fireGrowlsForMessages = fireGrowlsForMessages;
842 }
843
844 public String getGrowlScript() {
845 return growlScript;
846 }
847 }