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 }