001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
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 *     <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
016 *
017 * $Id: LayoutRowWidgetTagHandler.java 30553 2008-02-24 15:51:31Z atchertchian $
018 */
019
020package org.nuxeo.ecm.platform.forms.layout.facelets;
021
022import java.io.IOException;
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028
029import javax.el.ELException;
030import javax.el.ExpressionFactory;
031import javax.el.ValueExpression;
032import javax.faces.FacesException;
033import javax.faces.component.UIComponent;
034import javax.faces.view.facelets.FaceletContext;
035import javax.faces.view.facelets.FaceletException;
036import javax.faces.view.facelets.FaceletHandler;
037import javax.faces.view.facelets.TagAttribute;
038import javax.faces.view.facelets.TagConfig;
039import javax.faces.view.facelets.TagHandler;
040
041import org.apache.commons.logging.Log;
042import org.apache.commons.logging.LogFactory;
043import org.nuxeo.ecm.platform.forms.layout.api.LayoutRow;
044import org.nuxeo.ecm.platform.forms.layout.api.Widget;
045
046/**
047 * Layout widget recursion tag handler.
048 * <p>
049 * Iterates over a layout row widgets and apply next handlers as many times as needed.
050 * <p>
051 * Only works when used inside a tag using the {@link LayoutRowTagHandler}.
052 *
053 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
054 */
055public class LayoutRowWidgetTagHandler extends TagHandler {
056
057    private static final Log log = LogFactory.getLog(LayoutRowWidgetTagHandler.class);
058
059    protected final TagConfig config;
060
061    /**
062     * @since 7.2
063     */
064    protected final TagAttribute recomputeIds;
065
066    public LayoutRowWidgetTagHandler(TagConfig config) {
067        super(config);
068        this.config = config;
069        recomputeIds = getAttribute("recomputeIds");
070    }
071
072    /**
073     * For each widget in current row, exposes widget variables and applies next handler.
074     * <p>
075     * Needs row to be exposed in context, so works in conjunction with {@link LayoutRowTagHandler}.
076     * <p>
077     * Widget variables exposed: {@link RenderVariables.widgetVariables#widget} , same variable suffixed with "_n" where
078     * n is the widget level, and {@link RenderVariables.widgetVariables#widgetIndex}.
079     */
080    public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
081            ELException {
082
083        // resolve widgets from row in context
084        LayoutRow row = null;
085        String rowVariableName = RenderVariables.rowVariables.layoutRow.name();
086        FaceletHandlerHelper helper = new FaceletHandlerHelper(ctx, config);
087        TagAttribute rowAttribute = helper.createAttribute(rowVariableName, String.format("#{%s}", rowVariableName));
088        if (rowAttribute != null) {
089            row = (LayoutRow) rowAttribute.getObject(ctx, LayoutRow.class);
090        }
091        if (row == null) {
092            log.error("Could not resolve layout row " + rowAttribute);
093            return;
094        }
095
096        Widget[] widgets = row.getWidgets();
097        if (widgets == null || widgets.length == 0) {
098            return;
099        }
100
101        boolean recomputeIdsBool = false;
102        if (recomputeIds != null) {
103            recomputeIdsBool = recomputeIds.getBoolean(ctx);
104        }
105
106        int widgetCounter = 0;
107        for (Widget widget : widgets) {
108            // set unique id on widget before exposing it to the context, but assumes iteration could be done several
109            // times => do not generate id again if already set, unless specified by attribute "recomputeIds"
110            if (widget != null && (widget.getId() == null || recomputeIdsBool)) {
111                WidgetTagHandler.generateWidgetId(helper, widget, false);
112            }
113
114            // expose widget variables
115            Map<String, ValueExpression> variables = new HashMap<String, ValueExpression>();
116            ExpressionFactory eFactory = ctx.getExpressionFactory();
117            ValueExpression widgetVe = eFactory.createValueExpression(widget, Widget.class);
118            variables.put(RenderVariables.widgetVariables.widget.name(), widgetVe);
119            Integer level = null;
120            String tagConfigId = null;
121            if (widget != null) {
122                level = Integer.valueOf(widget.getLevel());
123                tagConfigId = widget.getTagConfigId();
124            }
125            variables.put(String.format("%s_%s", RenderVariables.widgetVariables.widget.name(), level), widgetVe);
126            ValueExpression widgetIndexVe = eFactory.createValueExpression(Integer.valueOf(widgetCounter),
127                    Integer.class);
128            variables.put(RenderVariables.widgetVariables.widgetIndex.name(), widgetIndexVe);
129            variables.put(String.format("%s_%s", RenderVariables.widgetVariables.widgetIndex.name(), level),
130                    widgetIndexVe);
131
132            // XXX: expose widget controls too, need to figure out
133            // why controls cannot be references to widget.controls like
134            // properties are in TemplateWidgetTypeHandler
135            if (widget != null) {
136                for (Map.Entry<String, Serializable> ctrl : widget.getControls().entrySet()) {
137                    String key = ctrl.getKey();
138                    String name = String.format("%s_%s", RenderVariables.widgetVariables.widgetControl.name(), key);
139                    Serializable value = ctrl.getValue();
140                    variables.put(name, eFactory.createValueExpression(value, Object.class));
141                }
142            }
143
144            List<String> blockedPatterns = new ArrayList<String>();
145            blockedPatterns.add(RenderVariables.widgetVariables.widget.name() + "*");
146            blockedPatterns.add(RenderVariables.widgetVariables.widgetIndex.name() + "*");
147            blockedPatterns.add(RenderVariables.widgetVariables.widgetControl.name() + "_*");
148
149            FaceletHandler handler = helper.getAliasTagHandler(tagConfigId, variables, blockedPatterns, nextHandler);
150
151            // apply
152            handler.apply(ctx, parent);
153            widgetCounter++;
154        }
155    }
156}