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.HashSet;
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.datadictionary.AccountingLineViewLinesDefinition;
025    import org.kuali.kfs.sys.document.service.AccountingLineFieldRenderingTransformation;
026    
027    /**
028     * Represents the rendering for a bunch of elements within the accounting line view
029     */
030    public class AccountingLineViewLines implements TableJoining, ReadOnlyable {
031        private List<AccountingLineViewLineFillingElement> elements;
032        private AccountingLineViewLinesDefinition definition;
033        
034        /**
035         * Gets the definition attribute. 
036         * @return Returns the definition.
037         */
038        public AccountingLineViewLinesDefinition getDefinition() {
039            return definition;
040        }
041        /**
042         * Sets the definition attribute value.
043         * @param definition The definition to set.
044         */
045        public void setDefinition(AccountingLineViewLinesDefinition definition) {
046            this.definition = definition;
047        }
048        
049        /**
050         * @see org.kuali.kfs.sys.document.web.AccountingLineViewRenderableElementContainer#getName()
051         */
052        public String getName() {
053            return definition.getElementName();
054        }
055        /**
056         * Gets the elements attribute. 
057         * @return Returns the elements.
058         */
059        public List<AccountingLineViewLineFillingElement> getElements() {
060            return elements;
061        }
062        /**
063         * Sets the elements attribute value.
064         * @param elements The elements to set.
065         */
066        public void setElements(List<AccountingLineViewLineFillingElement> lines) {
067            this.elements = lines;
068        }
069        
070        /**
071         * The interesting implementation...how many does it need?  Let's see here...one for each child row...
072         * yes...that's right, one table row for each child row
073         * @see org.kuali.kfs.sys.document.web.AccountingLineViewRenderableElement#getRequestedRowCount()
074         */
075        public int getRequestedRowCount() {
076            int sum = 0;
077            for (AccountingLineViewLineFillingElement line : elements) {
078                sum += line.getRequestedRowCount();
079            }
080            return sum;
081        }
082        
083        /**
084         * Throws an exception - lines should never be asked to join rows
085         * @see org.kuali.kfs.sys.document.web.TableJoining#joinRow(org.kuali.kfs.sys.document.web.AccountingLineTableRow)
086         */
087        public void joinRow(AccountingLineTableRow headerRow, AccountingLineTableRow row) {
088            throw new IllegalStateException("Error in line rendering algorithm - lines cannot join a single row.");
089        }
090        
091        /**
092         * Attempts to have each child line join the rows that have been given
093         * @see org.kuali.kfs.sys.document.web.TableJoining#joinTable(java.util.List)
094         */
095        public void joinTable(List<AccountingLineTableRow> rows) {
096            final int maxExpectedLineWidth = getMaxExpectedLineWidth();
097            
098            int count = 0;
099            for (AccountingLineViewLineFillingElement line : elements) {
100                AccountingLineTableRow headerRow = rows.get(count);
101                
102                if (line.getRequestedRowCount() > 1) {
103                    line.joinRow(headerRow, rows.get(count+1));
104                    padOutOrStretchCells(line, maxExpectedLineWidth, headerRow, rows.get(count+1));
105                    
106                    count += 2;
107                } else {
108                    line.joinRow(headerRow, null);
109                    padOutOrStretchCells(line, maxExpectedLineWidth, headerRow, null);
110                    
111                    count += 1;
112                }
113            }
114        }
115        
116        /**
117         * Either pads out out the given table rows with an empty cell or stretches the cell to fill the whole line 
118         * @param line the line joining the table
119         * @param maxExpectedLineWidth the expected width, in cell count, of the line
120         * @param headerRow the first row to add padding out to
121         * @param row the second row to add padding out to - if we're only filling one row, this will be null
122         */
123        protected void padOutOrStretchCells(AccountingLineViewLineFillingElement line, int maxExpectedLineWidth, AccountingLineTableRow headerRow, AccountingLineTableRow row) {
124            final int shorterThanMax = maxExpectedLineWidth - line.getDisplayingFieldWidth();
125            if (shorterThanMax > 0) {
126                if (line.shouldStretchToFillLine() && headerRow.getChildCellCount() == 1) {
127                    headerRow.getCells().get(0).setColSpan(maxExpectedLineWidth);
128                    if (row != null) {
129                        row.getCells().get(0).setColSpan(maxExpectedLineWidth);
130                    }
131                } else {
132                    PlaceHoldingLayoutElement placeHolder = new PlaceHoldingLayoutElement(shorterThanMax);
133                    placeHolder.joinRow(headerRow, row);
134                }
135            }
136        }
137        
138        /**
139         * @see org.kuali.kfs.sys.document.web.ReadOnlyable#readOnlyize()
140         */
141        public void readOnlyize() {
142            for (AccountingLineViewLineFillingElement line : elements) {
143                line.readOnlyize();
144            }
145        }
146        
147        /**
148         * @see org.kuali.kfs.sys.document.web.ReadOnlyable#isReadOnly()
149         */
150        public boolean isReadOnly() {
151            for (AccountingLineViewLineFillingElement line : elements) {
152                if (!line.isReadOnly()) {
153                    return false;
154                }
155            }
156            return true;
157        }
158        
159        /**
160         * @see org.kuali.kfs.sys.document.web.TableJoining#removeAllActionBlocks()
161         */
162        public void removeAllActionBlocks() {
163            for (AccountingLineViewLineFillingElement line : elements) {
164                line.removeAllActionBlocks();
165            }
166        }
167        
168        /**
169         * @see org.kuali.kfs.sys.document.web.TableJoining#removeUnviewableBlocks(java.util.Set)
170         */
171        public void removeUnviewableBlocks(Set<String> unviewableBlocks) {
172            Set<AccountingLineViewLineFillingElement> linesToRemove = new HashSet<AccountingLineViewLineFillingElement>();
173            for (AccountingLineViewLineFillingElement line : elements) {
174                if (unviewableBlocks.contains(line.getName())) {
175                    linesToRemove.add(line);
176                } else {
177                    line.removeUnviewableBlocks(unviewableBlocks);
178                }
179            }
180            elements.removeAll(linesToRemove);
181        }
182        
183        /**
184         * @see org.kuali.kfs.sys.document.web.TableJoining#performFieldTransformation(org.kuali.kfs.sys.document.service.AccountingLineFieldRenderingTransformation, org.kuali.kfs.sys.businessobject.AccountingLine, java.util.Map, java.util.Map)
185         */
186        public void performFieldTransformations(List<AccountingLineFieldRenderingTransformation> fieldTransformations, AccountingLine accountingLine, Map unconvertedValues) {
187            for (AccountingLineViewLineFillingElement line : elements) {
188                line.performFieldTransformations(fieldTransformations, accountingLine, unconvertedValues);
189            }
190        }
191        
192        /**
193         * @return the maximum expected width of any of the child line elements in cells
194         */
195        public int getMaxExpectedLineWidth() {
196            int maxWidth = 0;
197            for (AccountingLineViewLineFillingElement line: elements) {
198                int width = line.getDisplayingFieldWidth();
199                if (width > maxWidth) {
200                    maxWidth = width;
201                }
202            }
203            return maxWidth;
204        }
205        
206        /**
207         * Shuffles the responsibility to the child lines
208         * @see org.kuali.kfs.sys.document.web.TableJoining#readOnlyizeReadOnlyBlocks(java.util.Set)
209         */
210        public void readOnlyizeReadOnlyBlocks(Set<String> readOnlyBlocks) {
211            for (AccountingLineViewLineFillingElement line : elements) {
212                line.readOnlyizeReadOnlyBlocks(readOnlyBlocks);
213            }
214        }
215        
216        /**
217         * @see org.kuali.kfs.sys.document.web.TableJoining#setEditableBlocks(java.util.Set)
218         */
219        public void setEditableBlocks(Set<String> editableBlocks) {
220            for (AccountingLineViewLineFillingElement line : elements) {
221                line.setEditableBlocks(editableBlocks);
222            }
223        }
224        
225        /**
226         * @see org.kuali.kfs.sys.document.web.ReadOnlyable#setEditable()
227         */
228        public void setEditable() {
229            for (AccountingLineViewLineFillingElement line : elements) {
230                line.setEditable();
231            }       
232        }
233    }