001/**
002 * Copyright 2005-2018 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.apache.log4j.Logger;
020import org.kuali.rice.core.api.exception.RiceRuntimeException;
021import org.kuali.rice.krad.datadictionary.parse.BeanTag;
022import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
023import org.kuali.rice.krad.uif.UifConstants;
024import org.kuali.rice.krad.uif.component.Component;
025import org.kuali.rice.krad.uif.component.ComponentBase;
026import org.kuali.rice.krad.uif.component.ComponentSecurity;
027import org.kuali.rice.krad.uif.component.DelayedCopy;
028import org.kuali.rice.krad.uif.element.Label;
029import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
030import org.kuali.rice.krad.uif.util.ComponentFactory;
031import org.kuali.rice.krad.uif.util.LifecycleElement;
032import org.kuali.rice.krad.uif.util.MessageStructureUtils;
033import org.kuali.rice.krad.uif.view.View;
034import org.kuali.rice.krad.util.KRADUtils;
035
036import java.util.List;
037
038/**
039 * Base class for <code>Field</code> implementations
040 *
041 * <p>
042 * Sets the component type name so that all field templates have a fixed
043 * contract
044 * </p>
045 *
046 * <p>
047 * Holds a nested <code>Label</code> with configuration for rendering the
048 * label and configuration on label placement.
049 * </p>
050 *
051 * @author Kuali Rice Team (rice.collab@kuali.org)
052 */
053@BeanTag(name = "fieldBase", parent = "Uif-FieldBase")
054public class FieldBase extends ComponentBase implements Field {
055    private static final long serialVersionUID = -5888414844802862760L;
056    private static final Logger LOG = Logger.getLogger(FieldBase.class);
057
058    private String shortLabel;
059    
060    @DelayedCopy
061    private Label fieldLabel;
062
063    private boolean labelLeft;
064    private boolean labelRendered;
065
066    public FieldBase() {
067        super();
068
069        labelRendered = false;
070    }
071
072    /**
073     * The following finalization is performed:
074     *
075     * <ul>
076     * <li>Make sure that a label is defined for any data fields. If not then create hidden label using property
077     * name.</li>
078     * <li>If no label for a non data field then just log a warning.</li>
079     * </ul>
080     *
081     * {@inheritDoc}
082     */
083    @Override
084    public void performApplyModel(Object model, LifecycleElement parent) {
085        super.performApplyModel(model, parent);
086
087        if (!labelRendered && fieldLabel == null) {
088            if (this instanceof DataFieldBase) {
089                LOG.warn("DataField ("
090                        + this.getClass().getName()
091                        + ") ID: "
092                        + this.getId()
093                        + ", propertyName: "
094                        + ((DataFieldBase) this).getPropertyName()
095                        + " has no label. A hidden default label will be created.");
096                this.setLabel(((DataFieldBase) this).getPropertyName());
097                this.setLabelRendered(false);
098                this.setShowLabel(true);
099            } else {
100                if (this instanceof SpaceField == false) {
101                    LOG.warn("Field (" + this.getClass().getName() + ") ID: " + this.getId() + " has no label.");
102                }
103            }
104        }
105    }
106    
107    /**
108     * {@inheritDoc}
109     */
110    @Override
111    public void afterEvaluateExpression() {
112        super.afterEvaluateExpression();
113     
114        if (getReadOnly() == null) {
115            Component parent = ViewLifecycle.getPhase().getParent();
116            setReadOnly(parent == null ? null : parent.getReadOnly());
117        }
118    }
119
120    /**
121     * The following finalization is performed:
122     *
123     * <ul>
124     * <li>Set the labelForComponentId to this component id</li>
125     * <li>Set the label text on the label field from the field's label property</li>
126     * <li>Set the render property on the label's required message field if this field is marked as required</li>
127     * </ul>
128     *
129     * {@inheritDoc}
130     */
131    @Override
132    public void performFinalize(Object model, LifecycleElement parent) {
133        super.performFinalize(model, parent);
134
135        if (fieldLabel != null) {
136            fieldLabel.setLabelForComponentId(this.getId());
137
138            if ((getRequired() != null) && getRequired().booleanValue()) {
139                View view = ViewLifecycle.getView();
140                if (view.getViewTypeName() != null && view.getViewTypeName().equals(
141                        UifConstants.ViewType.MAINTENANCE)) {
142                    fieldLabel.setRenderRequiredIndicator(!Boolean.TRUE.equals(view.getReadOnly()));
143                } else {
144                    fieldLabel.setRenderRequiredIndicator(!Boolean.TRUE.equals(getReadOnly()));
145                }
146            } else {
147                setRequired(false);
148                fieldLabel.setRenderRequiredIndicator(false);
149            }
150
151            if (labelLeft) {
152                fieldLabel.addStyleClass("uif-labelLeft");
153            }
154            else {
155                fieldLabel.addStyleClass("uif-labelBlock");
156            }
157
158            fieldLabel.addDataAttribute(UifConstants.DataAttributes.LABEL_FOR, this.getId());
159            if (StringUtils.isNotBlank(this.getFieldLabel().getLabelText())) {
160                this.addDataAttribute(UifConstants.DataAttributes.LABEL, MessageStructureUtils.translateStringMessage(
161                        this.getFieldLabel().getLabelText()));
162            }
163        }
164
165        // set up script to add omit data so this field will not be posted on form submit
166        if (isOmitFromFormPost()) {
167            this.addDataAttribute(UifConstants.DataAttributes.OMIT_FROM_POST, "true");
168        }
169    }
170
171    /**
172     * Helper method for suffixing the ids of the fields nested components
173     *
174     * @param component component to adjust id for
175     * @param suffix suffix to append to id
176     */
177    protected void setNestedComponentIdAndSuffix(Component component, String suffix) {
178        if (component != null) {
179            String fieldId = getId();
180            fieldId += suffix;
181
182            component.setId(fieldId);
183        }
184    }
185
186    /**
187     * {@inheritDoc}
188     */
189    @Override
190    public final String getComponentTypeName() {
191        return "field";
192    }
193
194    /**
195     * @see org.kuali.rice.krad.uif.field.Field#getLabel
196     */
197    @BeanTagAttribute
198    public String getLabel() {
199        if (fieldLabel != null) {
200            return fieldLabel.getLabelText();
201        }
202
203        return "";
204    }
205
206    /**
207     * @see org.kuali.rice.krad.uif.field.Field#setLabel(java.lang.String)
208     */
209    public void setLabel(String labelText) {
210        if (StringUtils.isNotBlank(labelText) && this.fieldLabel == null) {
211            this.fieldLabel = ComponentFactory.getLabel();
212        }
213
214        if (this.fieldLabel != null) {
215            this.fieldLabel.setLabelText(labelText);
216        }
217    }
218
219    /**
220     * @see org.kuali.rice.krad.uif.field.Field#getLabelStyleClasses
221     */
222    @BeanTagAttribute
223    public List<String> getLabelStyleClasses() {
224        if (fieldLabel != null) {
225            return fieldLabel.getCssClasses();
226        }
227
228        return null;
229    }
230
231    /**
232     * @see org.kuali.rice.krad.uif.field.Field#setLabelStyleClasses
233     */
234    public void setLabelStyleClasses(List<String> labelStyleClasses) {
235        if (labelStyleClasses != null && this.fieldLabel == null) {
236            this.fieldLabel = ComponentFactory.getLabel();
237        }
238
239        if (this.fieldLabel != null) {
240            this.fieldLabel.setCssClasses(labelStyleClasses);
241        }
242    }
243
244    /**
245     * @see org.kuali.rice.krad.uif.field.Field#getLabelColSpan
246     */
247    @BeanTagAttribute
248    public int getLabelColSpan() {
249        if (fieldLabel != null) {
250            return fieldLabel.getColSpan();
251        }
252
253        return 1;
254    }
255
256    /**
257     * @see org.kuali.rice.krad.uif.field.Field#setLabelColSpan
258     */
259    public void setLabelColSpan(int labelColSpan) {
260        if (this.fieldLabel == null) {
261            this.fieldLabel = ComponentFactory.getLabel();
262        }
263
264        if (this.fieldLabel != null) {
265            this.fieldLabel.setColSpan(labelColSpan);
266        }
267    }
268
269    /**
270     * @see org.kuali.rice.krad.uif.field.Field#getShortLabel()
271     */
272    @BeanTagAttribute
273    public String getShortLabel() {
274        return this.shortLabel;
275    }
276
277    /**
278     * @see org.kuali.rice.krad.uif.field.Field#setShortLabel(java.lang.String)
279     */
280    public void setShortLabel(String shortLabel) {
281        this.shortLabel = shortLabel;
282    }
283
284    /**
285     * Sets whether the label should be displayed
286     *
287     * <p>
288     * Convenience method for configuration that sets the hidden indicator on
289     * the fields <code>Label</code> instance. The label is not really hidden
290     * but set off screen for accessibility.
291     * </p>
292     *
293     * @param showLabel true if label should be hidden, false if the label
294     * should not be hidden
295     */
296    public void setShowLabel(boolean showLabel) {
297        if (fieldLabel != null) {
298            fieldLabel.setHidden(showLabel);
299        }
300    }
301
302    /**
303     * @see org.kuali.rice.krad.uif.field.Field#getLabel
304     */
305    @BeanTagAttribute
306    public Label getFieldLabel() {
307        return this.fieldLabel;
308    }
309
310    /**
311     * @see org.kuali.rice.krad.uif.field.Field#setFieldLabel
312     */
313    public void setFieldLabel(Label fieldLabel) {
314        this.fieldLabel = fieldLabel;
315    }
316
317    /**
318     * {@inheritDoc}
319     */
320    @Override
321    @BeanTagAttribute
322    public boolean isLabelLeft() {
323        return labelLeft;
324    }
325
326    /**
327     * {@inheritDoc}
328     */
329    @Override
330    public void setLabelLeft(boolean labelLeft) {
331        this.labelLeft = labelLeft;
332    }
333
334    /**
335     * @see org.kuali.rice.krad.uif.field.Field#isLabelRendered()
336     */
337    @BeanTagAttribute
338    public boolean isLabelRendered() {
339        return this.labelRendered;
340    }
341
342    /**
343     * @see org.kuali.rice.krad.uif.field.Field#setLabelRendered(boolean)
344     */
345    public void setLabelRendered(boolean labelRendered) {
346        this.labelRendered = labelRendered;
347    }
348
349    /**
350     * @see org.kuali.rice.krad.uif.field.Field#getFieldSecurity()
351     */
352    public FieldSecurity getFieldSecurity() {
353        return (FieldSecurity) super.getComponentSecurity();
354    }
355
356    /**
357     * Override to assert a {@link FieldSecurity} instance is set
358     *
359     * @param componentSecurity instance of FieldSecurity
360     */
361    @Override
362    public void setComponentSecurity(ComponentSecurity componentSecurity) {
363        if ((componentSecurity != null) && !(componentSecurity instanceof FieldSecurity)) {
364            throw new RiceRuntimeException("Component security for Field should be instance of FieldSecurity");
365        }
366
367        super.setComponentSecurity(componentSecurity);
368    }
369
370    /**
371     * {@inheritDoc}
372     */
373    @Override
374    protected void initializeComponentSecurity() {
375        if (getComponentSecurity() == null) {
376            setComponentSecurity(KRADUtils.createNewObjectFromClass(FieldSecurity.class));
377        }
378    }
379
380    /**
381     * @see org.kuali.rice.krad.uif.field.FieldSecurity#isEditInLineAuthz()
382     */
383    @BeanTagAttribute
384    public Boolean isEditInLineAuthz() {
385        initializeComponentSecurity();
386
387        return getFieldSecurity().isEditInLineAuthz();
388    }
389
390    /**
391     * @see org.kuali.rice.krad.uif.field.FieldSecurity#setEditInLineAuthz(Boolean)
392     */
393    public void setEditInLineAuthz(Boolean editInLineAuthz) {
394        initializeComponentSecurity();
395
396        getFieldSecurity().setEditInLineAuthz(editInLineAuthz);
397    }
398
399    /**
400     * @see org.kuali.rice.krad.uif.field.FieldSecurity#isViewInLineAuthz()
401     */
402    @BeanTagAttribute
403    public Boolean isViewInLineAuthz() {
404        initializeComponentSecurity();
405
406        return getFieldSecurity().isViewInLineAuthz();
407    }
408
409    /**
410     * @see org.kuali.rice.krad.uif.field.FieldSecurity#setViewInLineAuthz(Boolean)
411     */
412    public void setViewInLineAuthz(Boolean viewInLineAuthz) {
413        initializeComponentSecurity();
414
415        getFieldSecurity().setViewInLineAuthz(viewInLineAuthz);
416    }
417
418}