001/*
002 * All rights reserved. This program and the accompanying materials
003 * are made available under the terms of the GNU Lesser General Public License
004 * (LGPL) version 2.1 which accompanies this distribution, and is available at
005 * http://www.gnu.org/licenses/lgpl.html
006 *
007 * This library is distributed in the hope that it will be useful,
008 * but WITHOUT ANY WARRANTY; without even the implied warranty of
009 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
010 * Lesser General Public License for more details.
011 *
012 * Contributors:
013 *     Original file from org.jboss.seam.excel.ui.UIColumn.java in jboss-seam-excel
014 *     Anahide Tchertchian
015 */
016package org.nuxeo.ecm.platform.ui.web.component.seam;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.Iterator;
021import java.util.List;
022
023import javax.faces.component.UIComponent;
024import javax.faces.context.FacesContext;
025
026import org.jboss.seam.excel.ExcelWorkbook;
027import org.jboss.seam.excel.ExcelWorkbookException;
028import org.jboss.seam.excel.WorksheetItem;
029import org.jboss.seam.excel.ui.UIWorksheet;
030import org.jboss.seam.excel.ui.command.Command;
031
032/**
033 * Overrides default column for better introspection of children.
034 * <p>
035 * If e:column tags are not direct children, the work sheet will not find them. As layout templating adds additional JSF
036 * components, the children tree has to be introspected further on, and other children components need to be processed
037 * (UIAliasHolder components used in layout rendering for instance).
038 *
039 * @since 5.4.2
040 */
041public class UIColumn extends org.jboss.seam.excel.ui.UIColumn {
042
043    public static final String COMPONENT_TYPE = UIColumn.class.getName();
044
045    public static final String FOOTER_FACET_NAME = "footer";
046
047    @SuppressWarnings("rawtypes")
048    @Override
049    public void encodeBegin(FacesContext facesContext) throws IOException {
050        // Get workbook and worksheet
051        ExcelWorkbook excelWorkbook = getWorkbook(getParent());
052
053        if (excelWorkbook == null) {
054            throw new ExcelWorkbookException("Could not find excel workbook");
055        }
056
057        // Column width etc.
058        excelWorkbook.applyColumnSettings(this);
059
060        UIWorksheet sheet = (UIWorksheet) getParentByClass(getParent(), UIWorksheet.class);
061        if (sheet == null) {
062            throw new ExcelWorkbookException("Could not find worksheet");
063        }
064
065        // Add header items (if any)
066        WorksheetItem headerItem = (WorksheetItem) getFacet(HEADER_FACET_NAME);
067        if (headerItem != null) {
068            excelWorkbook.addItem(headerItem);
069        }
070
071        // Execute commands (if any)
072        List<Command> commands = getCommands(getChildren());
073        for (Command command : commands) {
074            excelWorkbook.executeCommand(command);
075        }
076
077        // Get UiCell template this column's data cells and iterate over sheet
078        // data
079        // XXX: process all components instead of just UICell ones.
080        for (UIComponent child : getChildren()) {
081            Object oldValue = null;
082            Iterator iterator = null;
083            // Store away the old value for the sheet binding var (if there is
084            // one)
085            if (sheet.getVar() != null) {
086                oldValue = FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(sheet.getVar());
087                iterator = sheet.getDataIterator();
088            } else {
089                // No var, no iteration...
090                iterator = new ArrayList().iterator();
091            }
092
093            while (iterator.hasNext()) {
094                // Store the bound data in the request map and add the cell
095                FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(sheet.getVar(),
096                        iterator.next());
097
098                encodeChild(facesContext, sheet, excelWorkbook, child);
099            }
100
101            // No iteration, nothing to restore
102            if (sheet.getVar() == null) {
103                return;
104            }
105            // Restore the previously modified request map (if there was a var)
106            if (oldValue == null) {
107                FacesContext.getCurrentInstance().getExternalContext().getRequestMap().remove(sheet.getVar());
108            } else {
109                FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(sheet.getVar(), oldValue);
110            }
111
112        }
113
114        // Add footer items (if any)
115        WorksheetItem footerItem = (WorksheetItem) getFacet(FOOTER_FACET_NAME);
116        if (footerItem != null) {
117            excelWorkbook.addItem(footerItem);
118        }
119
120        // Move column pointer to next column
121        excelWorkbook.nextColumn();
122
123    }
124
125    @SuppressWarnings("rawtypes")
126    protected void encodeChild(FacesContext facesContext, UIWorksheet sheet, ExcelWorkbook excelWorkbook,
127            UIComponent child) throws IOException {
128        // XXX make sure other components are processed
129        if (child instanceof WorksheetItem) {
130            excelWorkbook.addItem((WorksheetItem) child);
131        } else {
132            if (child.isRendered()) {
133                child.encodeBegin(facesContext);
134                // do not let component handling render of its children
135                List subChildren = child.getChildren();
136                for (int j = 0, size = child.getChildCount(); j < size; j++) {
137                    UIComponent subChild = (UIComponent) subChildren.get(j);
138                    encodeChild(facesContext, sheet, excelWorkbook, subChild);
139                }
140                child.encodeEnd(facesContext);
141            }
142        }
143
144    }
145
146    @SuppressWarnings("unchecked")
147    public static <T> List<T> getAllChildrenOfType(List<UIComponent> children, Class<T> childType) {
148        List<T> matches = new ArrayList<T>();
149        for (UIComponent child : children) {
150            if (childType.isAssignableFrom(child.getClass())) {
151                matches.add((T) child);
152            } else {
153                // XXX introspect children
154                List<T> subChildren = getAllChildrenOfType(child.getChildren(), childType);
155                if (subChildren != null && !subChildren.isEmpty()) {
156                    matches.addAll(subChildren);
157                }
158            }
159        }
160        return matches;
161    }
162
163    /**
164     * Returns all commands from a child list
165     *
166     * @param children The list to search
167     * @return The commands
168     */
169    protected static List<Command> getCommands(List<UIComponent> children) {
170        return getAllChildrenOfType(children, Command.class);
171    }
172
173}