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