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    }