001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.krad.uif.field; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.config.property.ConfigurationService; 020import org.kuali.rice.krad.service.KRADServiceLocator; 021import org.kuali.rice.krad.uif.container.ContainerBase; 022import org.kuali.rice.krad.uif.container.PageGroup; 023import org.kuali.rice.krad.uif.view.View; 024import org.kuali.rice.krad.uif.component.Component; 025import org.kuali.rice.krad.util.ErrorMessage; 026import org.kuali.rice.krad.util.GlobalVariables; 027import org.kuali.rice.krad.util.MessageMap; 028import org.springframework.util.AutoPopulatingList; 029 030import java.text.MessageFormat; 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.LinkedHashSet; 034import java.util.List; 035 036/** 037 * Field that displays error, warning, and info messages for the keys that are 038 * matched. By default, an ErrorsField will match on id and bindingPath (if this 039 * ErrorsField is for an InputField), but can be set to match on 040 * additionalKeys and nested components keys (of the its parentComponent). 041 * 042 * In addition, there are a variety of options which can be toggled to effect 043 * the display of these messages during both client and server side validation 044 * display. See documentation on each get method for more details on the effect 045 * of each option. 046 * 047 * @author Kuali Rice Team (rice.collab@kuali.org) 048 */ 049public class ErrorsField extends FieldBase { 050 private static final long serialVersionUID = 780940788435330077L; 051 052 private List<String> additionalKeysToMatch; 053 054 private boolean fireGrowlsForMessages; 055 private String growlScript = ""; 056 057 // Title variables 058 private String errorTitle; 059 private String warningTitle; 060 private String infoTitle; 061 062 private boolean displayErrorTitle; 063 private boolean displayWarningTitle; 064 private boolean displayInfoTitle; 065 066 // Field variables 067 private boolean highlightOnError; 068 private boolean displayFieldErrorIcon; 069 070 // Message construction variables 071 private boolean displayFieldLabelWithMessages; 072 private boolean combineMessages; 073 074 // Message display flags 075 private boolean displayNestedMessages; 076 private boolean allowMessageRepeat; 077 078 private boolean displayMessages; 079 private boolean displayErrorMessages; 080 private boolean displayInfoMessages; 081 private boolean displayWarningMessages; 082 private boolean displayCounts; 083 private boolean alternateContainer; 084 085 // Error messages 086 private List<String> errors; 087 private List<String> warnings; 088 private List<String> infos; 089 090 // Counts 091 private int errorCount; 092 private int warningCount; 093 private int infoCount; 094 095 // not used 096 private boolean displayLockMessages; 097 098 public ErrorsField() { 099 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}