001    /**
002     * Copyright 2005-2013 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     */
016    package org.kuali.rice.krad.uif.element;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.datadictionary.parse.BeanTag;
020    import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
021    import org.kuali.rice.krad.datadictionary.parse.BeanTags;
022    import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
023    import org.kuali.rice.krad.datadictionary.validator.Validator;
024    import org.kuali.rice.krad.uif.component.Component;
025    import org.kuali.rice.krad.uif.container.Group;
026    import org.kuali.rice.krad.uif.util.ComponentFactory;
027    import org.kuali.rice.krad.uif.view.View;
028    import org.kuali.rice.krad.util.KRADConstants;
029    
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    /**
034     * Content element that renders a header element and optionally a <code>Group</code> to
035     * present along with the header text
036     *
037     * <p>
038     * Generally the group is used to display content to the right of the header,
039     * such as links for the group or other information
040     * </p>
041     *
042     * @author Kuali Rice Team (rice.collab@kuali.org)
043     */
044    @BeanTags({@BeanTag(name = "header-bean", parent = "Uif-HeaderBase"), @BeanTag(name = "headerOne-bean", parent = "Uif-HeaderOne"),
045            @BeanTag(name = "headerTwo-bean", parent = "Uif-HeaderTwo"),
046            @BeanTag(name = "headerThree-bean", parent = "Uif-HeaderThree"),
047            @BeanTag(name = "headerFour-bean", parent = "Uif-HeaderFour"),
048            @BeanTag(name = "headerFive-bean", parent = "Uif-HeaderFive"),
049            @BeanTag(name = "headerSix-bean", parent = "Uif-HeaderSix"),
050            @BeanTag(name = "viewHeader-bean", parent = "Uif-ViewHeader"),
051            @BeanTag(name = "pageHeader-bean", parent = "Uif-PageHeader"),
052            @BeanTag(name = "sectionHeader-bean", parent = "Uif-SectionHeader"),
053            @BeanTag(name = "subSectionHeader-bean", parent = "Uif-SubSectionHeader"),
054            @BeanTag(name = "subCollectionHeader-bean", parent = "Uif-SubCollectionHeader"),
055            @BeanTag(name = "editablePageHeader-bean", parent = "Uif-EditablePageHeader"),
056            @BeanTag(name = "readOnlyPageHeader-bean", parent = "Uif-ReadOnlyPageHeader"),
057            @BeanTag(name = "imageCaptionHeader-bean", parent = "Uif-ImageCaptionHeader"),
058            @BeanTag(name = "documentViewHeader-bean", parent = "Uif-DocumentViewHeader"),
059            @BeanTag(name = "lookupPageHeader-bean", parent = "Uif-LookupPageHeader")})
060    public class Header extends ContentElementBase {
061        private static final long serialVersionUID = -6950408292923393244L;
062    
063        private String headerText;
064        private String headerLevel;
065    
066        private String headerTagStyle;
067        private List<String> headerTagCssClasses;
068    
069        private Message richHeaderMessage;
070        private List<Component> inlineComponents;
071    
072        private Group upperGroup;
073        private Group rightGroup;
074        private Group lowerGroup;
075    
076        public Header() {
077            super();
078    
079            headerTagCssClasses = new ArrayList<String>();
080        }
081    
082        /**
083         * Sets up rich message content for the label, if any exists
084         *
085         * @see Component#performApplyModel(org.kuali.rice.krad.uif.view.View, Object,
086         *      org.kuali.rice.krad.uif.component.Component)
087         */
088        @Override
089        public void performApplyModel(View view, Object model, Component parent) {
090            super.performApplyModel(view, model, parent);
091    
092            if (richHeaderMessage == null && headerText != null && headerText.contains(
093                    KRADConstants.MessageParsing.LEFT_TOKEN) && headerText.contains(
094                    KRADConstants.MessageParsing.RIGHT_TOKEN)) {
095                Message message = ComponentFactory.getMessage();
096                view.assignComponentIds(message);
097                message.setMessageText(headerText);
098                message.setInlineComponents(inlineComponents);
099                message.setGenerateSpan(false);
100                view.getViewHelperService().performComponentInitialization(view, model, message);
101                this.setRichHeaderMessage(message);
102            }
103        }
104    
105        /**
106         * The following finalization is performed:
107         *
108         * <ul>
109         * <li>Set render on header group to false if no items are configured</li>
110         * </ul>
111         *
112         * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
113         *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
114         */
115        @Override
116        public void performFinalize(View view, Object model, Component parent) {
117            super.performFinalize(view, model, parent);
118    
119            // don't render header groups if no items were configured
120            if ((getUpperGroup() != null) && (getUpperGroup().getItems().isEmpty())) {
121                getUpperGroup().setRender(false);
122            }
123    
124            if ((getRightGroup() != null) && (getRightGroup().getItems().isEmpty())) {
125                getRightGroup().setRender(false);
126            }
127    
128            if ((getLowerGroup() != null) && (getLowerGroup().getItems().isEmpty())) {
129                getLowerGroup().setRender(false);
130            }
131    
132            //add preset styles to header groups
133            if (getUpperGroup() != null) {
134                getUpperGroup().addStyleClass("uif-header-upperGroup");
135            }
136    
137            if (getRightGroup() != null) {
138                getRightGroup().addStyleClass("uif-header-rightGroup");
139            }
140    
141            if (getLowerGroup() != null) {
142                getLowerGroup().addStyleClass("uif-header-lowerGroup");
143            }
144        }
145    
146        /**
147         * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
148         */
149        @Override
150        public List<Component> getComponentsForLifecycle() {
151            List<Component> components = super.getComponentsForLifecycle();
152    
153            components.add(richHeaderMessage);
154            components.add(upperGroup);
155            components.add(rightGroup);
156            components.add(lowerGroup);
157    
158            return components;
159        }
160    
161        /**
162         * Text that should be displayed on the header
163         *
164         * @return String header text
165         */
166        @BeanTagAttribute(name = "headerText")
167        public String getHeaderText() {
168            return this.headerText;
169        }
170    
171        /**
172         * Setter for the header text
173         *
174         * @param headerText
175         */
176        public void setHeaderText(String headerText) {
177            this.headerText = headerText;
178        }
179    
180        /**
181         * HTML header level (h1 ... h6) that should be applied to the header text
182         *
183         * @return String header level
184         */
185        @BeanTagAttribute(name = "headerLevel")
186        public String getHeaderLevel() {
187            return this.headerLevel;
188        }
189    
190        /**
191         * Setter for the header level
192         *
193         * @param headerLevel
194         */
195        public void setHeaderLevel(String headerLevel) {
196            this.headerLevel = headerLevel;
197        }
198    
199        /**
200         * Style classes that should be applied to the header text (h tag)
201         *
202         * <p>
203         * Note the style class given here applies to only the header text. The
204         * style class property inherited from the <code>Component</code> interface
205         * can be used to set the class for the whole field div (which could
206         * include a nested <code>Group</code>)
207         * </p>
208         *
209         * @return List<String> list of style classes
210         * @see org.kuali.rice.krad.uif.component.Component#getCssClasses()
211         */
212        @BeanTagAttribute(name = "headerTagCssClasses", type = BeanTagAttribute.AttributeType.LISTVALUE)
213        public List<String> getHeaderTagCssClasses() {
214            return this.headerTagCssClasses;
215        }
216    
217        /**
218         * Setter for the list of classes to apply to the header h tag
219         *
220         * @param headerTagCssClasses
221         */
222        public void setHeaderTagCssClasses(List<String> headerTagCssClasses) {
223            this.headerTagCssClasses = headerTagCssClasses;
224        }
225    
226        /**
227         * Builds the HTML class attribute string by combining the headerStyleClasses list
228         * with a space delimiter
229         *
230         * @return String class attribute string
231         */
232        public String getHeaderStyleClassesAsString() {
233            if (headerTagCssClasses != null) {
234                return StringUtils.join(headerTagCssClasses, " ");
235            }
236    
237            return "";
238        }
239    
240        /**
241         * Style that should be applied to the header h tag
242         *
243         * <p>
244         * Note the style given here applies to only the header text. The style
245         * property inherited from the <code>Component</code> interface can be used
246         * to set the style for the whole header div (which could include a nested
247         * <code>Group</code>)
248         * </p>
249         *
250         * @return String header style
251         * @see org.kuali.rice.krad.uif.component.Component#getStyle()
252         */
253        @BeanTagAttribute(name = "headerTagStyle")
254        public String getHeaderTagStyle() {
255            return this.headerTagStyle;
256        }
257    
258        /**
259         * Setter for the header h tag style
260         *
261         * @param headerTagStyle
262         */
263        public void setHeaderTagStyle(String headerTagStyle) {
264            this.headerTagStyle = headerTagStyle;
265        }
266    
267        /**
268         * Nested group instance that can be used to render contents above the header text
269         *
270         * <p>
271         * The header group is useful for adding content such as links or actions that is presented with the header
272         * </p>
273         *
274         * @return Group instance
275         */
276        @BeanTagAttribute(name = "upperGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
277        public Group getUpperGroup() {
278            return upperGroup;
279        }
280    
281        /**
282         * Setter for the header group instance that is rendered above the header text
283         *
284         * @param upperGroup
285         */
286        public void setUpperGroup(Group upperGroup) {
287            this.upperGroup = upperGroup;
288        }
289    
290        /**
291         * Nested group instance that can be used to render contents to the right of the header text
292         *
293         * <p>
294         * The header group is useful for adding content such as links or actions that is presented with the header
295         * </p>
296         *
297         * @return Group instance
298         */
299        @BeanTagAttribute(name = "rightGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
300        public Group getRightGroup() {
301            return rightGroup;
302        }
303    
304        /**
305         * Setter for the header group instance that is rendered to the right of the header text
306         *
307         * @param rightGroup
308         */
309        public void setRightGroup(Group rightGroup) {
310            this.rightGroup = rightGroup;
311        }
312    
313        /**
314         * Nested group instance that can be used to render contents below the header text
315         *
316         * <p>
317         * The header group is useful for adding content such as links or actions that is presented with the header
318         * </p>
319         *
320         * @return Group instance
321         */
322        @BeanTagAttribute(name = "lowerGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
323        public Group getLowerGroup() {
324            return lowerGroup;
325        }
326    
327        /**
328         * Setter for the header group instance that is rendered below the header text
329         *
330         * @param lowerGroup
331         */
332        public void setLowerGroup(Group lowerGroup) {
333            this.lowerGroup = lowerGroup;
334        }
335    
336        /**
337         * List of <code>Component</code> instances contained in the lower header group
338         *
339         * <p>
340         * Convenience method for configuration to get the items List from the
341         * lower header group
342         * </p>
343         *
344         * @return List<? extends Component> items
345         */
346        @BeanTagAttribute(name = "items", type = BeanTagAttribute.AttributeType.LISTBEAN)
347        public List<? extends Component> getItems() {
348            if (lowerGroup != null) {
349                return lowerGroup.getItems();
350            }
351    
352            return null;
353        }
354    
355        /**
356         * Setter for the lower group's items
357         *
358         * <p>
359         * Convenience method for configuration to set the items List for the
360         * lower header group
361         * </p>
362         *
363         * @param items
364         */
365        public void setItems(List<? extends Component> items) {
366            if (lowerGroup != null) {
367                lowerGroup.setItems(items);
368            }
369        }
370    
371        /**
372         * @see org.kuali.rice.krad.uif.component.Component#completeValidation
373         */
374        @Override
375        public void completeValidation(ValidationTrace tracer) {
376            tracer.addBean(this);
377    
378            // Checks that a correct header level is set
379            String headerLevel = getHeaderLevel().toUpperCase();
380            boolean correctHeaderLevel = false;
381            if (headerLevel.compareTo("H1") == 0) {
382                correctHeaderLevel = true;
383            } else if (headerLevel.compareTo("H2") == 0) {
384                correctHeaderLevel = true;
385            } else if (headerLevel.compareTo("H3") == 0) {
386                correctHeaderLevel = true;
387            } else if (headerLevel.compareTo("H4") == 0) {
388                correctHeaderLevel = true;
389            } else if (headerLevel.compareTo("H5") == 0) {
390                correctHeaderLevel = true;
391            } else if (headerLevel.compareTo("H6") == 0) {
392                correctHeaderLevel = true;
393            } else if (headerLevel.compareTo("LABEL") == 0) {
394                correctHeaderLevel = true;
395            }
396            if (!correctHeaderLevel) {
397                String currentValues[] = {"headerLevel =" + getHeaderLevel()};
398                tracer.createError("HeaderLevel must be of values h1, h2, h3, h4, h5, h6, or label", currentValues);
399            }
400    
401            // Checks that header text is set
402            if (getHeaderText() == null) {
403                if (!Validator.checkExpressions(this, "headerText")) {
404                    String currentValues[] = {"headertText =" + getHeaderText()};
405                    tracer.createWarning("HeaderText should be set", currentValues);
406                }
407            }
408    
409            super.completeValidation(tracer.getCopy());
410        }
411    
412        /**
413         * Gets the Message that represents the rich message content of the header if headerText is using rich message
414         * tags.
415         * <b>DO NOT set this
416         * property directly unless you need full control over the message structure.</b>
417         *
418         * @return Message with rich message structure, null if no rich message structure
419         */
420        @BeanTagAttribute(name = "richHeaderMessage", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
421        public Message getRichHeaderMessage() {
422            return richHeaderMessage;
423        }
424    
425        /**
426         * Sets the Message that represents the rich message content of the header if headerText is using rich message
427         * tags.
428         * <b>DO
429         * NOT set this
430         * property directly unless you need full control over the message structure.</b>
431         *
432         * @param richHeaderMessage
433         */
434        public void setRichHeaderMessage(Message richHeaderMessage) {
435            this.richHeaderMessage = richHeaderMessage;
436        }
437    
438        /**
439         * Gets the inlineComponents used by index in a Header that has rich message component index tags in its headerText
440         *
441         * @return the Label's inlineComponents
442         */
443        @BeanTagAttribute(name = "inlineComponents", type = BeanTagAttribute.AttributeType.LISTBEAN)
444        public List<Component> getInlineComponents() {
445            return inlineComponents;
446        }
447    
448        /**
449         * Sets the inlineComponents used by index in a Header that has rich message component index tags in its headerText
450         *
451         * @param inlineComponents
452         */
453        public void setInlineComponents(List<Component> inlineComponents) {
454            this.inlineComponents = inlineComponents;
455        }
456    }