001/** 002 * Copyright 2005-2015 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 java.beans.PropertyEditor; 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.List; 022 023import org.apache.commons.lang.StringEscapeUtils; 024import org.apache.commons.lang.StringUtils; 025import org.apache.commons.lang3.ArrayUtils; 026import org.kuali.rice.core.api.exception.RiceRuntimeException; 027import org.kuali.rice.core.api.util.type.TypeUtils; 028import org.kuali.rice.krad.bo.DataObjectRelationship; 029import org.kuali.rice.krad.bo.KualiCode; 030import org.kuali.rice.krad.datadictionary.AttributeDefinition; 031import org.kuali.rice.krad.datadictionary.mask.MaskFormatter; 032import org.kuali.rice.krad.datadictionary.parse.BeanTag; 033import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 034import org.kuali.rice.krad.datadictionary.parse.BeanTags; 035import org.kuali.rice.krad.datadictionary.validator.ValidationTrace; 036import org.kuali.rice.krad.datadictionary.validator.Validator; 037import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 038import org.kuali.rice.krad.uif.UifConstants; 039import org.kuali.rice.krad.uif.component.BindingInfo; 040import org.kuali.rice.krad.uif.component.ComponentSecurity; 041import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; 042import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata; 043import org.kuali.rice.krad.uif.util.ComponentFactory; 044import org.kuali.rice.krad.uif.util.LifecycleAwareList; 045import org.kuali.rice.krad.uif.util.LifecycleElement; 046import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 047import org.kuali.rice.krad.uif.util.ViewModelUtils; 048import org.kuali.rice.krad.uif.view.View; 049import org.kuali.rice.krad.uif.view.ViewModel; 050import org.kuali.rice.krad.uif.widget.Help; 051import org.kuali.rice.krad.uif.widget.Inquiry; 052import org.kuali.rice.krad.uif.widget.Tooltip; 053import org.kuali.rice.krad.util.KRADPropertyConstants; 054import org.kuali.rice.krad.util.KRADUtils; 055import org.kuali.rice.krad.valuefinder.ValueFinder; 056import org.kuali.rice.krad.web.form.InquiryForm; 057 058/** 059 * Field that renders data from the application, such as the value of a data object property 060 * 061 * @author Kuali Rice Team (rice.collab@kuali.org) 062 */ 063@BeanTags({@BeanTag(name = "data", parent = "Uif-DataField"), 064 @BeanTag(name = "dataLabelTop", parent = "Uif-DataField-LabelTop"), 065 @BeanTag(name = "dataLabelRight", parent = "Uif-DataField-LabelRight"), 066 @BeanTag(name = "dataNoLabel", parent = "Uif-DataField-withoutLabel")}) 067public class DataFieldBase extends FieldBase implements DataField { 068 private static final long serialVersionUID = -4129678891948564724L; 069 070 // binding 071 private String propertyName; 072 private BindingInfo bindingInfo; 073 074 private String dictionaryAttributeName; 075 private String dictionaryObjectEntry; 076 077 // value props 078 private Object defaultValue; 079 private Class<? extends ValueFinder> defaultValueFinderClass; 080 private List<Object> defaultValues; 081 private String forcedValue; 082 083 private PropertyEditor propertyEditor; 084 085 private boolean addHiddenWhenReadOnly; 086 087 // read only display properties 088 protected String readOnlyDisplayReplacementPropertyName; 089 protected String readOnlyDisplaySuffixPropertyName; 090 091 private String readOnlyDisplayReplacement; 092 private String readOnlyDisplaySuffix; 093 094 private String readOnlyListDisplayType; 095 private String readOnlyListDelimiter; 096 097 private boolean applyMask; 098 private MaskFormatter maskFormatter; 099 100 private List<String> additionalHiddenPropertyNames; 101 private List<String> propertyNamesForAdditionalDisplay; 102 103 private boolean escapeHtmlInPropertyValue; 104 private boolean multiLineReadOnlyDisplay; 105 106 // widgets 107 private Inquiry inquiry; 108 private boolean enableAutoInquiry; 109 110 private Help help; 111 112 // Optional span render flags 113 private boolean renderInfoMessageSpan; 114 private boolean renderMarkerIconSpan; 115 116 private String sortAs; 117 118 public DataFieldBase() { 119 super(); 120 121 enableAutoInquiry = true; 122 escapeHtmlInPropertyValue = true; 123 124 additionalHiddenPropertyNames = Collections.emptyList(); 125 propertyNamesForAdditionalDisplay = Collections.emptyList(); 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public void performInitialization(Object model) { 133 super.performInitialization(model); 134 135 if (bindingInfo != null) { 136 bindingInfo.setDefaults(ViewLifecycle.getView(), getPropertyName()); 137 } 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 public void afterEvaluateExpression() { 145 // set to true before calling super. 146 if (getReadOnly() == null) { 147 setReadOnly(true); 148 } 149 150 super.afterEvaluateExpression(); 151 } 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override 157 public void performApplyModel(Object model, LifecycleElement parent) { 158 super.performApplyModel(model, parent); 159 160 if (enableAutoInquiry && this.inquiry == null && Boolean.TRUE.equals(getReadOnly()) && hasAutoInquiryRelationship()) { 161 this.inquiry = ComponentFactory.getInquiry(); 162 } 163 164 if (isAddHiddenWhenReadOnly()) { 165 setReadOnly(true); 166 getAdditionalHiddenPropertyNames().add(getPropertyName()); 167 } 168 } 169 170 /** 171 * {@inheritDoc} 172 */ 173 @Override 174 public void performFinalize(Object model, LifecycleElement parent) { 175 super.performFinalize(model, parent); 176 177 // adjust the path for hidden fields and add as accessible paths 178 List<String> hiddenPropertyPaths = new ArrayList<String>(); 179 for (String hiddenPropertyName : getAdditionalHiddenPropertyNames()) { 180 String hiddenPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(hiddenPropertyName); 181 hiddenPropertyPaths.add(hiddenPropertyPath); 182 183 if (isRender() || StringUtils.isNotBlank(getProgressiveRender())) { 184 ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(hiddenPropertyPath); 185 } 186 } 187 this.additionalHiddenPropertyNames = hiddenPropertyPaths; 188 189 // adjust paths on informational property names 190 List<String> informationalPropertyPaths = new ArrayList<String>(); 191 for (String infoPropertyName : getPropertyNamesForAdditionalDisplay()) { 192 String infoPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(infoPropertyName); 193 informationalPropertyPaths.add(infoPropertyPath); 194 } 195 this.propertyNamesForAdditionalDisplay = informationalPropertyPaths; 196 197 // process read-only lists and additional and alternate display values 198 boolean hasPropertyEditor = getPropertyEditor() != null; 199 boolean hasReadOnlyDisplayReplacement = StringUtils.isNotBlank(getReadOnlyDisplayReplacement()); 200 boolean hasReadOnlyDisplayReplacementPropertyName = StringUtils.isNotBlank( 201 getReadOnlyDisplayReplacementPropertyName()); 202 String bindingPath = getBindingInfo().getBindingPath(); 203 Class<?> type = StringUtils.isNotEmpty(bindingPath) ? ObjectPropertyUtils.getPropertyType(model, bindingPath) : null; 204 boolean isReadOnlyList = Boolean.TRUE.equals(getReadOnly()) && type != null && List.class.isAssignableFrom(type); 205 206 if (!hasPropertyEditor && !hasReadOnlyDisplayReplacement && !hasReadOnlyDisplayReplacementPropertyName && isReadOnlyList) { 207 Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, bindingPath); 208 List<?> list = fieldValue != null ? (List<?>) fieldValue : Collections.emptyList(); 209 210 processReadOnlyListDisplay(model, list); 211 } else { 212 setAlternateAndAdditionalDisplayValue(ViewLifecycle.getView(), model); 213 } 214 215 if (this.getFieldLabel() != null && StringUtils.isNotBlank(this.getId())) { 216 this.getFieldLabel().setLabelForComponentId(this.getId() + UifConstants.IdSuffixes.CONTROL); 217 } 218 219 if (model instanceof ViewModel) { 220 View view = ViewLifecycle.getView(); 221 if(((ViewModel) model).isApplyDefaultValues()) { 222 223 // apply default field values to view 224 view.getViewHelperService().populateDefaultValueForField(model, this, 225 this.getBindingInfo().getBindingPath()); 226 227 // ensure default values are only applied once 228 ((ViewModel) model).setApplyDefaultValues(false); 229 } 230 } 231 232 ViewPostMetadata viewPostMetadata = ViewLifecycle.getViewPostMetadata(); 233 if (isRender() && viewPostMetadata != null) { 234 viewPostMetadata.addRenderedPropertyPath(getBindingInfo().getBindingPath()); 235 } 236 } 237 238 /** 239 * This method is called when the list is readOnly as determined in DataField's performFinalize method. This 240 * method 241 * should be overridden to perform any additional processing to the values before calling 242 * generateReadOnlyListDisplayReplacement. The default implementation calls it directly with the originalList. 243 * 244 * @param model the model 245 * @param originalList originalList of values 246 */ 247 protected void processReadOnlyListDisplay(Object model, List<?> originalList) { 248 this.setReadOnlyDisplayReplacement(generateReadOnlyListDisplayReplacement(originalList)); 249 } 250 251 /** 252 * Generates the html to be used and sets the readOnlyDisplayReplacement for DataFields that contain lists and 253 * do not have their own readOnlyDisplayReplacement defined. The type of html generated is based on the options 254 * set on readOnlyListDisplayType and readOnlyListDelimiter. 255 * 256 * @param list the list to be converted to readOnly html 257 */ 258 protected String generateReadOnlyListDisplayReplacement(List<?> list) { 259 //Default to delimited if nothing is set 260 if (getReadOnlyListDisplayType() == null) { 261 this.setReadOnlyListDisplayType(UifConstants.ReadOnlyListTypes.DELIMITED.name()); 262 } 263 264 String generatedHtml = ""; 265 266 //begin generation setup 267 if (!list.isEmpty()) { 268 if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.UL.name())) { 269 generatedHtml = "<ul class='uif-readOnlyStringList'>"; 270 } else if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.OL.name())) { 271 generatedHtml = "<ol class='uif-readOnlyStringList'>"; 272 } else if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.BREAK.name())) { 273 setReadOnlyListDelimiter("<br/>"); 274 } else if (this.getReadOnlyListDelimiter() == null) { 275 setReadOnlyListDelimiter(", "); 276 } 277 } 278 279 //iterate through each value 280 for (Object value : list) { 281 //if blank skip 282 if (!TypeUtils.isSimpleType(value.getClass()) || StringUtils.isBlank(value.toString())) { 283 continue; 284 } 285 286 //handle mask if any 287 if (isApplyMask()) { 288 value = getMaskFormatter().maskValue(value); 289 } 290 291 //TODO the value should use the formatted text property value we would expect to see instead of toString 292 //two types - delimited and html list 293 if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.UL.name()) 294 || getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.OL.name())) { 295 generatedHtml = generatedHtml + "<li>" + StringEscapeUtils.escapeHtml(value.toString()) + "</li>"; 296 } else { 297 //no matching needed - delimited is always the fallback and break uses same logic 298 generatedHtml = generatedHtml + StringEscapeUtils.escapeHtml(value.toString()) 299 + this.getReadOnlyListDelimiter(); 300 } 301 } 302 303 //end the generation 304 if (!list.isEmpty()) { 305 if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.UL.name())) { 306 generatedHtml = generatedHtml + "</ul>"; 307 } else if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.OL.name())) { 308 generatedHtml = generatedHtml + "</ol>"; 309 } else { 310 generatedHtml = StringUtils.removeEnd(generatedHtml, this.getReadOnlyListDelimiter()); 311 } 312 } 313 314 if (StringUtils.isBlank(generatedHtml)) { 315 generatedHtml = " "; 316 } 317 318 return generatedHtml; 319 } 320 321 /** 322 * Sets alternate and additional property value for this field. 323 * 324 * <p> 325 * If <code>AttributeSecurity</code> present in this field, make sure the current user has permission to view the 326 * field value. If user doesn't have permission to view the value, mask the value as configured and set it 327 * as alternate value for display. If security doesn't exists for this field but 328 * <code>alternateDisplayPropertyName</code> present, get its value and format it based on that 329 * fields formatting and set for display. 330 * </p> 331 * 332 * <p> 333 * For additional display value, if <code>AttributeSecurity</code> not present, sets the value if 334 * <code>additionalDisplayPropertyName</code> present. If not present, check whether this field is a 335 * <code>KualiCode</code> and get the relationship configured in the datadictionary file and set the name 336 * additional display value which will be displayed along with the code. If additional display property not 337 * present, check whether this field is has <code>MultiValueControlBase</code>. If yes, get the Label 338 * for the value and set it as additional display value. 339 * </p> 340 * 341 * @param view the current view instance 342 * @param model model instance 343 */ 344 protected void setAlternateAndAdditionalDisplayValue(View view, Object model) { 345 // if alternate or additional display values set don't use property names 346 if (StringUtils.isNotBlank(readOnlyDisplayReplacement) || StringUtils.isNotBlank(readOnlyDisplaySuffix)) { 347 return; 348 } 349 350 // check whether field value needs to be masked, and if so apply masking as alternateDisplayValue 351 if (isApplyMask()) { 352 Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, getBindingInfo().getBindingPath()); 353 if (getMaskFormatter() != null) { 354 readOnlyDisplayReplacement = getMaskFormatter().maskValue(fieldValue); 355 } 356 357 return; 358 } 359 360 // if not read only, return without trying to set alternate and additional values 361 if (!Boolean.TRUE.equals(getReadOnly())) { 362 return; 363 } 364 365 // if field is not secure, check for alternate and additional display properties 366 if (StringUtils.isNotBlank(getReadOnlyDisplayReplacementPropertyName())) { 367 String alternateDisplayPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath( 368 getReadOnlyDisplayReplacementPropertyName()); 369 370 Object alternateFieldValue = ObjectPropertyUtils.getPropertyValue(model, alternateDisplayPropertyPath); 371 if (alternateFieldValue != null) { 372 // TODO: format by type 373 readOnlyDisplayReplacement = alternateFieldValue.toString(); 374 } 375 } 376 377 // perform automatic translation for code references if enabled on view 378 if (StringUtils.isBlank(getReadOnlyDisplaySuffixPropertyName()) && view.isTranslateCodesOnReadOnlyDisplay()) { 379 // check for any relationship present for this field and it's of type KualiCode 380 Class<?> parentObjectClass = ViewModelUtils.getParentObjectClassForMetadata(view, model, this); 381 DataObjectRelationship relationship = 382 KRADServiceLocatorWeb.getLegacyDataAdapter().getDataObjectRelationship(null, 383 parentObjectClass, getBindingInfo().getBindingName(), "", true, false, false); 384 385 if (relationship != null 386 && getPropertyName().startsWith(relationship.getParentAttributeName()) 387 && KualiCode.class.isAssignableFrom(relationship.getRelatedClass())) { 388 readOnlyDisplaySuffixPropertyName = 389 relationship.getParentAttributeName() + "." + KRADPropertyConstants.NAME; 390 } 391 } 392 393 // now check for an additional display property and if set get the value 394 if (StringUtils.isNotBlank(getReadOnlyDisplaySuffixPropertyName())) { 395 String additionalDisplayPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath( 396 getReadOnlyDisplaySuffixPropertyName()); 397 398 Object additionalFieldValue = ObjectPropertyUtils.getPropertyValue(model, additionalDisplayPropertyPath); 399 if (additionalFieldValue != null) { 400 // TODO: format by type 401 readOnlyDisplaySuffix = additionalFieldValue.toString(); 402 } 403 } 404 } 405 406 /** 407 * {@inheritDoc} 408 */ 409 @Override 410 public void copyFromAttributeDefinition(AttributeDefinition attributeDefinition) { 411 // label 412 if (StringUtils.isEmpty(getLabel())) { 413 setLabel(attributeDefinition.getLabel()); 414 } 415 416 // short label 417 if (StringUtils.isEmpty(getShortLabel())) { 418 setShortLabel(attributeDefinition.getShortLabel()); 419 } 420 421 // security 422 if ((attributeDefinition.getAttributeSecurity() != null) && ((getDataFieldSecurity() == null) || ( 423 getDataFieldSecurity().getAttributeSecurity() == null))) { 424 initializeComponentSecurity(); 425 426 getDataFieldSecurity().setAttributeSecurity(attributeDefinition.getAttributeSecurity()); 427 } 428 429 // alternate property name 430 if (getReadOnlyDisplayReplacementPropertyName() == null && StringUtils.isNotBlank( 431 attributeDefinition.getAlternateDisplayAttributeName())) { 432 setReadOnlyDisplayReplacementPropertyName(attributeDefinition.getAlternateDisplayAttributeName()); 433 } 434 435 // additional property display name 436 if (getReadOnlyDisplaySuffixPropertyName() == null && StringUtils.isNotBlank( 437 attributeDefinition.getAdditionalDisplayAttributeName())) { 438 setReadOnlyDisplaySuffixPropertyName(attributeDefinition.getAdditionalDisplayAttributeName()); 439 } 440 441 // property editor 442 if (getPropertyEditor() == null) { 443 setPropertyEditor(attributeDefinition.getPropertyEditor()); 444 } 445 } 446 447 /** 448 * {@inheritDoc} 449 */ 450 @Override 451 public boolean isInputAllowed() { 452 return false; 453 } 454 455 /** 456 * {@inheritDoc} 457 */ 458 @Override 459 @BeanTagAttribute 460 public String getPropertyName() { 461 return this.propertyName; 462 } 463 464 /** 465 * {@inheritDoc} 466 */ 467 @Override 468 public void setPropertyName(String propertyName) { 469 this.propertyName = propertyName; 470 } 471 472 /** 473 * {@inheritDoc} 474 */ 475 @Override 476 @BeanTagAttribute 477 public PropertyEditor getPropertyEditor() { 478 return propertyEditor; 479 } 480 481 /** 482 * {@inheritDoc} 483 */ 484 @Override 485 public void setPropertyEditor(PropertyEditor propertyEditor) { 486 this.propertyEditor = propertyEditor; 487 } 488 489 /** 490 * {@inheritDoc} 491 */ 492 @Override 493 public void setPropertyEditorClass(Class<? extends PropertyEditor> propertyEditorClass) { 494 this.propertyEditor = KRADUtils.createNewObjectFromClass(propertyEditorClass); 495 } 496 497 /** 498 * {@inheritDoc} 499 */ 500 @Override 501 @BeanTagAttribute 502 public BindingInfo getBindingInfo() { 503 return this.bindingInfo; 504 } 505 506 /** 507 * {@inheritDoc} 508 */ 509 @Override 510 public void setBindingInfo(BindingInfo bindingInfo) { 511 this.bindingInfo = bindingInfo; 512 } 513 514 /** 515 * {@inheritDoc} 516 */ 517 @Override 518 public String getName() { 519 return this.getBindingInfo().getBindingPath(); 520 } 521 522 /** 523 * {@inheritDoc} 524 */ 525 @Override 526 @BeanTagAttribute 527 public String getDictionaryAttributeName() { 528 return this.dictionaryAttributeName; 529 } 530 531 /** 532 * {@inheritDoc} 533 */ 534 @Override 535 public void setDictionaryAttributeName(String dictionaryAttributeName) { 536 this.dictionaryAttributeName = dictionaryAttributeName; 537 } 538 539 /** 540 * {@inheritDoc} 541 */ 542 @Override 543 @BeanTagAttribute 544 public String getDictionaryObjectEntry() { 545 return this.dictionaryObjectEntry; 546 } 547 548 /** 549 * {@inheritDoc} 550 */ 551 @Override 552 public void setDictionaryObjectEntry(String dictionaryObjectEntry) { 553 this.dictionaryObjectEntry = dictionaryObjectEntry; 554 } 555 556 /** 557 * {@inheritDoc} 558 */ 559 @Override 560 @BeanTagAttribute 561 public Object getDefaultValue() { 562 return this.defaultValue; 563 } 564 565 /** 566 * {@inheritDoc} 567 */ 568 @Override 569 public void setDefaultValue(Object defaultValue) { 570 this.defaultValue = defaultValue; 571 } 572 573 /** 574 * {@inheritDoc} 575 */ 576 @Override 577 @BeanTagAttribute 578 public Class<? extends ValueFinder> getDefaultValueFinderClass() { 579 return this.defaultValueFinderClass; 580 } 581 582 /** 583 * {@inheritDoc} 584 */ 585 @Override 586 public void setDefaultValueFinderClass(Class<? extends ValueFinder> defaultValueFinderClass) { 587 this.defaultValueFinderClass = defaultValueFinderClass; 588 } 589 590 /** 591 * {@inheritDoc} 592 */ 593 @Override 594 @BeanTagAttribute 595 public List<Object> getDefaultValues() { 596 return this.defaultValues; 597 } 598 599 /** 600 * {@inheritDoc} 601 */ 602 public void setDefaultValues(List<Object> defaultValues) { 603 this.defaultValues = defaultValues; 604 } 605 606 /** 607 * {@inheritDoc} 608 */ 609 @Override 610 public String getForcedValue() { 611 return forcedValue; 612 } 613 614 /** 615 * {@inheritDoc} 616 */ 617 @Override 618 public void setForcedValue(String forcedValue) { 619 this.forcedValue = forcedValue; 620 } 621 622 /** 623 * {@inheritDoc} 624 */ 625 @Override 626 @BeanTagAttribute 627 public String getHelpSummary() { 628 return this.help.getTooltipHelpContent(); 629 } 630 631 /** 632 * {@inheritDoc} 633 */ 634 @Override 635 public void setHelpSummary(String helpSummary) { 636 this.help.setTooltipHelpContent(helpSummary); 637 } 638 639 /** 640 * {@inheritDoc} 641 */ 642 @Override 643 public DataFieldSecurity getDataFieldSecurity() { 644 return (DataFieldSecurity) super.getComponentSecurity(); 645 } 646 647 /** 648 * {@inheritDoc} 649 */ 650 @Override 651 public void setComponentSecurity(ComponentSecurity componentSecurity) { 652 if ((componentSecurity != null) && !(componentSecurity instanceof DataFieldSecurity)) { 653 throw new RiceRuntimeException("Component security for DataField should be instance of DataFieldSecurity"); 654 } 655 656 super.setComponentSecurity(componentSecurity); 657 } 658 659 /** 660 * @see org.kuali.rice.krad.uif.component.ComponentBase#initializeComponentSecurity() 661 */ 662 @Override 663 protected void initializeComponentSecurity() { 664 if (getComponentSecurity() == null) { 665 setComponentSecurity(KRADUtils.createNewObjectFromClass(DataFieldSecurity.class)); 666 } 667 } 668 669 /** 670 * {@inheritDoc} 671 */ 672 @Override 673 @BeanTagAttribute 674 public boolean isAddHiddenWhenReadOnly() { 675 return addHiddenWhenReadOnly; 676 } 677 678 /** 679 * {@inheritDoc} 680 */ 681 @Override 682 public void setAddHiddenWhenReadOnly(boolean addHiddenWhenReadOnly) { 683 this.addHiddenWhenReadOnly = addHiddenWhenReadOnly; 684 } 685 686 /** 687 * {@inheritDoc} 688 */ 689 @Override 690 @BeanTagAttribute(type = BeanTagAttribute.AttributeType.DIRECTORBYTYPE) 691 public Inquiry getInquiry() { 692 return this.inquiry; 693 } 694 695 /** 696 * {@inheritDoc} 697 */ 698 @Override 699 public void setInquiry(Inquiry inquiry) { 700 this.inquiry = inquiry; 701 } 702 703 /** 704 * {@inheritDoc} 705 */ 706 @Override 707 public boolean isEnableAutoInquiry() { 708 return enableAutoInquiry; 709 } 710 711 /** 712 * {@inheritDoc} 713 */ 714 @Override 715 public void setEnableAutoInquiry(boolean enableAutoInquiry) { 716 this.enableAutoInquiry = enableAutoInquiry; 717 } 718 719 /** 720 * {@inheritDoc} 721 */ 722 @Override 723 @BeanTagAttribute(type = BeanTagAttribute.AttributeType.DIRECTORBYTYPE) 724 public Help getHelp() { 725 return this.help; 726 } 727 728 /** 729 * {@inheritDoc} 730 */ 731 @Override 732 public void setHelp(Help help) { 733 this.help = help; 734 } 735 736 /** 737 * {@inheritDoc} 738 */ 739 @Override 740 @BeanTagAttribute 741 public boolean isRenderInfoMessageSpan() { 742 return renderInfoMessageSpan; 743 } 744 745 /** 746 * {@inheritDoc} 747 */ 748 @Override 749 public void setRenderInfoMessageSpan(boolean renderInfoMessageSpan) { 750 this.renderInfoMessageSpan = renderInfoMessageSpan; 751 } 752 753 /** 754 * {@inheritDoc} 755 */ 756 @Override 757 @BeanTagAttribute 758 public boolean isRenderMarkerIconSpan() { 759 return renderMarkerIconSpan; 760 } 761 762 /** 763 * {@inheritDoc} 764 */ 765 @Override 766 public void setRenderMarkerIconSpan(boolean renderMarkerIconSpan) { 767 this.renderMarkerIconSpan = renderMarkerIconSpan; 768 } 769 770 /** 771 * {@inheritDoc} 772 */ 773 @Override 774 public void setTooltipOfComponent(Tooltip tooltip) { 775 getFieldLabel().setToolTip(tooltip); 776 } 777 778 /** 779 * {@inheritDoc} 780 */ 781 @Override 782 public String getHelpTitle() { 783 return this.getLabel(); 784 } 785 786 /** 787 * {@inheritDoc} 788 */ 789 @Override 790 @BeanTagAttribute 791 public String getReadOnlyDisplaySuffixPropertyName() { 792 return this.readOnlyDisplaySuffixPropertyName; 793 } 794 795 /** 796 * {@inheritDoc} 797 */ 798 @Override 799 public void setReadOnlyDisplaySuffixPropertyName(String readOnlyDisplaySuffixPropertyName) { 800 this.readOnlyDisplaySuffixPropertyName = readOnlyDisplaySuffixPropertyName; 801 } 802 803 /** 804 * {@inheritDoc} 805 */ 806 @Override 807 @BeanTagAttribute 808 public String getReadOnlyDisplayReplacementPropertyName() { 809 return this.readOnlyDisplayReplacementPropertyName; 810 } 811 812 /** 813 * {@inheritDoc} 814 */ 815 @Override 816 public void setReadOnlyDisplayReplacementPropertyName(String readOnlyDisplayReplacementPropertyName) { 817 this.readOnlyDisplayReplacementPropertyName = readOnlyDisplayReplacementPropertyName; 818 } 819 820 /** 821 * {@inheritDoc} 822 */ 823 @Override 824 @BeanTagAttribute 825 public String getReadOnlyDisplayReplacement() { 826 return readOnlyDisplayReplacement; 827 } 828 829 /** 830 * {@inheritDoc} 831 */ 832 @Override 833 public void setReadOnlyDisplayReplacement(String value) { 834 this.readOnlyDisplayReplacement = value; 835 } 836 837 /** 838 * {@inheritDoc} 839 */ 840 @Override 841 @BeanTagAttribute 842 public String getReadOnlyDisplaySuffix() { 843 return readOnlyDisplaySuffix; 844 } 845 846 /** 847 * {@inheritDoc} 848 */ 849 @Override 850 public void setReadOnlyDisplaySuffix(String value) { 851 this.readOnlyDisplaySuffix = value; 852 } 853 854 /** 855 * {@inheritDoc} 856 */ 857 @Override 858 @BeanTagAttribute 859 public String getReadOnlyListDisplayType() { 860 return readOnlyListDisplayType; 861 } 862 863 /** 864 * {@inheritDoc} 865 */ 866 @Override 867 public void setReadOnlyListDisplayType(String readOnlyListDisplayType) { 868 this.readOnlyListDisplayType = readOnlyListDisplayType; 869 } 870 871 /** 872 * {@inheritDoc} 873 */ 874 @Override 875 @BeanTagAttribute 876 public String getReadOnlyListDelimiter() { 877 return readOnlyListDelimiter; 878 } 879 880 /** 881 * {@inheritDoc} 882 */ 883 @Override 884 public void setReadOnlyListDelimiter(String readOnlyListDelimiter) { 885 this.readOnlyListDelimiter = readOnlyListDelimiter; 886 } 887 888 /** 889 * {@inheritDoc} 890 */ 891 @Override 892 @BeanTagAttribute 893 public boolean isApplyMask() { 894 return applyMask; 895 } 896 897 /** 898 * {@inheritDoc} 899 */ 900 @Override 901 public void setApplyMask(boolean applyMask) { 902 this.applyMask = applyMask; 903 } 904 905 /** 906 * {@inheritDoc} 907 */ 908 @Override 909 @BeanTagAttribute 910 public MaskFormatter getMaskFormatter() { 911 return maskFormatter; 912 } 913 914 /** 915 * {@inheritDoc} 916 */ 917 @Override 918 public void setMaskFormatter(MaskFormatter maskFormatter) { 919 this.maskFormatter = maskFormatter; 920 } 921 922 /** 923 * {@inheritDoc} 924 */ 925 @Override 926 @BeanTagAttribute 927 public List<String> getAdditionalHiddenPropertyNames() { 928 if (additionalHiddenPropertyNames == Collections.EMPTY_LIST && isMutable(true)) { 929 additionalHiddenPropertyNames = new LifecycleAwareList<String>(this); 930 } 931 932 return additionalHiddenPropertyNames; 933 } 934 935 /** 936 * {@inheritDoc} 937 */ 938 @Override 939 public void setAdditionalHiddenPropertyNames(List<String> additionalHiddenPropertyNames) { 940 if (additionalHiddenPropertyNames == null) { 941 this.additionalHiddenPropertyNames = Collections.emptyList(); 942 } else { 943 this.additionalHiddenPropertyNames = 944 new LifecycleAwareList<String>(this, additionalHiddenPropertyNames); 945 } 946 } 947 948 /** 949 * {@inheritDoc} 950 */ 951 @Override 952 @BeanTagAttribute 953 public List<String> getPropertyNamesForAdditionalDisplay() { 954 if (propertyNamesForAdditionalDisplay == Collections.EMPTY_LIST && isMutable(true)) { 955 propertyNamesForAdditionalDisplay = new LifecycleAwareList<String>(this); 956 } 957 958 return propertyNamesForAdditionalDisplay; 959 } 960 961 /** 962 * {@inheritDoc} 963 */ 964 @Override 965 public void setPropertyNamesForAdditionalDisplay(List<String> propertyNamesForAdditionalDisplay) { 966 if (propertyNamesForAdditionalDisplay == null) { 967 this.propertyNamesForAdditionalDisplay = Collections.emptyList(); 968 } else { 969 this.propertyNamesForAdditionalDisplay = 970 new LifecycleAwareList<String>(this, propertyNamesForAdditionalDisplay); 971 } 972 } 973 974 /** 975 * {@inheritDoc} 976 */ 977 @Override 978 @BeanTagAttribute 979 public boolean isEscapeHtmlInPropertyValue() { 980 return this.escapeHtmlInPropertyValue; 981 } 982 983 /** 984 * {@inheritDoc} 985 */ 986 @Override 987 public void setEscapeHtmlInPropertyValue(boolean escapeHtmlInPropertyValue) { 988 this.escapeHtmlInPropertyValue = escapeHtmlInPropertyValue; 989 } 990 991 /** 992 * {@inheritDoc} 993 */ 994 @Override 995 @BeanTagAttribute 996 public boolean isMultiLineReadOnlyDisplay() { 997 return multiLineReadOnlyDisplay; 998 } 999 1000 /** 1001 * {@inheritDoc} 1002 */ 1003 @Override 1004 public void setMultiLineReadOnlyDisplay(boolean multiLineReadOnlyDisplay) { 1005 this.multiLineReadOnlyDisplay = multiLineReadOnlyDisplay; 1006 } 1007 1008 /** 1009 * {@inheritDoc} 1010 */ 1011 @Override 1012 public boolean hasSecureValue() { 1013 boolean hasHideAuthz = false; 1014 1015 if (getDataFieldSecurity() != null) { 1016 boolean isViewAuthz = false; 1017 boolean isViewInLineAuthz = false; 1018 boolean isHide = false; 1019 1020 if (getDataFieldSecurity().isViewAuthz() != null) { 1021 isViewAuthz = getDataFieldSecurity().isViewAuthz().booleanValue(); 1022 } 1023 1024 if (getDataFieldSecurity().isViewInLineAuthz() != null) { 1025 isViewInLineAuthz = getDataFieldSecurity().isViewInLineAuthz().booleanValue(); 1026 } 1027 1028 if (getDataFieldSecurity().getAttributeSecurity() != null) { 1029 isHide = getDataFieldSecurity().getAttributeSecurity().isHide(); 1030 } 1031 1032 hasHideAuthz = isViewAuthz || isViewInLineAuthz || isHide; 1033 } 1034 1035 return isApplyMask() || (hasHideAuthz && isHidden()); 1036 } 1037 1038 /** 1039 * {@inheritDoc} 1040 */ 1041 @Override 1042 public boolean isRenderFieldset() { 1043 return (!Boolean.TRUE.equals(this.getReadOnly()) 1044 && inquiry != null 1045 && inquiry.isRender() 1046 && inquiry.getInquiryLink() != null 1047 && inquiry.getInquiryLink().isRender()) || (help != null 1048 && help.isRender() 1049 && help.getHelpAction() != null 1050 && help.getHelpAction().isRender()); 1051 } 1052 1053 /** 1054 * {@inheritDoc} 1055 */ 1056 @Override 1057 @BeanTagAttribute(name = "sortAs") 1058 public String getSortAs() { 1059 return sortAs; 1060 } 1061 1062 /** 1063 * {@inheritDoc} 1064 */ 1065 @Override 1066 public void setSortAs(String sortAs) { 1067 if (!(sortAs.equals(UifConstants.TableToolsValues.CURRENCY) || sortAs.equals(UifConstants.TableToolsValues.DATE) || sortAs.equals(UifConstants.TableToolsValues.NUMERIC) || sortAs.equals(UifConstants.TableToolsValues.STRING))) { 1068 throw new IllegalArgumentException("invalid sortAs value of " + sortAs + ", allowed: " + UifConstants.TableToolsValues.CURRENCY + "|" + UifConstants.TableToolsValues.DATE + "|" + UifConstants.TableToolsValues.NUMERIC + "|" + UifConstants.TableToolsValues.STRING); 1069 } 1070 this.sortAs = sortAs; 1071 } 1072 1073 /** 1074 * {@inheritDoc} 1075 */ 1076 @Override 1077 public void completeValidation(ValidationTrace tracer) { 1078 tracer.addBean(this); 1079 1080 // Checks that the property is connected to the field 1081 if (getPropertyName() == null) { 1082 if (!Validator.checkExpressions(this, "propertyName")) { 1083 String currentValues[] = {"propertyName = " + getPropertyName()}; 1084 tracer.createError("Property name not set", currentValues); 1085 } 1086 } 1087 1088 // Checks that the default values present 1089/* if (getDefaultValue() != null && getDefaultValues() != null) { 1090 String currentValues[] = 1091 {"defaultValue =" + getDefaultValue(), "defaultValues Size =" + getDefaultValues().length}; 1092 tracer.createWarning("Both Default Value and Default Values set", currentValues); 1093 }*/ 1094 1095 // Checks that a mask formatter is set if the data field is to be masked 1096 if (isApplyMask()) { 1097 if (maskFormatter == null) { 1098 String currentValues[] = {"applyMask =" + isApplyMask(), "maskFormatter =" + maskFormatter}; 1099 tracer.createWarning("Apply mask is true, but no value is set for maskFormatter", currentValues); 1100 } 1101 } 1102 1103 super.completeValidation(tracer.getCopy()); 1104 } 1105 1106 /** 1107 * Determines whether or not to create an automatic inquiry widget for this field within the current lifecycle. 1108 * 1109 * @return True if an automatic inquiry widget should be created for this field on the current lifecycle. 1110 */ 1111 protected boolean hasAutoInquiryRelationship() { 1112 if (getBindingInfo() == null) { 1113 return false; 1114 } 1115 1116 View view = ViewLifecycle.getView(); 1117 Object model = ViewLifecycle.getModel(); 1118 Object object = ViewModelUtils.getParentObjectForMetadata(view, model, this); 1119 1120 // Do checks for inquiry when read only 1121 if (Boolean.TRUE.equals(getReadOnly())) { 1122 String bindingPath = getBindingInfo().getBindingPath(); 1123 1124 if (StringUtils.isBlank(bindingPath) || bindingPath.equals("null")) { 1125 return false; 1126 } 1127 1128 Object propertyValue; 1129 1130 // do not render the inquiry if the field value is null 1131 try { 1132 propertyValue = ObjectPropertyUtils.getPropertyValue(model, bindingPath); 1133 1134 if ((propertyValue == null) || StringUtils.isBlank(propertyValue.toString())) { 1135 return false; 1136 } 1137 } catch (Exception e) { 1138 // if we can't get the value just swallow the exception and don't set an inquiry 1139 return false; 1140 } 1141 1142 // do not render the inquiry link if it is the same as its parent 1143 if (view.getViewTypeName() == UifConstants.ViewType.INQUIRY) { 1144 InquiryForm inquiryForm = (InquiryForm) model; 1145 String[] parameterValues = inquiryForm.getInitialRequestParameters().get(propertyName); 1146 1147 // do not render the inquiry if current data object is the same as its parent and the request parameter 1148 // contains the parent field value 1149 if (StringUtils.equals(inquiryForm.getDataObjectClassName(), dictionaryObjectEntry) 1150 && ArrayUtils.contains(parameterValues, propertyValue.toString())) { 1151 return false; 1152 } 1153 } 1154 } 1155 1156 return object != null && KRADServiceLocatorWeb.getViewDictionaryService().isInquirable(object.getClass()); 1157 } 1158 1159}