View Javadoc

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 }