All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.custom.datalist.AbstractHtmlDataList Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF2.1 features. A JSF2.1 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.custom.datalist;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.ContextCallback;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.component.UserRoleAware;

/**
 * Similar to dataTable, but does not render a table. 
 * 
 * Instead the layout attribute controls how each dataRow is rendered. 
 * 
 * Unless otherwise specified, all attributes accept static values or EL expressions.
 * 
 * @JSFComponent
 *   name = "t:dataList"
 *   class = "org.apache.myfaces.custom.datalist.HtmlDataList"
 *   tagClass = "org.apache.myfaces.custom.datalist.HtmlDataListTag"
 * @since 1.1.7
 * @author Manfred Geiler (latest modification by $Author: lu4242 $)
 * @version $Revision: 940152 $ $Date: 2010-05-01 21:03:39 -0500 (Sáb, 01 May 2010) $
 */
public abstract class AbstractHtmlDataList
        extends org.apache.myfaces.component.html.ext.HtmlDataTableHack
        implements UserRoleAware
{
    public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlDataList";
    private static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.List";
        
    private static Log log = LogFactory.getLog(AbstractHtmlDataList.class);
    private static final int PROCESS_DECODES = 1;
    private static final int PROCESS_VALIDATORS = 2; // not currently in use
    private static final int PROCESS_UPDATES = 3; // not currently in use
    private static final String SKIP_ITERATION_HINT = "javax.faces.visit.SKIP_ITERATION";
    
    private transient FacesContext _facesContext;

    /**
     * Throws NullPointerException if context is null.  Sets row index to -1, 
     * calls processChildren, sets row index to -1.
     */

    public void processDecodes(FacesContext context)
    {

        if (context == null)
            throw new NullPointerException("context");
        if (!isRendered())
            return;

        setRowIndex(-1);
        processChildren(context, PROCESS_DECODES);
        setRowIndex(-1);
        try
        {
            decode(context);
        }
        catch (RuntimeException e)
        {
            context.renderResponse();
            throw e;
        }        
    }

    public void processUpdates(FacesContext context)
    {
        if (context == null)
            throw new NullPointerException("context");
        if (!isRendered())
            return;

        setRowIndex(-1);
        processChildren(context, PROCESS_UPDATES);
        setRowIndex(-1);
        checkUpdateModelError(context);
    }

    public void processValidators(FacesContext context)
    {
        if (context == null)
            throw new NullPointerException("context");
        if (!isRendered())
            return;

        setRowIndex(-1);
        processChildren(context, PROCESS_VALIDATORS);
        setRowIndex(-1);
        checkUpdateModelError(context);        
    }

    /**
     * Iterates over all children, processes each according to the specified 
     * process action if the child is rendered.
     */

    public void processChildren(FacesContext context, int processAction)
    {
        // use this method for processing other than decode ?
        int first = getFirst();
        int rows = getRows();
        int last = rows == 0 ? getRowCount() : first + rows;

        if (log.isTraceEnabled())
        {
            log.trace("processing " + getChildCount()
                            + " children: starting at " + first
                            + ", ending at " + last);
        }

        for (int rowIndex = first; last == -1 || rowIndex < last; rowIndex++)
        {

            setRowIndex(rowIndex);

            if (!isRowAvailable())
            {
                if (log.isTraceEnabled())
                {
                    log.trace("scrolled past the last row, aborting");
                }
                break;
            }

            for (Iterator it = getChildren().iterator(); it.hasNext();)
            {
                UIComponent child = (UIComponent) it.next();
                if (child.isRendered())
                    process(context, child, processAction);
            }
        }
    }

    /**
     * Copy and pasted from UIData in order to maintain binary compatibility.
     */

    private void process(FacesContext context, UIComponent component,
            int processAction)
    {
        switch (processAction)
        {
        case PROCESS_DECODES:
            component.processDecodes(context);
            break;
        case PROCESS_VALIDATORS:
            component.processValidators(context);
            break;
        case PROCESS_UPDATES:
            component.processUpdates(context);
            break;
        }
    }
    
    public void setRowIndex(int rowIndex)
    {
        super.setRowIndex(rowIndex);
        String rowIndexVar = getRowIndexVar();
        String rowCountVar = getRowCountVar();
        if (rowIndexVar != null || rowCountVar != null)
        {
            Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
            if (rowIndex >= 0)
            {
                //regular row index, update request scope variables
                if (rowIndexVar != null)
                {
                    requestMap.put(getRowIndexVar(), new Integer(rowIndex));
                }
                if (rowCountVar != null)
                {
                    requestMap.put(getRowCountVar(), new Integer(getRowCount()));
                }
            }
            else
            {
                //rowIndex == -1 means end of loop --> remove request scope variables
                if (rowIndexVar != null)
                {
                    requestMap.remove(getRowIndexVar());
                }
                if (rowCountVar != null)
                {
                    requestMap.remove(getRowCountVar());
                }
            }
        }
    }
    
    @Override
    protected void restoreDescendantComponentStates(Object state)
    {
        restoreDescendantComponentStates(getChildren().iterator(), state, true);
    }

    @Override
    protected Object saveDescendantComponentStates()
    {
        return saveDescendantComponentStates(getChildren().iterator(), true);
    }
    
    @Override
    protected Map saveFullDescendantComponentStates(FacesContext facesContext)
    {
        return saveFullDescendantComponentStates(facesContext, null, getChildren().iterator(), true, getContainerClientId(facesContext));
    }
    
    @Override
    protected void restoreFullDescendantComponentStates(FacesContext facesContext, Object initialState)
    {
        restoreFullDescendantComponentStates(facesContext, getChildren().iterator(), initialState, true);
    }

    @Override
    protected void restoreFullDescendantComponentDeltaStates(FacesContext facesContext,
            Map rowState, Object initialState)
    {
        restoreFullDescendantComponentDeltaStates(facesContext, getChildren().iterator(), rowState, initialState, true, getContainerClientId(facesContext));
    }
    
    @Override
    protected Collection saveDescendantInitialComponentStates(FacesContext facesContext)
    {
        return saveDescendantInitialComponentStates(facesContext, getChildren().iterator(), true);
    }

    @Override
    public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback)
        throws FacesException
    {
        if (context == null || clientId == null || callback == null)
        {
            throw new NullPointerException();
        }
        
        final String baseClientId = getClientId(context);

        // searching for this component?
        boolean returnValue = baseClientId.equals(clientId);

        boolean isCachedFacesContext = isTemporalFacesContext();
        if (!isCachedFacesContext)
        {
            setTemporalFacesContext(context);
        }
        
        pushComponentToEL(context, this);
        try
        {
            if (returnValue)
            {
                try
                {
                    callback.invokeContextCallback(context, this);
                    return true;
                }
                catch (Exception e)
                {
                    throw new FacesException(e);
                }
            }
    
            // Now Look throught facets on this UIComponent
            for (Iterator it = this.getFacets().values().iterator(); !returnValue && it.hasNext();)
            {
                returnValue = it.next().invokeOnComponent(context, clientId, callback);
            }
    
            if (returnValue)
            {
                return returnValue;
            }
            
            // is the component an inner component?
            if (clientId.startsWith(baseClientId))
            {
                // Check if the clientId for the component, which we 
                // are looking for, has a rowIndex attached
                char separator = UINamingContainer.getSeparatorChar(context);
                ValueExpression rowKeyVE = getValueExpression("rowKey");
                boolean rowKeyFound = false;
                
                if (rowKeyVE != null)
                {
                    int oldRow = this.getRowIndex();
                    try
                    {
                        // iterate over the rows
                        int rowsToProcess = getRows();
                        // if getRows() returns 0, all rows have to be processed
                        if (rowsToProcess == 0)
                        {
                            rowsToProcess = getRowCount();
                        }
                        int rowIndex = getFirst();
                        for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++)
                        {
                            setRowIndex(rowIndex);
                            if (!isRowAvailable())
                            {
                                break;
                            }
                            
                            if (clientId.startsWith(getContainerClientId(context)))
                            {
                                rowKeyFound = true;
                                break;
                            }
                        }
                        
                        if (rowKeyFound)
                        {
                            for (Iterator it1 = getChildren().iterator(); 
                                    !returnValue && it1.hasNext();)
                            {
                                //recursive call to find the component
                                returnValue = it1.next().invokeOnComponent(context, clientId, callback);
                            }
                        }
                    }
                    finally
                    {
                        this.setRowIndex(oldRow);
                    }
                }
                //If the char next to baseClientId is the separator one and
                //the subId matches the regular expression
                if (rowKeyVE == null && clientId.matches(baseClientId + separator+"[0-9]+"+separator+".*"))
                {
                    String subId = clientId.substring(baseClientId.length() + 1);
                    String clientRow = subId.substring(0, subId.indexOf(separator));
        
                    //Now we save the current position
                    int oldRow = this.getRowIndex();
                    
                    // try-finally --> make sure, that the old row index is restored
                    try
                    {
                        //The conversion is safe, because its already checked on the
                        //regular expresion
                        this.setRowIndex(Integer.parseInt(clientRow));
                        
                        // check, if the row is available
                        if (!isRowAvailable())
                        {
                            return false;
                        }
            
                        for (Iterator it1 = getChildren().iterator(); 
                                !returnValue && it1.hasNext();)
                        {
                            //recursive call to find the component
                            returnValue = it1.next().invokeOnComponent(context, clientId, callback);
                        }
                    }
                    finally
                    {
                        //Restore the old position. Doing this prevent
                        //side effects.
                        this.setRowIndex(oldRow);
                    }
                }
            }
        }
        finally
        {
            //all components must call popComponentFromEl after visiting is finished
            popComponentFromEL(context);
            if (!isCachedFacesContext)
            {
                setTemporalFacesContext(null);
            }
        }

        return returnValue;
    }
    
    @Override
    public boolean visitTree(VisitContext context, VisitCallback callback)
    {
        if (!isVisitable(context))
        {
            return false;
        }

        boolean isTemporalFacesContext = isTemporalFacesContext();
        if (!isTemporalFacesContext)
        {
            setTemporalFacesContext(context.getFacesContext());
        }
        // save the current row index
        int oldRowIndex = getRowIndex();
        // set row index to -1 to process the facets and to get the rowless clientId
        setRowIndex(-1);
        // push the Component to EL
        pushComponentToEL(context.getFacesContext(), this);
        try
        {
            VisitResult visitResult = context.invokeVisitCallback(this,
                    callback);
            switch (visitResult)
            {
            //we are done nothing has to be processed anymore
            case COMPLETE:
                return true;

            case REJECT:
                return false;

                //accept
            default:
                // determine if we need to visit our children 
                Collection subtreeIdsToVisit = context
                        .getSubtreeIdsToVisit(this);
                boolean doVisitChildren = subtreeIdsToVisit != null
                        && !subtreeIdsToVisit.isEmpty();
                if (doVisitChildren)
                {
                    // visit the facets of the component
                    for (UIComponent facet : getFacets().values())
                    {
                        if (facet.visitTree(context, callback))
                        {
                            return true;
                        }
                    }
                    Boolean skipIterationHint = (Boolean) context.getFacesContext().getAttributes().get(SKIP_ITERATION_HINT);
                    if (skipIterationHint != null && skipIterationHint.booleanValue())
                    {
                        // If SKIP_ITERATION is enabled, do not take into account rows.
                        if (getChildCount() > 0) {
                            for (UIComponent child : getChildren()) {
                                if (child.visitTree(context, callback)) {
                                    return true;
                                }
                            }
                        }
                    }
                    else
                    {
                        // iterate over the rows
                        int rowsToProcess = getRows();
                        // if getRows() returns 0, all rows have to be processed
                        if (rowsToProcess == 0)
                        {
                            rowsToProcess = getRowCount();
                        }
                        int rowIndex = getFirst();
                        for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++)
                        {
                            setRowIndex(rowIndex);
                            if (!isRowAvailable())
                            {
                                return false;
                            }
                            // visit the children of every child of the UIData that is an instance of UIColumn
                            for (UIComponent child : getChildren())
                            {
                                if (child.visitTree(context, callback))
                                {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            // pop the component from EL and restore the old row index
            popComponentFromEL(context.getFacesContext());
            setRowIndex(oldRowIndex);
            if (!isTemporalFacesContext)
            {
                setTemporalFacesContext(null);
            }
        }

        // Return false to allow the visiting to continue
        return false;
    }    
    
    @Override
    protected FacesContext getFacesContext()
    {
        if (_facesContext == null)
        {
            return super.getFacesContext();
        }
        else
        {
            return _facesContext;
        }
    }
    
    private boolean isTemporalFacesContext()
    {
        return _facesContext != null;
    }
    
    private void setTemporalFacesContext(FacesContext facesContext)
    {
        _facesContext = facesContext;
    }

    /**
     * A parameter name, under which the rowCount is set in request 
     * scope similar to the var parameter.
     * 
     * @JSFProperty
     */
    public abstract String getRowCountVar();
    
    /**
     *  A parameter name, under which the current rowIndex is set in 
     *  request scope similar to the var parameter.
     * 
     * @JSFProperty
     */
    public abstract String getRowIndexVar();

    /**
     * simple|unorderedList|orderedList
     * 
    *
  • simple = for each dataRow all children are simply rendered
  • *
  • unorderedList = the list is rendered as HTML unordered list (= bullet list)
  • *
  • orderedList = the list is rendered as HTML ordered list
  • *
* Default: simple * * @JSFProperty */ public abstract String getLayout(); /** * CSS class to be applied to individual items in the list * * @JSFProperty */ public abstract String getItemStyleClass(); /** * OnClick handler to be applied to individual items in the list * * @JSFProperty */ public abstract String getItemOnClick(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy