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