View Javadoc

1   /**
2    * Copyright 2005-2013 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.exception.RiceRuntimeException;
20  import org.kuali.rice.krad.bo.DataObjectRelationship;
21  import org.kuali.rice.krad.bo.KualiCode;
22  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
23  import org.kuali.rice.krad.datadictionary.mask.MaskFormatter;
24  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
25  import org.kuali.rice.krad.uif.component.BindingInfo;
26  import org.kuali.rice.krad.uif.component.Component;
27  import org.kuali.rice.krad.uif.component.ComponentSecurity;
28  import org.kuali.rice.krad.uif.component.DataBinding;
29  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
30  import org.kuali.rice.krad.uif.util.ViewModelUtils;
31  import org.kuali.rice.krad.uif.view.View;
32  import org.kuali.rice.krad.uif.widget.Inquiry;
33  import org.kuali.rice.krad.util.KRADPropertyConstants;
34  import org.kuali.rice.krad.util.ObjectUtils;
35  import org.kuali.rice.krad.valuefinder.ValueFinder;
36  
37  import java.beans.PropertyEditor;
38  import java.util.ArrayList;
39  import java.util.List;
40  
41  /**
42   * Field that renders data from the application, such as the value of a data object property
43   *
44   * @author Kuali Rice Team (rice.collab@kuali.org)
45   */
46  public class DataField extends FieldBase implements DataBinding {
47      private static final long serialVersionUID = -4129678891948564724L;
48  
49      // binding
50      private String propertyName;
51      private BindingInfo bindingInfo;
52  
53      private String dictionaryAttributeName;
54      private String dictionaryObjectEntry;
55  
56      // value props
57      private String defaultValue;
58      private Class<? extends ValueFinder> defaultValueFinderClass;
59  
60      private PropertyEditor propertyEditor;
61  
62      private boolean readOnlyHidden;
63  
64      // alternate and additional display properties
65      protected String alternateDisplayPropertyName;
66      protected String additionalDisplayPropertyName;
67  
68      private String alternateDisplayValue;
69      private String additionalDisplayValue;
70  
71      private boolean applyValueMask;
72      private MaskFormatter maskFormatter;
73  
74      private List<String> hiddenPropertyNames;
75      private List<String> informationalDisplayPropertyNames;
76  
77      private boolean escapeHtmlInPropertyValue = true;
78  
79      private String helpSummary;
80      private String helpDescription;
81  
82      // widgets
83      private Inquiry fieldInquiry;
84  
85      public DataField() {
86          super();
87  
88          readOnlyHidden = false;
89          applyValueMask = false;
90  
91          hiddenPropertyNames = new ArrayList<String>();
92          informationalDisplayPropertyNames = new ArrayList<String>();
93      }
94  
95      /**
96       * The following initialization is performed:
97       *
98       * <ul>
99       * <li>Set defaults for binding</li>
100      * <li>Default the model path if not set</li>
101      * </ul>
102      *
103      * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View,
104      *      java.lang.Object)
105      */
106     @Override
107     public void performInitialization(View view, Object model) {
108         super.performInitialization(view, model);
109 
110         if (bindingInfo != null) {
111             bindingInfo.setDefaults(view, getPropertyName());
112         }
113     }
114 
115     /**
116      * The following updates are done here:
117      *
118      * <ul>
119      * <li>If readOnlyHidden set to true, set field to readonly and add to hidden property names</li>
120      * </ul>
121      */
122     public void performApplyModel(View view, Object model, Component parent) {
123         super.performApplyModel(view, model, parent);
124 
125         if (isReadOnlyHidden()) {
126             setReadOnly(true);
127             getHiddenPropertyNames().add(getPropertyName());
128         }
129     }
130 
131     /**
132      * The following actions are performed:
133      *
134      * <ul>
135      * <li>Set the ids for the various attribute components</li>
136      * <li>Sets up the client side validation for constraints on this field. In
137      * addition, it sets up the messages applied to this field</li>
138      * </ul>
139      *
140      * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
141      *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
142      */
143     @Override
144     public void performFinalize(View view, Object model, Component parent) {
145         super.performFinalize(view, model, parent);
146 
147         // adjust the path for hidden fields
148         // TODO: should this check the view#readOnly?
149         List<String> hiddenPropertyPaths = new ArrayList<String>();
150         for (String hiddenPropertyName : getHiddenPropertyNames()) {
151             String hiddenPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(hiddenPropertyName);
152             hiddenPropertyPaths.add(hiddenPropertyPath);
153         }
154         this.hiddenPropertyNames = hiddenPropertyPaths;
155 
156         // adjust paths on informational property names
157         List<String> informationalPropertyPaths = new ArrayList<String>();
158         for (String infoPropertyName : getInformationalDisplayPropertyNames()) {
159             String infoPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(infoPropertyName);
160             informationalPropertyPaths.add(infoPropertyPath);
161         }
162         this.informationalDisplayPropertyNames = informationalPropertyPaths;
163 
164         // Additional and Alternate display value
165         setAlternateAndAdditionalDisplayValue(view, model);
166     }
167 
168     /**
169      * Sets alternate and additional property value for this field.
170      *
171      * <p>
172      * If <code>AttributeSecurity</code> present in this field, make sure the current user has permission to view the
173      * field value. If user doesn't have permission to view the value, mask the value as configured and set it
174      * as alternate value for display. If security doesn't exists for this field but
175      * <code>alternateDisplayPropertyName</code> present, get its value and format it based on that
176      * fields formatting and set for display.
177      * </p>
178      *
179      * <p>
180      * For additional display value, if <code>AttributeSecurity</code> not present, sets the value if
181      * <code>additionalDisplayPropertyName</code> present. If not present, check whether this field is a
182      * <code>KualiCode</code> and get the relationship configured in the datadictionary file and set the name
183      * additional display value which will be displayed along with the code. If additional display property not
184      * present, check whether this field is has <code>MultiValueControlBase</code>. If yes, get the Label
185      * for the value and set it as additional display value.
186      * </p>
187      *
188      * @param view - the current view instance
189      * @param model - model instance
190      */
191     protected void setAlternateAndAdditionalDisplayValue(View view, Object model) {
192         // if alternate or additional display values set don't use property names
193         if (StringUtils.isNotBlank(alternateDisplayValue) || StringUtils.isNotBlank(additionalDisplayValue)) {
194             return;
195         }
196 
197         // check whether field value needs to be masked, and if so apply masking as alternateDisplayValue
198         if (isApplyValueMask()) {
199             Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, getBindingInfo().getBindingPath());
200             alternateDisplayValue = getMaskFormatter().maskValue(fieldValue);
201 
202             // mask values are forced to be readonly
203             setReadOnly(true);
204             return;
205         }
206 
207         // if not read only, return without trying to set alternate and additional values
208         if (!isReadOnly()) {
209             return;
210         }
211 
212         // if field is not secure, check for alternate and additional display properties
213         if (StringUtils.isNotBlank(getAlternateDisplayPropertyName())) {
214             String alternateDisplayPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(
215                     getAlternateDisplayPropertyName());
216 
217             Object alternateFieldValue = ObjectPropertyUtils.getPropertyValue(model, alternateDisplayPropertyPath);
218             if (alternateFieldValue != null) {
219                 // TODO: format by type
220                 alternateDisplayValue = alternateFieldValue.toString();
221             }
222         }
223 
224         // perform automatic translation for code references if enabled on view
225         if (StringUtils.isBlank(getAdditionalDisplayPropertyName()) && view.isTranslateCodes()) {
226             // check for any relationship present for this field and it's of type KualiCode
227             Class<?> parentObjectClass = ViewModelUtils.getParentObjectClassForMetadata(view, model, this);
228             DataObjectRelationship relationship =
229                     KRADServiceLocatorWeb.getDataObjectMetaDataService().getDataObjectRelationship(null,
230                             parentObjectClass, getBindingInfo().getBindingName(), "", true, false, false);
231 
232             if (relationship != null
233                     && getPropertyName().startsWith(relationship.getParentAttributeName())
234                     && KualiCode.class.isAssignableFrom(relationship.getRelatedClass())) {
235                 additionalDisplayPropertyName =
236                         relationship.getParentAttributeName() + "." + KRADPropertyConstants.NAME;
237             }
238         }
239 
240         // now check for an additional display property and if set get the value
241         if (StringUtils.isNotBlank(getAdditionalDisplayPropertyName())) {
242             String additionalDisplayPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(
243                     getAdditionalDisplayPropertyName());
244 
245             Object additionalFieldValue = ObjectPropertyUtils.getPropertyValue(model, additionalDisplayPropertyPath);
246             if (additionalFieldValue != null) {
247                 // TODO: format by type
248                 additionalDisplayValue = additionalFieldValue.toString();
249             }
250         }
251     }
252 
253     /**
254      * Defaults the properties of the <code>DataField</code> to the
255      * corresponding properties of its <code>AttributeDefinition</code>
256      * retrieved from the dictionary (if such an entry exists). If the field
257      * already contains a value for a property, the definitions value is not
258      * used.
259      *
260      * @param view - view instance the field belongs to
261      * @param attributeDefinition - AttributeDefinition instance the property values should be
262      * copied from
263      */
264     public void copyFromAttributeDefinition(View view, AttributeDefinition attributeDefinition) {
265         // label
266         if (StringUtils.isEmpty(getLabel())) {
267             setLabel(attributeDefinition.getLabel());
268         }
269 
270         // short label
271         if (StringUtils.isEmpty(getShortLabel())) {
272             setShortLabel(attributeDefinition.getShortLabel());
273         }
274 
275         // summary
276         if (StringUtils.isEmpty(getHelpSummary())) {
277             setHelpSummary(attributeDefinition.getSummary());
278         }
279 
280         // description
281         if (StringUtils.isEmpty(getHelpDescription())) {
282             setHelpDescription(attributeDefinition.getDescription());
283         }
284 
285         // security
286         if (getDataFieldSecurity().getAttributeSecurity() == null) {
287             getDataFieldSecurity().setAttributeSecurity(attributeDefinition.getAttributeSecurity());
288         }
289 
290         // alternate property name
291         if (getAlternateDisplayPropertyName() == null && StringUtils.isNotBlank(
292                 attributeDefinition.getAlternateDisplayAttributeName())) {
293             setAlternateDisplayPropertyName(attributeDefinition.getAlternateDisplayAttributeName());
294         }
295 
296         // additional property display name
297         if (getAdditionalDisplayPropertyName() == null && StringUtils.isNotBlank(
298                 attributeDefinition.getAdditionalDisplayAttributeName())) {
299             setAdditionalDisplayPropertyName(attributeDefinition.getAdditionalDisplayAttributeName());
300         }
301 
302         // property editor
303         if (getPropertyEditor() == null) {
304             setPropertyEditor(attributeDefinition.getPropertyEditor());
305         }
306     }
307 
308     /**
309      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
310      */
311     @Override
312     public List<Component> getComponentsForLifecycle() {
313         List<Component> components = super.getComponentsForLifecycle();
314 
315         components.add(fieldInquiry);
316 
317         return components;
318     }
319 
320     /**
321      * Indicates whether the data field instance allows input, subclasses should override and set to
322      * true if input is allowed
323      *
324      * @return boolean true if input is allowed, false if read only
325      */
326     public boolean isInputAllowed() {
327         return false;
328     }
329 
330     /**
331      * @see org.kuali.rice.krad.uif.component.DataBinding#getPropertyName()
332      */
333     public String getPropertyName() {
334         return this.propertyName;
335     }
336 
337     /**
338      * Setter for the component's property name
339      *
340      * @param propertyName
341      */
342     public void setPropertyName(String propertyName) {
343         this.propertyName = propertyName;
344     }
345 
346     /**
347      * Performs formatting of the field value for display and then converting the value back to its
348      * expected type from a string
349      *
350      * <p>
351      * Note property editors exist and are already registered for the basic Java types and the
352      * common Kuali types such as [@link KualiDecimal}. Registration with this property is only
353      * needed for custom property editors
354      * </p>
355      *
356      * @return PropertyEditor property editor instance to use for this field
357      */
358     public PropertyEditor getPropertyEditor() {
359         return propertyEditor;
360     }
361 
362     /**
363      * Setter for the custom property editor to use for the field
364      *
365      * @param propertyEditor
366      */
367     public void setPropertyEditor(PropertyEditor propertyEditor) {
368         this.propertyEditor = propertyEditor;
369     }
370 
371     /**
372      * Convenience setter for configuring a property editor by class
373      *
374      * @param propertyEditorClass
375      */
376     public void setPropertyEditorClass(Class<? extends PropertyEditor> propertyEditorClass) {
377         this.propertyEditor = ObjectUtils.newInstance(propertyEditorClass);
378     }
379 
380     /**
381      * @see org.kuali.rice.krad.uif.component.DataBinding#getBindingInfo()
382      */
383     public BindingInfo getBindingInfo() {
384         return this.bindingInfo;
385     }
386 
387     /**
388      * Setter for the field's binding info
389      *
390      * @param bindingInfo
391      */
392     public void setBindingInfo(BindingInfo bindingInfo) {
393         this.bindingInfo = bindingInfo;
394     }
395 
396     /**
397      * Name of the attribute within the data dictionary the attribute field is
398      * associated with
399      *
400      * <p>
401      * During the initialize phase for the <code>View</code>, properties for
402      * attribute fields are defaulted from a corresponding
403      * <code>AttributeDefinition</code> in the data dictionary. Based on the
404      * propertyName and parent object class the framework attempts will
405      * determine the attribute definition that is associated with the field and
406      * set this property. However this property can also be set in the fields
407      * configuration to use another dictionary attribute.
408      * </p>
409      *
410      * <p>
411      * The attribute name is used along with the dictionary object entry to find
412      * the <code>AttributeDefinition</code>
413      * </p>
414      *
415      * @return String attribute name
416      */
417     public String getDictionaryAttributeName() {
418         return this.dictionaryAttributeName;
419     }
420 
421     /**
422      * Setter for the dictionary attribute name
423      *
424      * @param dictionaryAttributeName
425      */
426     public void setDictionaryAttributeName(String dictionaryAttributeName) {
427         this.dictionaryAttributeName = dictionaryAttributeName;
428     }
429 
430     /**
431      * Object entry name in the data dictionary the associated attribute is
432      * apart of
433      *
434      * <p>
435      * During the initialize phase for the <code>View</code>, properties for
436      * attribute fields are defaulted from a corresponding
437      * <code>AttributeDefinition</code> in the data dictionary. Based on the
438      * parent object class the framework will determine the object entry for the
439      * associated attribute. However the object entry can be set in the field's
440      * configuration to use another object entry for the attribute
441      * </p>
442      *
443      * <p>
444      * The attribute name is used along with the dictionary object entry to find
445      * the <code>AttributeDefinition</code>
446      * </p>
447      *
448      * @return
449      */
450     public String getDictionaryObjectEntry() {
451         return this.dictionaryObjectEntry;
452     }
453 
454     /**
455      * Setter for the dictionary object entry
456      *
457      * @param dictionaryObjectEntry
458      */
459     public void setDictionaryObjectEntry(String dictionaryObjectEntry) {
460         this.dictionaryObjectEntry = dictionaryObjectEntry;
461     }
462 
463     /**
464      * Default value for the model property the field points to
465      *
466      * <p>
467      * When a new <code>View</code> instance is requested, the corresponding
468      * model will be newly created. During this initialization process the value
469      * for the model property will be set to the given default value (if set)
470      * </p>
471      *
472      * @return String default value
473      */
474     public String getDefaultValue() {
475         return this.defaultValue;
476     }
477 
478     /**
479      * Setter for the fields default value
480      *
481      * @param defaultValue
482      */
483     public void setDefaultValue(String defaultValue) {
484         this.defaultValue = defaultValue;
485     }
486 
487     /**
488      * Gives Class that should be invoked to produce the default value for the
489      * field
490      *
491      * @return Class<? extends ValueFinder> default value finder class
492      */
493     public Class<? extends ValueFinder> getDefaultValueFinderClass() {
494         return this.defaultValueFinderClass;
495     }
496 
497     /**
498      * Setter for the default value finder class
499      *
500      * @param defaultValueFinderClass
501      */
502     public void setDefaultValueFinderClass(Class<? extends ValueFinder> defaultValueFinderClass) {
503         this.defaultValueFinderClass = defaultValueFinderClass;
504     }
505 
506     /**
507      * Summary help text for the field
508      *
509      * @return String summary help text
510      */
511     public String getHelpSummary() {
512         return helpSummary;
513     }
514 
515     /**
516      * Setter for the summary help text
517      *
518      * @param helpSummary
519      */
520     public void setHelpSummary(String helpSummary) {
521         this.helpSummary = helpSummary;
522     }
523 
524     /**
525      * Full help information text for the field
526      *
527      * @return String help description text
528      */
529     public String getHelpDescription() {
530         return this.helpDescription;
531     }
532 
533     /**
534      * Setter for the help description text
535      *
536      * @param helpDescription
537      */
538     public void setHelpDescription(String helpDescription) {
539         this.helpDescription = helpDescription;
540     }
541 
542     /**
543      * Data Field Security object that indicates what authorization (permissions) exist for the field
544      *
545      * @return DataFieldSecurity instance
546      */
547     public DataFieldSecurity getDataFieldSecurity() {
548         return (DataFieldSecurity) super.getComponentSecurity();
549     }
550 
551     /**
552      * Override to assert a {@link DataFieldSecurity} instance is set
553      *
554      * @param componentSecurity - instance of DataFieldSecurity
555      */
556     @Override
557     public void setComponentSecurity(ComponentSecurity componentSecurity) {
558         if (!(componentSecurity instanceof DataFieldSecurity)) {
559             throw new RiceRuntimeException("Component security for DataField should be instance of DataFieldSecurity");
560         }
561 
562         super.setComponentSecurity(componentSecurity);
563     }
564 
565     @Override
566     protected Class<? extends ComponentSecurity> getComponentSecurityClass() {
567         return DataFieldSecurity.class;
568     }
569 
570     /**
571      * Indicates the field should be read-only but also a hidden should be generated for the field
572      *
573      * <p>
574      * Useful for when a value is just displayed but is needed by script
575      * </p>
576      *
577      * @return boolean true if field should be readOnly hidden, false if not
578      */
579     public boolean isReadOnlyHidden() {
580         return readOnlyHidden;
581     }
582 
583     /**
584      * Setter for the read-only hidden indicator
585      *
586      * @param readOnlyHidden
587      */
588     public void setReadOnlyHidden(boolean readOnlyHidden) {
589         this.readOnlyHidden = readOnlyHidden;
590     }
591 
592     /**
593      * Inquiry widget for the field
594      *
595      * <p>
596      * The inquiry widget will render a link for the field value when read-only
597      * that points to the associated inquiry view for the field. The inquiry can
598      * be configured to point to a certain <code>InquiryView</code>, or the
599      * framework will attempt to associate the field with a inquiry based on its
600      * metadata (in particular its relationships in the model)
601      * </p>
602      *
603      * @return Inquiry field inquiry
604      */
605     public Inquiry getFieldInquiry() {
606         return this.fieldInquiry;
607     }
608 
609     /**
610      * Setter for the inquiry widget
611      *
612      * @param fieldInquiry
613      */
614     public void setFieldInquiry(Inquiry fieldInquiry) {
615         this.fieldInquiry = fieldInquiry;
616     }
617 
618     /**
619      * Additional display attribute name, which will be displayed next to the actual field value
620      * when the field is readonly with hypen inbetween like PropertyValue - AdditionalPropertyValue
621      *
622      * @param additionalDisplayPropertyName - Name of the additional display property
623      */
624     public void setAdditionalDisplayPropertyName(String additionalDisplayPropertyName) {
625         this.additionalDisplayPropertyName = additionalDisplayPropertyName;
626     }
627 
628     /**
629      * Returns the additional display attribute name to be displayed when the field is readonly
630      *
631      * @return Additional Display Attribute Name
632      */
633     public String getAdditionalDisplayPropertyName() {
634         return this.additionalDisplayPropertyName;
635     }
636 
637     /**
638      * Sets the alternate display attribute name to be displayed when the field is readonly.
639      * This properties value will be displayed instead of actual fields value when the field is readonly.
640      *
641      * @param alternateDisplayPropertyName - alternate display property name
642      */
643     public void setAlternateDisplayPropertyName(String alternateDisplayPropertyName) {
644         this.alternateDisplayPropertyName = alternateDisplayPropertyName;
645     }
646 
647     /**
648      * Returns the alternate display attribute name to be displayed when the field is readonly.
649      *
650      * @return alternate Display Property Name
651      */
652     public String getAlternateDisplayPropertyName() {
653         return this.alternateDisplayPropertyName;
654     }
655 
656     /**
657      * Returns the alternate display value
658      *
659      * @return the alternate display value set for this field
660      */
661     public String getAlternateDisplayValue() {
662         return alternateDisplayValue;
663     }
664 
665     /**
666      * Setter for the alternative display value
667      *
668      * @param value
669      */
670     public void setAlternateDisplayValue(String value) {
671         this.alternateDisplayValue = value;
672     }
673 
674     /**
675      * Returns the additional display value.
676      *
677      * @return the additional display value set for this field
678      */
679     public String getAdditionalDisplayValue() {
680         return additionalDisplayValue;
681     }
682 
683     /**
684      * Setter for the additional display value
685      *
686      * @param value
687      */
688     public void setAdditionalDisplayValue(String value) {
689         this.additionalDisplayValue = value;
690     }
691 
692     /**
693      * Indicates whether the value for the field should be masked (or partially masked) on display
694      *
695      * <p>
696      * If set to true, the field value will be masked by applying the configured {@link #getMaskFormatter()}
697      * </p>
698      *
699      * <p>
700      * If a KIM permission exists that should be checked to determine whether the value should be masked or not,
701      * this value should not be set but instead the mask or partialMask property on {@link #getComponentSecurity()}
702      * should be set to true. This indicates there is a mask permission that should be consulted. If the user
703      * does not have the permission, this flag will be set to true by the framework and the value masked using
704      * the mask formatter configured on the security object
705      * </p>
706      *
707      * @return boolean true if the field value should be masked, false if not
708      */
709     public boolean isApplyValueMask() {
710         return applyValueMask;
711     }
712 
713     /**
714      * Setter for the apply value mask flag
715      *
716      * @param applyValueMask
717      */
718     public void setApplyValueMask(boolean applyValueMask) {
719         this.applyValueMask = applyValueMask;
720     }
721 
722     /**
723      * MaskFormatter instance that will be used to mask the field value when {@link #isApplyValueMask()} is true
724      *
725      * <p>
726      * Note in cases where the mask is applied due to security (KIM permissions), the mask or partial mask formatter
727      * configured on {@link #getComponentSecurity()} will be used instead of this mask formatter
728      * </p>
729      *
730      * @return MaskFormatter instance
731      */
732     public MaskFormatter getMaskFormatter() {
733         return maskFormatter;
734     }
735 
736     /**
737      * Setter for the MaskFormatter instance to apply when the value is masked
738      *
739      * @param maskFormatter
740      */
741     public void setMaskFormatter(MaskFormatter maskFormatter) {
742         this.maskFormatter = maskFormatter;
743     }
744 
745     /**
746      * Allows specifying hidden property names without having to specify as a
747      * field in the group config (that might impact layout)
748      *
749      * @return List<String> hidden property names
750      */
751     public List<String> getHiddenPropertyNames() {
752         return hiddenPropertyNames;
753     }
754 
755     /**
756      * Setter for the hidden property names
757      *
758      * @param hiddenPropertyNames
759      */
760     public void setHiddenPropertyNames(List<String> hiddenPropertyNames) {
761         this.hiddenPropertyNames = hiddenPropertyNames;
762     }
763 
764     /**
765      * List of property names whose values should be displayed read-only under this field
766      *
767      * <p>
768      * In the attribute field template for each information property name given its values is
769      * outputted read-only. Informational property values can also be updated dynamically with
770      * the use of field attribute query
771      * </p>
772      *
773      * <p>
774      * Simple property names can be given if the property has the same binding parent as this
775      * field, in which case the binding path will be adjusted by the framework. If the property
776      * names starts with org.kuali.rice.krad.uif.UifConstants#NO_BIND_ADJUST_PREFIX, no binding
777      * prefix will be added.
778      * </p>
779      *
780      * @return List<String> informational property names
781      */
782     public List<String> getInformationalDisplayPropertyNames() {
783         return informationalDisplayPropertyNames;
784     }
785 
786     /**
787      * Setter for the list of informational property names
788      *
789      * @param informationalDisplayPropertyNames
790      */
791     public void setInformationalDisplayPropertyNames(List<String> informationalDisplayPropertyNames) {
792         this.informationalDisplayPropertyNames = informationalDisplayPropertyNames;
793     }
794 
795     /**
796      * Sets HTML escaping for this property value. HTML escaping will be handled in alternate and additional fields
797      * also.
798      */
799     public void setEscapeHtmlInPropertyValue(boolean escapeHtmlInPropertyValue) {
800         this.escapeHtmlInPropertyValue = escapeHtmlInPropertyValue;
801     }
802 
803     /**
804      * Returns true if HTML escape allowed for this field
805      *
806      * @return true if escaping allowed
807      */
808     public boolean isEscapeHtmlInPropertyValue() {
809         return this.escapeHtmlInPropertyValue;
810     }
811 
812     /**
813      * Indicates whether the value for the field is secure
814      *
815      * <p>
816      * A value will be secured if masking has been applied (by configuration or a failed KIM permission) or the field
817      * has been marked as hidden due to an authorization check
818      * </p>
819      *
820      * @return boolean true if value is secure, false if not
821      */
822     public boolean hasSecureValue() {
823         return isApplyValueMask() || ((getComponentSecurity().isViewAuthz()
824                 || getDataFieldSecurity().isViewInLineAuthz()
825                 || ((getDataFieldSecurity().getAttributeSecurity() != null) && getDataFieldSecurity()
826                 .getAttributeSecurity().isHide())) && isHidden());
827     }
828 
829 }