001    /*
002     * Copyright 2011 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.kfs.sys.document.web;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    import java.util.Map;
021    import java.util.Set;
022    
023    import org.kuali.kfs.sys.businessobject.AccountingLine;
024    import org.kuali.kfs.sys.document.AccountingDocument;
025    import org.kuali.kfs.sys.document.datadictionary.AccountingLineViewColumnsDefinition;
026    import org.kuali.kfs.sys.document.service.AccountingLineFieldRenderingTransformation;
027    
028    /**
029     * A layout element that renders elements 
030     */
031    public class AccountingLineViewColumns implements AccountingLineViewLineFillingElement {
032        private List<AccountingLineViewField> fields;
033        private AccountingLineViewColumnsDefinition definition;
034        
035        /**
036         * Constructs a AccountingLineViewColumns
037         * @param definition the data dictionary validation of this columns layout element
038         * @param fields the fields to render within this columns layout element
039         */
040        public AccountingLineViewColumns(AccountingLineViewColumnsDefinition definition, List<AccountingLineViewField> fields) {
041            this.definition = definition;
042            this.fields = fields;
043        }
044    
045        /**
046         * Returns the name of this element
047         * @see org.kuali.kfs.sys.document.web.TableJoining#getName()
048         */
049        public String getName() {
050            return definition.getName();
051        }
052    
053        /**
054         * 
055         * @see org.kuali.kfs.sys.document.web.TableJoining#getRequestedRowCount()
056         */
057        public int getRequestedRowCount() {
058            return 1;
059        }
060    
061        /**
062         * This element should be stretched
063         * @see org.kuali.kfs.sys.document.web.AccountingLineViewLineFillingElement#stretchToFillLine()
064         */
065        public boolean shouldStretchToFillLine() {
066            return true;
067        }
068    
069        /**
070         * Joins the header row with a line filling cell, which includes within it an inner table that shows all the child fields
071         * @see org.kuali.kfs.sys.document.web.TableJoining#joinRow(org.kuali.kfs.sys.document.web.AccountingLineTableRow, org.kuali.kfs.sys.document.web.AccountingLineTableRow)
072         */
073        public void joinRow(AccountingLineTableRow headerLabelRow, AccountingLineTableRow row) {
074            AccountingLineTableCell cell = new AccountingLineTableCell();
075    
076            AccountingLineTable columnsTable = new AccountingLineTable();
077    
078            List<AccountingLineTableRow> rows = createRowsForFields();
079            
080            columnsTable.setRows(rows);
081            cell.addRenderableElement(columnsTable);
082            headerLabelRow.addCell(cell);
083        }
084        
085        /**
086         * Creates rows for the inner tables for each field inside this columsn definition
087         * @return a List of created AccountingLineTableRows
088         */
089        protected List<AccountingLineTableRow> createRowsForFields() {
090            List<AccountingLineTableRow> rows = new ArrayList<AccountingLineTableRow>();
091            
092            int countForThisRow = 0;
093            AccountingLineTableRow row = new AccountingLineTableRow();
094            for (AccountingLineViewField field : fields) {
095                row.addCell(createHeaderCellForField(field));
096                row.addCell(createCellForField(field));
097                countForThisRow += 1;
098                
099                if (countForThisRow == definition.getColumnCount()) {
100                    rows.add(row);
101                    countForThisRow = 0;
102                    row = new AccountingLineTableRow();
103                }
104            }
105            if (countForThisRow > 0) { // oops! we stopped mid-row and now need to fill it out
106                while (countForThisRow < definition.getColumnCount()) {
107                    row.addCell(createPaddingCell());
108                    countForThisRow += 1;
109                }
110                rows.add(row);
111            }
112            
113            return rows;
114        }
115        
116        /**
117         * Creates a header cell for for the given field 
118         * @param field the field to create a header cell for
119         * @return a header cell
120         */
121        protected AccountingLineTableCell createHeaderCellForField(AccountingLineViewField field) {
122            AccountingLineTableCell headerCell = new AccountingLineTableCell();
123            headerCell.setRendersAsHeader(true);
124            headerCell.addRenderableElement(field.createHeaderLabel());
125            return headerCell;
126        }
127        
128        /**
129         * Creates the "field" cell for the given field
130         * @param field the field to create a cell for
131         * @return the cell withe field in it
132         */
133        protected AccountingLineTableCell createCellForField(AccountingLineViewField field) {
134            AccountingLineTableCell cell = new AccountingLineTableCell();
135            cell.addRenderableElement(field);
136            return cell;
137        }
138        
139        /**
140         * Creates an empty cell to pad out the place typically held for a cell
141         * @return an empty table cell that spans two columns
142         */
143        protected AccountingLineTableCell createPaddingCell() {
144            AccountingLineTableCell cell = new AccountingLineTableCell();
145            cell.setColSpan(2);
146            cell.setNeverEmpty(true);
147            return cell;
148        }
149    
150        /**
151         * An exception state; line filling elements can only join tables through lines 
152         * @see org.kuali.kfs.sys.document.web.TableJoining#joinTable(java.util.List)
153         */
154        public void joinTable(List<AccountingLineTableRow> rows) {
155            throw new IllegalStateException("Line elements may not join a table directly; the specified rendering is incorrect");
156        }
157    
158        /**
159         * Has fields perform the transformations
160         * @see org.kuali.kfs.sys.document.web.TableJoining#performFieldTransformations(java.util.List, org.kuali.kfs.sys.businessobject.AccountingLine, java.util.Map, java.util.Map)
161         */
162        public void performFieldTransformations(List<AccountingLineFieldRenderingTransformation> fieldTransformations, AccountingLine accountingLine, Map unconvertedValues) {
163            int count = 0;
164            for (AccountingLineViewField field : fields) {
165                for (AccountingLineFieldRenderingTransformation transformation : fieldTransformations) {
166                    transformation.transformField(accountingLine, field.getField(), field.getDefinition(), unconvertedValues);
167                }
168            }
169        }
170    
171        /**
172         * Removes any child action blocks; surviving blocks are instructed to remove child blocks they have
173         * @see org.kuali.kfs.sys.document.web.TableJoining#removeAllActionBlocks()
174         */
175        public void removeAllActionBlocks() {
176            List<AccountingLineViewField> fieldsToRemove = new ArrayList<AccountingLineViewField>();
177            for (AccountingLineViewField field : fields) {
178                if (field.isActionBlock()) {
179                    fieldsToRemove.add(field);
180                } else {
181                    field.removeAllActionBlocks();
182                }
183            }
184            fields.removeAll(fieldsToRemove);
185        }
186    
187        /**
188         * Goes through all child fields; removes any fields which match unviewable blocks or otherwise, has the field remove unviewable blocks
189         * @see org.kuali.kfs.sys.document.web.TableJoining#removeUnviewableBlocks(java.util.Set)
190         */
191        public void removeUnviewableBlocks(Set<String> unviewableBlocks) {
192            List<AccountingLineViewField> unviewableFields = new ArrayList<AccountingLineViewField>();
193            for (AccountingLineViewField field : fields) {
194                if (unviewableBlocks.contains(field.getName())) {
195                    unviewableFields.add(field);
196                } else {
197                    field.removeUnviewableBlocks(unviewableBlocks);
198                }
199            }
200            fields.removeAll(unviewableFields);
201        }
202    
203        /**
204         * Has each field readOnlyize
205         * @see org.kuali.kfs.sys.document.web.TableJoining#readOnlyizeReadOnlyBlocks(java.util.Set)
206         */
207        public void readOnlyizeReadOnlyBlocks(Set<String> readOnlyBlocks) {
208            for (AccountingLineViewField field : fields) {
209                field.readOnlyizeReadOnlyBlocks(readOnlyBlocks);
210            }
211        }
212    
213        /**
214         * Gets the fields attribute. 
215         * @return Returns the fields.
216         */
217        public List<AccountingLineViewField> getFields() {
218            return fields;
219        }
220    
221        /**
222         * Sets the fields attribute value.
223         * @param fields The fields to set.
224         */
225        public void setFields(List<AccountingLineViewField> fields) {
226            this.fields = fields;
227        }
228    
229        /**
230         * @see org.kuali.kfs.sys.document.web.ReadOnlyable#isReadOnly()
231         */
232        public boolean isReadOnly() {
233            for (AccountingLineViewField field : fields) {
234                if (!field.isReadOnly()) return false;
235            }
236            return true;
237        }
238    
239        /**
240         * @see org.kuali.kfs.sys.document.web.ReadOnlyable#readOnlyize()
241         */
242        public void readOnlyize() {
243            for (AccountingLineViewField field : fields) {
244                field.readOnlyize();
245            }
246        }
247    
248        /**
249         * Always returns 1; this will build an inner table in one cell
250         * @see org.kuali.kfs.sys.document.web.AccountingLineViewLineFillingElement#getDisplayingFieldWidth()
251         */
252        public int getDisplayingFieldWidth() {
253            return 1;
254        }
255    
256        /**
257         * @see org.kuali.kfs.sys.document.web.TableJoining#setEditableBlocks(java.util.Set)
258         */
259        public void setEditableBlocks(Set<String> editableBlocks) {
260            for (AccountingLineViewField field : fields) {
261                field.setEditableBlocks(editableBlocks);
262            }
263        }
264    
265        /**
266         * @see org.kuali.kfs.sys.document.web.ReadOnlyable#setEditable()
267         */
268        public void setEditable() {
269            for (AccountingLineViewField field : fields) {
270                field.setEditable();
271            }
272        }
273    
274    }