001 /** 002 * Copyright 2005-2014 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.layout; 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.uif.component.Component; 022 import org.kuali.rice.krad.uif.container.Container; 023 import org.kuali.rice.krad.uif.element.Label; 024 import org.kuali.rice.krad.uif.field.Field; 025 import org.kuali.rice.krad.uif.field.InputField; 026 import org.kuali.rice.krad.uif.util.LifecycleElement; 027 import org.kuali.rice.krad.util.KRADUtils; 028 029 import java.util.ArrayList; 030 import java.util.List; 031 032 /** 033 * A Css Grid Layout which only takes fields as its content and separates out the field's labels into 034 * separate columns 035 * 036 * <p>This layout does not use the container's items' colspan property to influence column size.</p> 037 * 038 * @author Kuali Rice Team (rice.collab@kuali.org) 039 */ 040 @BeanTag(name = "cssGridLabelColumnLayout-bean", parent = "Uif-CssGridLabelColumnLayout") 041 public class CssGridLabelColumnLayoutManager extends CssGridLayoutManagerBase { 042 private static final long serialVersionUID = 3100360397450755904L; 043 044 private int numberOfLabelColumns = 1; 045 private String labelColumnCssClass = ""; 046 047 /** 048 * CssGridLabelColumnLayoutManager's performFinalize method calculates and separates the items into rows 049 * 050 * {@inheritDoc} 051 */ 052 @Override 053 public void performFinalize(Object model, LifecycleElement component) { 054 super.performFinalize(model, component); 055 056 Container container = (Container) component; 057 processSeparateLabelLayout(container); 058 } 059 060 /** 061 * Separates the labels and field content into the appropriate number of rows and div "cells" based on 062 * the numberOfLabelColumns property, by making making labels take up their own column and turning off rendering 063 * them for the fields 064 * 065 * @param container the container using this layout manager 066 */ 067 private void processSeparateLabelLayout(Container container) { 068 int labelColumnSize = 3; 069 int fieldColumnSize = 9; 070 if (numberOfLabelColumns > 1) { 071 labelColumnSize = (NUMBER_OF_COLUMNS / numberOfLabelColumns) * 1 / 3; 072 fieldColumnSize = (NUMBER_OF_COLUMNS / numberOfLabelColumns) * 2 / 3; 073 } 074 int itemNumber = 0; 075 int rowIndex = 0; 076 boolean isOdd = true; 077 078 List<Component> currentRow = new ArrayList<Component>(); 079 for (Component item : container.getItems()) { 080 if (!(item instanceof Field)) { 081 throw new RuntimeException("Must use fields when separateFieldLabelsIntoColumns option is " 082 + "true for CssGridLayouts. Item class: " 083 + item.getClass().getName() 084 + 085 " in Container id: " 086 + container.getId()); 087 } 088 089 isOdd = rowIndex % 2 == 0; 090 Field field = (Field) item; 091 Label label; 092 093 // pull out label field 094 if (field.getFieldLabel() != null) { 095 field.getFieldLabel().addStyleClass("displayWith-" + field.getId()); 096 if (!field.isRender() && StringUtils.isBlank(field.getProgressiveRender())) { 097 field.getFieldLabel().setRender(false); 098 } else if (!field.isRender() && StringUtils.isNotBlank(field.getProgressiveRender())) { 099 field.getFieldLabel().setRender(true); 100 String prefixStyle = ""; 101 if (StringUtils.isNotBlank(field.getFieldLabel().getStyle())) { 102 prefixStyle = field.getFieldLabel().getStyle(); 103 } 104 field.getFieldLabel().setStyle(prefixStyle + ";" + "display: none;"); 105 } 106 107 label = field.getFieldLabel(); 108 109 /* if (field instanceof InputField && field.getRequired() != null && field.getRequired()) { 110 label.setRenderRequiredIndicator(true); 111 }*/ 112 113 // set boolean to indicate label field should not be 114 // rendered with the attribute 115 field.setLabelRendered(true); 116 } else { 117 throw new RuntimeException("Label must exist on fields in CssGridLabelColumnLayoutManager. Item class: " 118 + item.getClass().getName() 119 + " in Container id: " 120 + container.getId()); 121 } 122 123 // Determine "cell" label div css and add it to cellCssClassAttributes (retrieved by index in template) 124 List<String> cellCssClasses = label.getWrapperCssClasses(); 125 if (cellCssClasses == null) { 126 label.setWrapperCssClasses(new ArrayList<String>()); 127 cellCssClasses = label.getWrapperCssClasses(); 128 } 129 cellCssClasses.add(0, labelColumnCssClass); 130 cellCssClasses.add(0, BOOTSTRAP_SPAN_PREFIX + labelColumnSize); 131 cellCssClassAttributes.add(getCellStyleClassesAsString(cellCssClasses)); 132 133 // Add label 134 currentRow.add(label); 135 136 // Determine "cell" field div css and add it to cellCssClassAttributes (retrieved by index in template) 137 cellCssClasses = field.getWrapperCssClasses(); 138 if (cellCssClasses == null) { 139 field.setWrapperCssClasses(new ArrayList<String>()); 140 cellCssClasses = field.getWrapperCssClasses(); 141 } 142 cellCssClasses.add(0, BOOTSTRAP_SPAN_PREFIX + fieldColumnSize); 143 cellCssClassAttributes.add(getCellStyleClassesAsString(cellCssClasses)); 144 145 // Add field 146 currentRow.add(field); 147 148 itemNumber++; 149 if (itemNumber == numberOfLabelColumns) { 150 rows.add(new ArrayList<Component>(currentRow)); 151 currentRow = new ArrayList<Component>(); 152 153 // Determine "row" div css 154 String rowCss = rowLayoutCssClass + " " + KRADUtils.generateRowCssClassString(conditionalRowCssClasses, 155 rowIndex, isOdd, null, null); 156 rowCssClassAttributes.add(rowCss); 157 158 itemNumber = 0; 159 rowIndex++; 160 } 161 } 162 163 // Add any extra fields that do not take up a full row 164 if (itemNumber > 0) { 165 // Determine "row" div css 166 String rowCss = rowLayoutCssClass + " " + KRADUtils.generateRowCssClassString(conditionalRowCssClasses, 167 rowIndex, isOdd, null, null); 168 rowCssClassAttributes.add(rowCss); 169 170 rows.add(currentRow); 171 } 172 } 173 174 /** 175 * The css class to use on the label column's div "cells" 176 * 177 * @return the css class to use on label column div "cells" 178 */ 179 @BeanTagAttribute(name = "labelColumnCssClass") 180 public String getLabelColumnCssClass() { 181 return labelColumnCssClass; 182 } 183 184 /** 185 * Setter for {@link #getLabelColumnCssClass()}. 186 * 187 * @param labelColumnCssClass property value 188 */ 189 public void setLabelColumnCssClass(String labelColumnCssClass) { 190 this.labelColumnCssClass = labelColumnCssClass; 191 } 192 193 /** 194 * The number of label columns used in this layout 195 * 196 * <p> 197 * The only supported values for this property are 1-3 which translates to 2-6 columns per a 198 * row. This property defines how many of the total columns are label columns. 199 * </p> 200 * 201 * @return the total number of label columns 202 */ 203 @BeanTagAttribute(name = "numberOfLabelColumns") 204 public int getNumberOfLabelColumns() { 205 return numberOfLabelColumns; 206 } 207 208 /** 209 * Setter for {@link #getNumberOfLabelColumns()}. 210 * 211 * @param numberOfLabelColumns property value 212 */ 213 public void setNumberOfLabelColumns(int numberOfLabelColumns) { 214 this.numberOfLabelColumns = numberOfLabelColumns; 215 } 216 217 }