View Javadoc
1   /**
2    * Copyright 2005-2014 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.element;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.List;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
24  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
25  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
26  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
27  import org.kuali.rice.krad.datadictionary.validator.Validator;
28  import org.kuali.rice.krad.uif.UifConstants;
29  import org.kuali.rice.krad.uif.component.Component;
30  import org.kuali.rice.krad.uif.container.Group;
31  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleRestriction;
32  import org.kuali.rice.krad.uif.util.ComponentFactory;
33  import org.kuali.rice.krad.uif.util.ComponentUtils;
34  import org.kuali.rice.krad.uif.util.LifecycleElement;
35  import org.kuali.rice.krad.uif.view.View;
36  import org.kuali.rice.krad.uif.widget.Help;
37  import org.kuali.rice.krad.uif.util.LifecycleElement;
38  import org.kuali.rice.krad.util.KRADConstants;
39  
40  /**
41   * Content element that renders a header element and optionally a <code>Group</code> to
42   * present along with the header text
43   *
44   * <p>
45   * Generally the group is used to display content to the right of the header,
46   * such as links for the group or other information
47   * </p>
48   *
49   * @author Kuali Rice Team (rice.collab@kuali.org)
50   */
51  @BeanTags({@BeanTag(name = "header-bean", parent = "Uif-HeaderBase"), @BeanTag(name = "headerOne-bean", parent = "Uif-HeaderOne"),
52          @BeanTag(name = "headerTwo-bean", parent = "Uif-HeaderTwo"),
53          @BeanTag(name = "headerThree-bean", parent = "Uif-HeaderThree"),
54          @BeanTag(name = "headerFour-bean", parent = "Uif-HeaderFour"),
55          @BeanTag(name = "headerFive-bean", parent = "Uif-HeaderFive"),
56          @BeanTag(name = "headerSix-bean", parent = "Uif-HeaderSix"),
57          @BeanTag(name = "pageHeader-bean", parent = "Uif-PageHeader"),
58          @BeanTag(name = "sectionHeader-bean", parent = "Uif-SectionHeader"),
59          @BeanTag(name = "subSectionHeader-bean", parent = "Uif-SubSectionHeader"),
60          @BeanTag(name = "subCollectionHeader-bean", parent = "Uif-SubCollectionHeader"),
61          @BeanTag(name = "editablePageHeader-bean", parent = "Uif-EditablePageHeader"),
62          @BeanTag(name = "readOnlyPageHeader-bean", parent = "Uif-ReadOnlyPageHeader"),
63          @BeanTag(name = "imageCaptionHeader-bean", parent = "Uif-ImageCaptionHeader"),
64          @BeanTag(name = "documentViewHeader-bean", parent = "Uif-DocumentViewHeader"),
65          @BeanTag(name = "lookupPageHeader-bean", parent = "Uif-LookupPageHeader")})
66  public class Header extends ContentElementBase {
67      private static final long serialVersionUID = -6950408292923393244L;
68  
69      private String headerText;
70      private String headerLevel;
71  
72      private String headerTagStyle;
73      private List<String> headerTagCssClasses;
74      private boolean headerTagOnly;
75  
76      private Message richHeaderMessage;
77      private List<Component> inlineComponents;
78  
79      private Group upperGroup;
80      private Group rightGroup;
81      private Group lowerGroup;
82  
83      private boolean renderWrapper;
84  
85      public Header() {
86          super();
87  
88          headerTagCssClasses = new ArrayList<String>();
89          renderWrapper = true;
90      }
91  
92      /**
93       * Sets up rich message content for the label, if any exists
94       *
95       * {@inheritDoc}
96       */
97      @Override
98      public void performApplyModel(Object model, LifecycleElement parent) {
99          super.performApplyModel(model, parent);
100 
101         if (richHeaderMessage == null && headerText != null && headerText.contains(
102                 KRADConstants.MessageParsing.LEFT_TOKEN) && headerText.contains(
103                 KRADConstants.MessageParsing.RIGHT_TOKEN)) {
104             Message message = ComponentFactory.getMessage();
105             message.setMessageText(headerText);
106             message.setInlineComponents(inlineComponents);
107             message.setRenderWrapperTag(false);
108             
109             this.setRichHeaderMessage(message);
110         }
111     }
112 
113     /**
114      * The following finalization is performed:
115      *
116      * <ul>
117      * <li>Set render on header group to false if no items are configured</li>
118      * </ul>
119      *
120      * {@inheritDoc}
121      */
122     @Override
123     public void performFinalize(Object model, LifecycleElement parent) {
124         super.performFinalize(model, parent);
125 
126         // don't render header groups if no items were configured
127         if ((getUpperGroup() != null) && (getUpperGroup().getItems().isEmpty())) {
128             getUpperGroup().setRender(false);
129         }
130 
131         if ((getRightGroup() != null) && (getRightGroup().getItems().isEmpty())) {
132             getRightGroup().setRender(false);
133         }
134 
135         if ((getLowerGroup() != null) && (getLowerGroup().getItems().isEmpty())) {
136             getLowerGroup().setRender(false);
137         }
138 
139         //add preset styles to header groups
140         if (getUpperGroup() != null) {
141             getUpperGroup().addStyleClass("uif-header-upperGroup");
142         }
143 
144         if (getRightGroup() != null) {
145             getRightGroup().addStyleClass("uif-header-rightGroup");
146         }
147 
148         if (getLowerGroup() != null) {
149             getLowerGroup().addStyleClass("uif-header-lowerGroup");
150         }
151     }
152 
153     /**
154      * {@inheritDoc}
155      */
156     @Override
157     public List<String> getAdditionalTemplates() {
158         List<String> additionalTemplates = super.getAdditionalTemplates();
159 
160         Object parent = getContext().get(UifConstants.ContextVariableNames.PARENT);
161         
162         Help help = null;
163         if (parent instanceof Group) {
164             help = ((Group) parent).getHelp();
165         } else if (parent instanceof View) {
166             help = ((View) parent).getHelp();
167         }
168         
169         if (help != null) {
170             String helpTemplate = help.getTemplate();
171             if (additionalTemplates.isEmpty()) {
172                 additionalTemplates = new ArrayList<String>();
173             }
174             additionalTemplates.add(helpTemplate);
175         }
176         
177         return additionalTemplates;
178     }
179 
180     /**
181      * Text that should be displayed on the header
182      *
183      * @return header text
184      */
185     @BeanTagAttribute(name = "headerText")
186     public String getHeaderText() {
187         return this.headerText;
188     }
189 
190     /**
191      * Setter for the header text
192      *
193      * @param headerText
194      */
195     public void setHeaderText(String headerText) {
196         this.headerText = headerText;
197     }
198 
199     /**
200      * HTML header level (h1 ... h6) that should be applied to the header text
201      *
202      * @return header level
203      */
204     @BeanTagAttribute(name = "headerLevel")
205     public String getHeaderLevel() {
206         return this.headerLevel;
207     }
208 
209     /**
210      * Setter for the header level
211      *
212      * @param headerLevel
213      */
214     public void setHeaderLevel(String headerLevel) {
215         this.headerLevel = headerLevel;
216     }
217 
218     /**
219      * Style classes that should be applied to the header text (h tag)
220      *
221      * <p>
222      * Note the style class given here applies to only the header text. The
223      * style class property inherited from the <code>Component</code> interface
224      * can be used to set the class for the whole field div (which could
225      * include a nested <code>Group</code>)
226      * </p>
227      *
228      * @return list of style classes
229      * @see org.kuali.rice.krad.uif.component.Component#getCssClasses()
230      */
231     @BeanTagAttribute(name = "headerTagCssClasses", type = BeanTagAttribute.AttributeType.LISTVALUE)
232     public List<String> getHeaderTagCssClasses() {
233         return this.headerTagCssClasses;
234     }
235 
236     /**
237      * Setter for the list of classes to apply to the header h tag
238      *
239      * @param headerTagCssClasses
240      */
241     public void setHeaderTagCssClasses(List<String> headerTagCssClasses) {
242         this.headerTagCssClasses = headerTagCssClasses;
243     }
244 
245     /**
246      * Builds the HTML class attribute string by combining the headerStyleClasses list
247      * with a space delimiter
248      *
249      * @return class attribute string
250      */
251     public String getHeaderStyleClassesAsString() {
252         if (headerTagCssClasses != null) {
253             return StringUtils.join(headerTagCssClasses, " ");
254         }
255 
256         return "";
257     }
258 
259     /**
260      * Style that should be applied to the header h tag
261      *
262      * <p>
263      * Note the style given here applies to only the header text. The style
264      * property inherited from the <code>Component</code> interface can be used
265      * to set the style for the whole header div (which could include a nested
266      * <code>Group</code>)
267      * </p>
268      *
269      * @return header style
270      * @see org.kuali.rice.krad.uif.component.Component#getStyle()
271      */
272     @BeanTagAttribute(name = "headerTagStyle")
273     public String getHeaderTagStyle() {
274         return this.headerTagStyle;
275     }
276 
277     /**
278      * Setter for the header h tag style
279      *
280      * @param headerTagStyle
281      */
282     public void setHeaderTagStyle(String headerTagStyle) {
283         this.headerTagStyle = headerTagStyle;
284     }
285 
286     public boolean isHeaderTagOnly() {
287         return headerTagOnly;
288     }
289 
290     public void setHeaderTagOnly(boolean headerTagOnly) {
291         this.headerTagOnly = headerTagOnly;
292     }
293 
294     /**
295      * Nested group instance that can be used to render contents above the header text
296      *
297      * <p>
298      * The header group is useful for adding content such as links or actions that is presented with the header
299      * </p>
300      *
301      * @return Group instance
302      */
303     @BeanTagAttribute(name = "upperGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
304     public Group getUpperGroup() {
305         return upperGroup;
306     }
307 
308     /**
309      * Setter for the header group instance that is rendered above the header text
310      *
311      * @param upperGroup
312      */
313     public void setUpperGroup(Group upperGroup) {
314         this.upperGroup = upperGroup;
315     }
316 
317     /**
318      * Nested group instance that can be used to render contents to the right of the header text
319      *
320      * <p>
321      * The header group is useful for adding content such as links or actions that is presented with the header
322      * </p>
323      *
324      * @return Group instance
325      */
326     @BeanTagAttribute(name = "rightGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
327     public Group getRightGroup() {
328         return rightGroup;
329     }
330 
331     /**
332      * Setter for the header group instance that is rendered to the right of the header text
333      *
334      * @param rightGroup
335      */
336     public void setRightGroup(Group rightGroup) {
337         this.rightGroup = rightGroup;
338     }
339 
340     /**
341      * Nested group instance that can be used to render contents below the header text
342      *
343      * <p>
344      * The header group is useful for adding content such as links or actions that is presented with the header
345      * </p>
346      *
347      * @return Group instance
348      */
349     @BeanTagAttribute(name = "lowerGroup", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
350     public Group getLowerGroup() {
351         return lowerGroup;
352     }
353 
354     /**
355      * Setter for the header group instance that is rendered below the header text
356      *
357      * @param lowerGroup
358      */
359     public void setLowerGroup(Group lowerGroup) {
360         this.lowerGroup = lowerGroup;
361     }
362 
363     /**
364      * List of <code>Component</code> instances contained in the lower header group
365      *
366      * <p>
367      * Convenience method for configuration to get the items List from the
368      * lower header group
369      * </p>
370      *
371      * @return List<? extends Component> items
372      */
373     @ViewLifecycleRestriction
374     @BeanTagAttribute(name = "items", type = BeanTagAttribute.AttributeType.LISTBEAN)
375     public List<? extends Component> getItems() {
376         if (lowerGroup != null) {
377             return lowerGroup.getItems();
378         }
379 
380         return null;
381     }
382 
383     /**
384      * Setter for the lower group's items
385      *
386      * <p>
387      * Convenience method for configuration to set the items List for the
388      * lower header group
389      * </p>
390      *
391      * @param items
392      */
393     public void setItems(List<? extends Component> items) {
394         if (lowerGroup != null) {
395             lowerGroup.setItems(items);
396         }
397     }
398 
399     /**
400      * Gets the Message that represents the rich message content of the header if headerText is using rich message
401      * tags.
402      * <b>DO NOT set this
403      * property directly unless you need full control over the message structure.</b>
404      *
405      * @return rich message structure, null if no rich message structure
406      */
407     @BeanTagAttribute(name = "richHeaderMessage", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
408     public Message getRichHeaderMessage() {
409         return richHeaderMessage;
410     }
411 
412     /**
413      * Sets the Message that represents the rich message content of the header if headerText is using rich message
414      * tags.
415      * <b>DO
416      * NOT set this
417      * property directly unless you need full control over the message structure.</b>
418      *
419      * @param richHeaderMessage
420      */
421     public void setRichHeaderMessage(Message richHeaderMessage) {
422         this.richHeaderMessage = richHeaderMessage;
423     }
424 
425     /**
426      * Gets the inlineComponents used by index in a Header that has rich message component index tags in its headerText
427      *
428      * @return the Label's inlineComponents
429      */
430     @BeanTagAttribute(name = "inlineComponents", type = BeanTagAttribute.AttributeType.LISTBEAN)
431     public List<Component> getInlineComponents() {
432         return inlineComponents;
433     }
434 
435     /**
436      * Sets the inlineComponents used by index in a Header that has rich message component index tags in its headerText
437      *
438      * @param inlineComponents
439      */
440     public void setInlineComponents(List<Component> inlineComponents) {
441         this.inlineComponents = inlineComponents;
442     }
443 
444     /**
445      * {@inheritDoc}
446      */
447     @Override
448     public void completeValidation(ValidationTrace tracer) {
449         tracer.addBean(this);
450 
451         // Checks that a correct header level is set
452         String headerLevel = getHeaderLevel().toUpperCase();
453         boolean correctHeaderLevel = false;
454         if (headerLevel.compareTo("H1") == 0) {
455             correctHeaderLevel = true;
456         } else if (headerLevel.compareTo("H2") == 0) {
457             correctHeaderLevel = true;
458         } else if (headerLevel.compareTo("H3") == 0) {
459             correctHeaderLevel = true;
460         } else if (headerLevel.compareTo("H4") == 0) {
461             correctHeaderLevel = true;
462         } else if (headerLevel.compareTo("H5") == 0) {
463             correctHeaderLevel = true;
464         } else if (headerLevel.compareTo("H6") == 0) {
465             correctHeaderLevel = true;
466         } else if (headerLevel.compareTo("LABEL") == 0) {
467             correctHeaderLevel = true;
468         }
469         if (!correctHeaderLevel) {
470             String currentValues[] = {"headerLevel =" + getHeaderLevel()};
471             tracer.createError("HeaderLevel must be of values h1, h2, h3, h4, h5, h6, or label", currentValues);
472         }
473 
474         // Checks that header text is set
475         if (getHeaderText() == null) {
476             if (!Validator.checkExpressions(this, "headerText")) {
477                 String currentValues[] = {"headertText =" + getHeaderText()};
478                 tracer.createWarning("HeaderText should be set", currentValues);
479             }
480         }
481 
482         super.completeValidation(tracer.getCopy());
483     }
484 }