You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2010/08/18 23:25:09 UTC
svn commit: r986953 -
/myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/datalist/AbstractHtmlDataList.java
Author: lu4242
Date: Wed Aug 18 21:25:08 2010
New Revision: 986953
URL: http://svn.apache.org/viewvc?rev=986953&view=rev
Log:
TOMAHAWK-1536 t:dataList needs to implement invokeOnComponent and visitTree
Added:
myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/datalist/AbstractHtmlDataList.java
Added: myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/datalist/AbstractHtmlDataList.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/datalist/AbstractHtmlDataList.java?rev=986953&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/datalist/AbstractHtmlDataList.java (added)
+++ myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/datalist/AbstractHtmlDataList.java Wed Aug 18 21:25:08 2010
@@ -0,0 +1,477 @@
+/*
+ * 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.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 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
+ 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);
+ }
+
+ 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<UIComponent> 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);
+ String subId = clientId.substring(baseClientId.length() + 1);
+ //If the char next to baseClientId is the separator one and
+ //the subId matches the regular expression
+ if (clientId.charAt(baseClientId.length()) == separator &&
+ subId.matches("[0-9]+"+separator+".*"))
+ {
+ 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<UIComponent> 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
+ {
+ 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<String> 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;
+ }
+ }
+ // 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
+ * <ul>
+ * <li>simple = for each dataRow all children are simply rendered</li>
+ * <li>unorderedList = the list is rendered as HTML unordered list (= bullet list)</li>
+ * <li>orderedList = the list is rendered as HTML ordered list</li>
+ * </ul>
+ * 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();
+}