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/04/23 23:52:25 UTC

svn commit: r937536 - in /myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext: AbstractHtmlDataTable.java HtmlDataTableHack.java

Author: lu4242
Date: Fri Apr 23 21:52:24 2010
New Revision: 937536

URL: http://svn.apache.org/viewvc?rev=937536&view=rev
Log:
TOMAHAWK-1474 add clientBehavior stuff and TOMAHAWK-1471 update to use PSS

Modified:
    myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/AbstractHtmlDataTable.java
    myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTableHack.java

Modified: myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/AbstractHtmlDataTable.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/AbstractHtmlDataTable.java?rev=937536&r1=937535&r2=937536&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/AbstractHtmlDataTable.java (original)
+++ myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/AbstractHtmlDataTable.java Fri Apr 23 21:52:24 2010
@@ -18,26 +18,6 @@
  */
 package org.apache.myfaces.component.html.ext;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.myfaces.component.NewspaperTable;
-import org.apache.myfaces.component.UserRoleAware;
-import org.apache.myfaces.component.UserRoleUtils;
-import org.apache.myfaces.custom.column.HtmlSimpleColumn;
-import org.apache.myfaces.custom.crosstable.UIColumns;
-import org.apache.myfaces.custom.sortheader.HtmlCommandSortHeader;
-import org.apache.myfaces.renderkit.html.ext.HtmlTableRenderer;
-import org.apache.myfaces.renderkit.html.util.TableContext;
-import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
-
-import javax.faces.application.Application;
-import javax.faces.component.EditableValueHolder;
-import javax.faces.component.NamingContainer;
-import javax.faces.component.UIColumn;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.faces.el.ValueBinding;
-import javax.faces.model.DataModel;
 import java.io.IOException;
 import java.sql.ResultSet;
 import java.util.ArrayList;
@@ -50,6 +30,33 @@ import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
 
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.component.ContextCallback;
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.UIColumn;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
+import javax.faces.component.UIPanel;
+import javax.faces.context.FacesContext;
+import javax.faces.el.ValueBinding;
+import javax.faces.model.DataModel;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFacet;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
+import org.apache.myfaces.component.NewspaperTable;
+import org.apache.myfaces.component.UserRoleAware;
+import org.apache.myfaces.component.UserRoleUtils;
+import org.apache.myfaces.custom.column.HtmlSimpleColumn;
+import org.apache.myfaces.custom.crosstable.UIColumns;
+import org.apache.myfaces.custom.sortheader.HtmlCommandSortHeader;
+import org.apache.myfaces.renderkit.html.ext.HtmlTableRenderer;
+import org.apache.myfaces.renderkit.html.util.TableContext;
+
 /**
  * The MyFacesDataTable extends the standard JSF DataTable by two
  * important features:
@@ -67,15 +74,15 @@ import java.util.StringTokenizer;
  * <br/>
  * Unless otherwise specified, all attributes accept static values or EL expressions.
  * 
- * @JSFComponent
- *   name = "t:dataTable"
- *   class = "org.apache.myfaces.component.html.ext.HtmlDataTable"
- *   tagClass = "org.apache.myfaces.generated.taglib.html.ext.HtmlDataTableTag"
  * @since 1.1.7
  * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
  * @author Manfred Geiler
  * @version $Revision: 691856 $ $Date: 2008-09-03 21:40:30 -0500 (mié, 03 sep 2008) $
  */
+@JSFComponent(
+   name = "t:dataTable",
+   clazz = "org.apache.myfaces.component.html.ext.HtmlDataTable",
+   tagClass = "org.apache.myfaces.generated.taglib.html.ext.HtmlDataTableTag")
 public abstract class AbstractHtmlDataTable extends HtmlDataTableHack implements UserRoleAware, NewspaperTable
 {
     private static final Log log = LogFactory.getLog(AbstractHtmlDataTable.class);
@@ -103,21 +110,11 @@ public abstract class AbstractHtmlDataTa
 
     private _SerializableDataModel _preservedDataModel;
 
-    private String _forceIdIndexFormula = null;
-    private String _sortColumn = null;
-    private Boolean _sortAscending = null;
-    private String _sortProperty = null;
-    private String _rowStyleClass = null;
-    private String _rowStyle = null;
-    private String _varDetailToggler = null;
-
-    private int _sortColumnIndex = -1;
-
     private boolean _isValidChildren = true;
 
-    private Map _expandedNodes = new HashMap();
+    private Map<Integer, Boolean> _expandedNodes = new HashMap<Integer, Boolean>();
 
-    private Map _detailRowStates = new HashMap();
+    private Map<String, Object> _detailRowStates = new HashMap<String, Object>();
 
     private TableContext _tableContext = null;
 
@@ -146,11 +143,12 @@ public abstract class AbstractHtmlDataTa
         // Trick : Remove the last part starting with NamingContainer.SEPARATOR_CHAR that contains the rowIndex.
         // It would be best to not resort to String manipulation,
         // but we can't get super.super.getClientId() :-(
-        int indexLast_ = standardClientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
+        char separator = UINamingContainer.getSeparatorChar(context);
+        int indexLast_ = standardClientId.lastIndexOf(separator);
         if (indexLast_ == -1)
         {
             log.info("Could not parse super.getClientId. forcedIdIndex will contain the rowIndex.");
-            return standardClientId + NamingContainer.SEPARATOR_CHAR + forcedIdIndex;
+            return standardClientId + separator + forcedIdIndex;
         }
 
         //noinspection UnnecessaryLocalVariable
@@ -162,7 +160,8 @@ public abstract class AbstractHtmlDataTa
     {
         if (expr.length() > 0 && Character.isDigit(expr.charAt(0)))
         {
-            int separatorIndex = expr.indexOf(NamingContainer.SEPARATOR_CHAR);
+            char separator = UINamingContainer.getSeparatorChar(getFacesContext());
+            int separatorIndex = expr.indexOf(separator);
 
             String rowIndexStr = expr;
             String remainingPart = null;
@@ -196,6 +195,126 @@ public abstract class AbstractHtmlDataTa
             return super.findComponent(expr);
         }
     }
+    
+    
+
+    @Override
+    public boolean invokeOnComponent(FacesContext context, String clientId,
+            ContextCallback callback) throws FacesException
+    {
+        if (context == null || clientId == null || callback == null)
+        {
+            throw new NullPointerException();
+        }
+
+        // searching for this component?
+        boolean returnValue = this.getClientId(context).equals(clientId);
+
+        if (returnValue)
+        {
+            try
+            {
+                callback.invokeContextCallback(context, this);
+            }
+            catch (Exception e)
+            {
+                throw new FacesException(e);
+            }
+            return returnValue;
+        }
+
+        // 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 == true)
+        {
+            return returnValue;
+        }
+        
+        // Now we have to check if it is searching an inner component
+        String baseClientId = super.getClientId(context);
+        
+        // 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);
+            if (clientId.matches(baseClientId + separator+"[0-9]+"+separator+".*"))
+            {
+                String subId = clientId.substring(baseClientId.length() + 1);
+                String clientRow = subId.substring(0, subId.indexOf(':'));
+    
+                //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);
+                }
+            }
+            else
+            {
+                // MYFACES-2370: search the component in the childrens' facets too.
+                // We have to check the childrens' facets here, because in MyFaces
+                // the rowIndex is not attached to the clientId for the children of
+                // facets of the UIColumns. However, in RI the rowIndex is 
+                // attached to the clientId of UIColumns' Facets' children.
+                for (Iterator<UIComponent> itChildren = this.getChildren().iterator();
+                        !returnValue && itChildren.hasNext();)
+                {
+                    UIComponent child = itChildren.next();
+                    // This is the only part different to UIData.invokeOnComponent. Since we have
+                    // an auto wrapping on columns feature, it is necessary to check columns ids
+                    // without row for invokeOnComponent, but do not traverse all elements, so
+                    // save/restore algorithm could be able to remove / add them.  
+                    if (child instanceof UIColumn && clientId.equals(child.getClientId()))
+                    {
+                        try {
+                            callback.invokeContextCallback(context, child);
+                        } catch (Exception e) {
+                            throw new FacesException(e);
+                        }
+                        returnValue = true;
+                    }
+                    // process the child's facets
+                    for (Iterator<UIComponent> itChildFacets = child.getFacets().values().iterator(); 
+                            !returnValue && itChildFacets.hasNext();)
+                    {
+                        //recursive call to find the component
+                        returnValue = itChildFacets.next().invokeOnComponent(context, clientId, callback);
+                    }
+                }
+            }
+        }
+
+        return returnValue;
+    }
 
     public void setRowIndex(int rowIndex)
     {
@@ -285,10 +404,10 @@ public abstract class AbstractHtmlDataTa
 
         }
 
-        if (_varDetailToggler != null)
+        if (getStateHelper().get(PropertyKeys.varDetailToggler) != null)
         {
             Map requestMap = getFacesContext().getExternalContext().getRequestMap();
-            requestMap.put(_varDetailToggler, this);
+            requestMap.put(getStateHelper().get(PropertyKeys.varDetailToggler), this);
         }
     }
 
@@ -581,13 +700,54 @@ public abstract class AbstractHtmlDataTa
                     if (propertyName == null)
                         log.warn("Couldn't determine sort property for column [" + aColumn.getId() + "].");
 
-                    if (headerFacet != null)
+                    if (headerFacet instanceof UIPanel)
+                    {
+                        // In jsf 2.0, facets allow more than one component. That causes a side effect on
+                        // facelets mode when auto wrapping is used, because the algorithm is not aware
+                        // we wrap everything inside a HtmlCommandSortHeader. We have to check
+                        // here that condition and if so, fix it and threat it correctly. 
+                        HtmlCommandSortHeader sortHeader = null;
+                        for (UIComponent childHeaderFacet : headerFacet.getChildren())
+                        {
+                            if (childHeaderFacet instanceof HtmlCommandSortHeader)
+                            {
+                                sortHeader = (HtmlCommandSortHeader) childHeaderFacet;
+                                break;
+                            }
+                        }
+                        if (sortHeader != null)
+                        {
+                            aColumn.getFacets().remove("header");
+                            aColumn.setHeader(sortHeader);
+                            headerFacet = sortHeader;
+                            
+                            //command sort headers are already in place, just store the column name and sort property name
+                            columnName = sortHeader.getColumnName();
+                            propertyName = sortHeader.getPropertyName();
+
+                            //if the command sort header component doesn't specify a sort property, determine it
+                            if (propertyName == null)
+                            {
+                                propertyName = getSortPropertyFromEL(aColumn);
+                                sortHeader.setPropertyName(propertyName);
+                            }
+
+                            if (propertyName == null)
+                                log.warn("Couldn't determine sort property for column [" + aColumn.getId() + "].");                            
+                        }
+                    }
+                    if (headerFacet != null && isSortHeaderNeeded(aColumn, headerFacet))
                     {
+                        // We need to force PreRemoveFromViewEvent on the wrapped facet, so we remove it manually here.
+                        // Otherwise the component is just moved on the view and no event is triggered. 
+                        aColumn.getFacets().remove("header");
+                        
                         HtmlCommandSortHeader sortHeader = createSortHeaderComponent(context, aColumn, headerFacet, propertyName);
                         columnName = sortHeader.getColumnName();
 
                         aColumn.setHeader(sortHeader);
-                        sortHeader.setParent(aColumn);
+                        //setParent is called internally!
+                        //sortHeader.setParent(aColumn);
                     }
                 }
                 else if (headerFacet instanceof HtmlCommandSortHeader)
@@ -609,7 +769,10 @@ public abstract class AbstractHtmlDataTa
                 }
 
                 //make the column marked as default sorted be the current sorted column
-                if (defaultSorted && getSortColumn() == null)
+                //When getSortColumn() eval to a ValueExpression and it is a String, it could return
+                //null but here it is coerced to "", so we need to assume "" as null.
+                String sortColumn = getSortColumn();
+                if (defaultSorted &&  (sortColumn == null ? true : sortColumn.length() == 0))
                 {
                     setSortColumn(columnName);
                     setSortProperty(propertyName);
@@ -700,7 +863,7 @@ public abstract class AbstractHtmlDataTa
     protected int columnNameToIndex(String columnName)
     {
         int index = 0;
-        for (Iterator iter = getChildren().iterator(); iter.hasNext();)
+        for (Iterator<UIComponent> iter = getChildren().iterator(); iter.hasNext();)
         {
             UIComponent aChild = (UIComponent) iter.next();
             if (aChild instanceof UIColumn)
@@ -709,7 +872,7 @@ public abstract class AbstractHtmlDataTa
                 if (headerFacet != null && headerFacet instanceof HtmlCommandSortHeader)
                 {
                     HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) headerFacet;
-                    if (columnName != null && columnName.equals(sortHeader.getColumnName()))
+                    if (columnName != null && columnName.length()>0 && columnName.equals(sortHeader.getColumnName()))
                         return index;
                 }
             }
@@ -726,7 +889,7 @@ public abstract class AbstractHtmlDataTa
     public void encodeEnd(FacesContext context) throws IOException
     {
         super.encodeEnd(context);
-        for (Iterator iter = getChildren().iterator(); iter.hasNext();)
+        for (Iterator<UIComponent> iter = getChildren().iterator(); iter.hasNext();)
         {
             UIComponent component = (UIComponent) iter.next();
             if (component instanceof UIColumns)
@@ -739,8 +902,8 @@ public abstract class AbstractHtmlDataTa
     /**
      * The index of the first row to be displayed, where 0 is the first row.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public int getFirst()
     {
         if (_preservedDataModel != null)
@@ -767,8 +930,8 @@ public abstract class AbstractHtmlDataTa
     /**
      *  The number of rows to be displayed. Specify zero for all remaining rows in the table.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public int getRows()
     {
         if (_preservedDataModel != null)
@@ -796,36 +959,57 @@ public abstract class AbstractHtmlDataTa
     {
         boolean preserveSort = isPreserveSort();
 
-        Object[] values = new Object[15];
-        values[0] = super.saveState(context);
-        values[1] = _preserveDataModel;
-
-        if (isPreserveDataModel())
+        if (initialStateMarked())
         {
-            _preservedDataModel = getSerializableDataModel();
-            values[2] = saveAttachedState(context, _preservedDataModel);
+            Object parentSaved = super.saveState(context);
+            boolean preserveDataModel = isPreserveDataModel();
+            
+            if (parentSaved == null && !preserveSort 
+                    && !preserveDataModel && isExpandedEmpty())
+            {
+                //No values
+                return null;
+            }
+            
+            Object[] values = new Object[5];
+            values[0] = parentSaved;
+            
+            if (isPreserveDataModel())
+            {
+                _preservedDataModel = getSerializableDataModel();
+                values[1] = saveAttachedState(context, _preservedDataModel);
+            }
+            else
+            {
+                values[1] = null;
+            }
+            
+            values[2] = preserveSort ? getSortColumn() : null;
+            values[3] = preserveSort ? Boolean.valueOf(isSortAscending()) : null;
+            values[4] = _expandedNodes;
+            return values;
         }
         else
         {
-            values[2] = null;
-        }
-        values[3] = _preserveSort;
-        values[4] = _forceIdIndexFormula;
-        values[5] = _sortColumn;
-        values[6] = _sortAscending;
-        values[7] = _sortProperty;
-
-        values[8] = _rowStyleClass;
-        values[9] = _rowStyle;
+            Object[] values = new Object[5];
+            values[0] = super.saveState(context);
 
-        values[10] = preserveSort ? getSortColumn() : null;
-        values[11] = preserveSort ? Boolean.valueOf(isSortAscending()) : null;
-
-        values[12] = _varDetailToggler;
-        values[13] = _expandedNodes;
-        values[14] = new Integer(_sortColumnIndex);
+            if (isPreserveDataModel())
+            {
+                _preservedDataModel = getSerializableDataModel();
+                values[1] = saveAttachedState(context, _preservedDataModel);
+            }
+            else
+            {
+                values[1] = null;
+            }
+            
+            values[2] = preserveSort ? getSortColumn() : null;
+            values[3] = preserveSort ? Boolean.valueOf(isSortAscending()) : null;
+            values[4] = _expandedNodes;
 
-        return values;
+            return values;
+        }
     }
 
     /**
@@ -868,7 +1052,9 @@ public abstract class AbstractHtmlDataTa
                     if (aColumn.isSortable())
                         isSortable = true;
 
-                    if (aColumn.isDefaultSorted() && getSortColumn() == null)
+                    String sortColumn = getSortColumn();
+                    
+                    if (aColumn.isDefaultSorted() && (sortColumn == null ? true : sortColumn.length() == 0))
                         setSortProperty(aColumn.getSortPropertyName());
                 }
             }
@@ -891,49 +1077,43 @@ public abstract class AbstractHtmlDataTa
 
     public void restoreState(FacesContext context, Object state)
     {
+        if (state == null)
+        {
+            return;
+        }
+        
         Object[] values = (Object[]) state;
         super.restoreState(context, values[0]);
-        _preserveDataModel = (Boolean) values[1];
         if (isPreserveDataModel())
         {
-            _preservedDataModel = (_SerializableDataModel) restoreAttachedState(context, values[2]);
+            _preservedDataModel = (_SerializableDataModel) restoreAttachedState(context, values[1]);
         }
         else
         {
             _preservedDataModel = null;
         }
-        _preserveSort = (Boolean) values[3];
-        _forceIdIndexFormula = (String) values[4];
-        _sortColumn = (String) values[5];
-        _sortAscending = (Boolean) values[6];
-        _sortProperty = (String) values[7];
-
-        _rowStyleClass = (String) values[8];
-        _rowStyle = (String) values[9];
 
         if (isPreserveSort())
         {
-            String sortColumn = (String) values[10];
-            Boolean sortAscending = (Boolean) values[11];
+            String sortColumn = (String) values[2];
+            Boolean sortAscending = (Boolean) values[3];
             if (sortColumn != null && sortAscending != null)
             {
-                ValueBinding vb = getValueBinding("sortColumn");
-                if (vb != null && !vb.isReadOnly(context))
+                ValueExpression vb = getValueExpression("sortColumn");
+                if (vb != null && !vb.isReadOnly(context.getELContext()))
                 {
-                    vb.setValue(context, sortColumn);
+                    vb.setValue(context.getELContext(), sortColumn);
                 }
 
-                vb = getValueBinding("sortAscending");
-                if (vb != null && !vb.isReadOnly(context))
+                vb = getValueExpression("sortAscending");
+                if (vb != null && !vb.isReadOnly(context.getELContext()))
                 {
-                    vb.setValue(context, sortAscending);
+                    vb.setValue(context.getELContext(), sortAscending);
                 }
             }
         }
 
-        _varDetailToggler = (String) values[12];
-        _expandedNodes = (Map) values[13];
-        _sortColumnIndex = values[14] != null ? ((Integer) values[14]).intValue() : -1;
+        _expandedNodes = (Map) values[4];
     }
 
     public _SerializableDataModel getSerializableDataModel()
@@ -997,12 +1177,12 @@ public abstract class AbstractHtmlDataTa
 
     public void setForceIdIndexFormula(String forceIdIndexFormula)
     {
-        _forceIdIndexFormula = forceIdIndexFormula;
-        ValueBinding vb = getValueBinding("forceIdIndexFormula");
+        getStateHelper().put(PropertyKeys.forceIdIndexFormula, forceIdIndexFormula);
+        ValueExpression vb = getValueExpression("forceIdIndexFormula");
         if (vb != null)
         {
-            vb.setValue(getFacesContext(), _forceIdIndexFormula);
-            _forceIdIndexFormula = null;
+            vb.setValue(getFacesContext().getELContext(), forceIdIndexFormula);
+            getStateHelper().put(PropertyKeys.forceIdIndexFormula, null);
         }
     }
 
@@ -1013,17 +1193,11 @@ public abstract class AbstractHtmlDataTa
      * Example : #{myRowVar.key} Warning, the EL should 
      * evaluate to a unique value for each row !
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public String getForceIdIndexFormula()
     {
-        if (_forceIdIndexFormula != null)
-            return _forceIdIndexFormula;
-        ValueBinding vb = getValueBinding("forceIdIndexFormula");
-        if (vb == null)
-            return null;
-        Object eval = vb.getValue(getFacesContext());
-        return eval == null ? null : eval.toString();
+        return (String) getStateHelper().eval(PropertyKeys.forceIdIndexFormula);
     }
 
     /**
@@ -1041,14 +1215,14 @@ public abstract class AbstractHtmlDataTa
      */
     public void setSortColumn(String sortColumn)
     {
-        _sortColumn = sortColumn;
+        getStateHelper().put(PropertyKeys.sortColumn, sortColumn);
         // update model is necessary here, because processUpdates is never called
         // reason: HtmlCommandSortHeader.isImmediate() == true
-        ValueBinding vb = getValueBinding("sortColumn");
+        ValueExpression vb = getValueExpression("sortColumn");
         if (vb != null)
         {
-            vb.setValue(getFacesContext(), _sortColumn);
-            _sortColumn = null;
+            vb.setValue(getFacesContext().getELContext(), sortColumn);
+            getStateHelper().put(PropertyKeys.sortColumn, null);
         }
 
         setSortColumnIndex(columnNameToIndex(sortColumn));
@@ -1063,25 +1237,24 @@ public abstract class AbstractHtmlDataTa
      * is expected to use this property to determine how to sort 
      * the DataModel's contents.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public String getSortColumn()
     {
-        if (_sortColumn != null) return _sortColumn;
-        ValueBinding vb = getValueBinding("sortColumn");
-        return vb != null ? (String) vb.getValue(getFacesContext()) : null;
+        return (String) getStateHelper().eval(PropertyKeys.sortColumn);
     }
 
     public void setSortAscending(boolean sortAscending)
     {
-        _sortAscending = Boolean.valueOf(sortAscending);
+        getStateHelper().put(PropertyKeys.sortAscending, sortAscending);
+        
         // update model is necessary here, because processUpdates is never called
         // reason: HtmlCommandSortHeader.isImmediate() == true
-        ValueBinding vb = getValueBinding("sortAscending");
+        ValueExpression vb = getValueExpression("sortAscending");
         if (vb != null)
         {
-            vb.setValue(getFacesContext(), _sortAscending);
-            _sortAscending = null;
+            vb.setValue(getFacesContext().getELContext(), sortAscending);
+            getStateHelper().put(PropertyKeys.sortAscending, null);
         }
     }
 
@@ -1094,18 +1267,15 @@ public abstract class AbstractHtmlDataTa
      * DataModel used) is expected to use this property to 
      * determine how to sort the DataModel's contents.
      * 
-     * @JSFProperty
-     *   defaultValue = "true"
      */
+    @JSFProperty(defaultValue="true")
     public boolean isSortAscending()
     {
-        if (_sortAscending != null)
-            return _sortAscending.booleanValue();
-        ValueBinding vb = getValueBinding("sortAscending");
-        Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
-        return v != null ? v.booleanValue() : DEFAULT_SORTASCENDING;
+        return (Boolean) getStateHelper().eval(PropertyKeys.sortAscending, DEFAULT_SORTASCENDING);
     }
 
+    public abstract void setSortProperty(String sortProperty);
+    
     /**
      * The name of a javabean property on which the table is sorted.
      * <p>
@@ -1117,27 +1287,14 @@ public abstract class AbstractHtmlDataTa
      * directly settable by users; instead it is set by other components
      * such as a CommandSortHeader.
      */
-    public void setSortProperty(String sortProperty)
-    {
-        _sortProperty = sortProperty;
-    }
-
-    /**
-     * @JSFProperty
-     *   literalOnly="true"
-     *   tagExcluded="true"
-     */
-    public String getSortProperty()
-    {
-        return _sortProperty;
-    }
+    @JSFProperty(literalOnly=true,tagExcluded=true)
+    public abstract String getSortProperty();
 
     /**
      * Define if the table is sortable or not
      * 
-     * @JSFProperty
-     *   defaultValue="false"
      */
+    @JSFProperty(defaultValue="false")
     public abstract boolean isSortable();
 
     /**
@@ -1150,160 +1307,112 @@ public abstract class AbstractHtmlDataTa
      * number of columns. Using the colspan attribute of the 
      * column tag might help alot.
      * 
-     * @JSFProperty
-     *   defaultValue="false"
      */
+    @JSFProperty(defaultValue="false")
     public abstract boolean isEmbedded();
 
     /**
      * true|false - true if the detailStamp should be expanded by default. default: false
      * 
-     * @JSFProperty
-     *   defaultValue="false"
      */
+    @JSFProperty(defaultValue="false")
     public abstract boolean isDetailStampExpandedDefault();
 
     /**
      * before|after - where to render the detailStamp, before the 
      * actual row or after it. default: after
      * 
-     * @JSFProperty
-     *   defaultValue="after"
      */
+    @JSFProperty(defaultValue="after")
     public abstract String getDetailStampLocation();
 
     /**
      * Defines a JavaScript onmouseover event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnMouseOver")
     public abstract String getRowOnMouseOver();
 
     /**
      * Defines a JavaScript onmouseout event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnMouseOut")
     public abstract String getRowOnMouseOut();
 
     /**
      * Defines a JavaScript onclick event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnClick")
     public abstract String getRowOnClick();
 
     /**
      * Defines a JavaScript ondblclick event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnDblClick")
     public abstract String getRowOnDblClick();
 
     /**
      * Defines a JavaScript onkeydown event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnKeyDown")
     public abstract String getRowOnKeyDown();
 
     /**
      * Defines a JavaScript onkeypress event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnKeyPress")
     public abstract String getRowOnKeyPress();
 
     /**
      * Defines a JavaScript onkeyup event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnKeyUp")
     public abstract String getRowOnKeyUp();
 
     /**
      * Corresponds to the HTML class attribute for the row tr tag.
      * 
-     * @JSFProperty
      */
-    public String getRowStyleClass()
-    {
-    if (_rowStyleClass != null)
-        return _rowStyleClass;
-
-    // TODO: temporarily support fully-qualified ext. dataTable attribute names.
-    ValueBinding vb = getValueBinding("org.apache.myfaces.dataTable.ROW_STYLECLASS");
-    if (vb != null)
-        log.warn("org.apache.myfaces.dataTable.ROW_STYLECLASS is deprecated. Please use rowStyleClass instead.");
-    else
-        vb = getValueBinding(JSFAttr.ROW_STYLECLASS_ATTR);
-    if(vb == null)
-        return null;
-    String bindingValue = (String) vb.getValue(getFacesContext());
-    if(bindingValue == "")
-        return null;  // Fix for JSF 1.2 EL coercing nulls to empty string
-    return bindingValue;
-    }
-
-    public void setRowStyleClass(String rowStyleClass)
-    {
-        _rowStyleClass = rowStyleClass;
-    }
+    @JSFProperty
+    public abstract String getRowStyleClass();
 
     /**
      * Corresponds to the HTML style attribute for the row tr tag.
      * 
-     * @JSFProperty
      */
-    public String getRowStyle()
-    {
-        if (_rowStyle != null)
-            return _rowStyle;
-
-    // TODO: temporarily support fully-qualified ext. dataTable attribute names.
-        ValueBinding vb = getValueBinding("org.apache.myfaces.dataTable.ROW_STYLE");
-    if (vb != null)
-        log.warn("org.apache.myfaces.dataTable.ROW_STYLE is deprecated. Please use rowStyle instead.");
-    else
-        vb = getValueBinding(JSFAttr.ROW_STYLE_ATTR);
-    if(vb == null)
-        return null;
-    String bindingValue = (String) vb.getValue(getFacesContext());
-    if(bindingValue == "")
-        return null;  // Fix for JSF 1.2 EL coercing nulls to empty string
-    return bindingValue;
-    }
-
-    public void setRowStyle(String rowStyle)
-    {
-        _rowStyle = rowStyle;
-    }
+    @JSFProperty
+    public abstract String getRowStyle();
 
     /**
      * Defines a JavaScript onmpusedown event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnMouseDown")
     public abstract String getRowOnMouseDown();
 
     /**
      * Defines a JavaScript onmousemove event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnMouseMove")
     public abstract String getRowOnMouseMove();
 
     /**
      * Defines a JavaScript onmouseup event handler for each table row
      * 
-     * @JSFProperty
      */
+    @JSFProperty(clientEvent="rowOnMouseUp")
     public abstract String getRowOnMouseUp();
 
     /**
-     * @JSFProperty
-     *   tagExcluded = "true"
      */
+    @JSFProperty(tagExcluded=true)
     protected boolean isValidChildren()
     {
         return _isValidChildren;
@@ -1338,7 +1447,7 @@ public abstract class AbstractHtmlDataTa
 
     public void setVarDetailToggler(String varDetailToggler)
     {
-        _varDetailToggler = varDetailToggler;
+        getStateHelper().put(PropertyKeys.varDetailToggler, varDetailToggler ); 
     }
 
     /**
@@ -1347,42 +1456,39 @@ public abstract class AbstractHtmlDataTa
      *  action method "toggleDetail" which expand/collapse the current 
      *  detail row.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public String getVarDetailToggler()
     {
-        if (_varDetailToggler != null)
-            return _varDetailToggler;
-        ValueBinding vb = getValueBinding("varDetailToggler");
-        return vb != null ? (String) vb.getValue(getFacesContext()) : null;
+        return (String) getStateHelper().eval(PropertyKeys.varDetailToggler);
     }
 
     /**
      * Corresponds to the HTML style attribute for grouped rows.
      *  
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getRowGroupStyle();
 
     /**
      * StyleClass for grouped rows.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getRowGroupStyleClass();
     
     /**
      * Corresponds to the HTML style attribute for the table body tag
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getBodyStyle();
 
     /**
      * Corresponds to the HTML class attribute for the table body tag.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getBodyStyleClass();
 
     public AbstractHtmlDataTable()
@@ -1452,15 +1558,21 @@ public abstract class AbstractHtmlDataTa
 
     public int getSortColumnIndex()
     {
-        if (_sortColumnIndex == -1)
-            _sortColumnIndex = columnNameToIndex(getSortColumn());
+        Integer sortColumnIndex = (Integer) getStateHelper().get(PropertyKeys.sortColumnIndex);
+        if (sortColumnIndex == null)
+        {
+            //By default is -1 
+            sortColumnIndex = -1;
+        }
+        if (sortColumnIndex == -1)
+            sortColumnIndex = columnNameToIndex(getSortColumn());
 
-        return _sortColumnIndex;
+        return sortColumnIndex;
     }
 
     public void setSortColumnIndex(int sortColumnIndex)
     {
-        _sortColumnIndex = sortColumnIndex;
+        getStateHelper().put(PropertyKeys.sortColumnIndex, sortColumnIndex ); 
     }
 
     /**
@@ -1468,26 +1580,23 @@ public abstract class AbstractHtmlDataTa
      * 
      * Set the number of columns the table will be divided over.
      * 
-     * @JSFProperty
-     *   defaultValue="1"
      */
+    @JSFProperty(defaultValue="1")
     public abstract int getNewspaperColumns();
 
     /**
      * The orientation of the newspaper columns in the newspaper 
      * table - "horizontal" or "vertical". Default: vertical
      * 
-     * @JSFProperty
-     *   defaultValue = "vertical"
      */
+    @JSFProperty(defaultValue = "vertical")
     public abstract String getNewspaperOrientation();
 
     /**
      * Gets the spacer facet, between each pair of newspaper columns.
      * 
-     * @JSFFacet
-     *   name="spacer"
      */
+    @JSFFacet
     public UIComponent getSpacer()
     {
         return (UIComponent) getFacets().get(SPACER_FACET_NAME);
@@ -1558,13 +1667,6 @@ public abstract class AbstractHtmlDataTa
     private static final boolean DEFAULT_PRESERVESORT = true;
     private static final boolean DEFAULT_RENDEREDIFEMPTY = true;
 
-    private Boolean _preserveDataModel = null;
-    private Boolean _preserveSort = null;
-
-    public void setPreserveDataModel(boolean preserveDataModel)
-    {
-        _preserveDataModel = Boolean.valueOf(preserveDataModel);
-    }
 
     /**
      * Indicates whether the state of the whole DataModel should 
@@ -1578,38 +1680,18 @@ public abstract class AbstractHtmlDataTa
      * the DataModel can be updated to reflect any changes in the 
      * sort criteria. Default: false
      * 
-     * @JSFProperty
      */
-    public boolean isPreserveDataModel()
-    {
-        if (_preserveDataModel != null)
-            return _preserveDataModel.booleanValue();
-        ValueBinding vb = getValueBinding("preserveDataModel");
-        Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
-        return v != null ? v.booleanValue() : DEFAULT_PRESERVEDATAMODEL;
-    }
+    @JSFProperty
+    public abstract boolean isPreserveDataModel();
 
-    public void setPreserveSort(boolean preserveSort)
-    {
-        _preserveSort = Boolean.valueOf(preserveSort);
-    }
-    
     /**
      * Indicates whether the state of the sortColumn and sortAscending 
      * attribute should be saved and restored and written back to the 
      * model during the update model phase. Default: true
      * 
-     * @JSFProperty
-     *   defaultValue = "true"
      */
-    public boolean isPreserveSort()
-    {
-        if (_preserveSort != null)
-            return _preserveSort.booleanValue();
-        ValueBinding vb = getValueBinding("preserveSort");
-        Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
-        return v != null ? v.booleanValue() : DEFAULT_PRESERVESORT;
-    }
+    @JSFProperty(defaultValue = "true")
+    public abstract boolean isPreserveSort();
 
     /**
      * Indicates whether this table should be rendered if the 
@@ -1623,25 +1705,24 @@ public abstract class AbstractHtmlDataTa
      * the DataModel and calles the model getter only once 
      * per request. Default: true
      * 
-     * @JSFProperty
-     *   defaultValue = "true"
      */
+    @JSFProperty(defaultValue = "true")
     public abstract boolean isRenderedIfEmpty();
 
     /**
      * A parameter name, under which the current rowIndex is set 
      * in request scope similar to the var parameter.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getRowIndexVar();
     
     /**
      * A parameter name, under which the rowCount is set in 
      * request scope similar to the var parameter.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getRowCountVar();
 
     /**
@@ -1651,8 +1732,8 @@ public abstract class AbstractHtmlDataTa
      * request scope attribute is null in the first row or 
      * when isRowAvailable returns false for the previous row.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getPreviousRowDataVar();
 
     /**
@@ -1660,43 +1741,54 @@ public abstract class AbstractHtmlDataTa
      * scope similar to the var parameter. TRUE for the column that 
      * is currently sorted, FALSE otherwise.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getSortedColumnVar();
     
     /**
      * HTML: Specifies the horizontal alignment of this element. 
      * Deprecated in HTML 4.01.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getAlign();
 
     /**
      * The id to use for
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getRowId();
         
     /**
      * Reserved for future use.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getDatafld();
     
     /**
      * Reserved for future use.
      * 
-     * @JSFProperty
      */
+    @JSFProperty
     public abstract String getDatasrc();
     
     /**
      * Reserved for future use.
      * 
-     * @JSFProperty
      */
-    public abstract String getDataformatas();    
+    @JSFProperty
+    public abstract String getDataformatas();
+    
+    protected enum PropertyKeys
+    {
+        preservedDataModel
+        , forceIdIndexFormula
+        , sortColumn
+        , sortAscending
+        , varDetailToggler
+        , expandedNodes
+        , sortColumnIndex
+    }
 }

Modified: myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTableHack.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTableHack.java?rev=937536&r1=937535&r2=937536&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTableHack.java (original)
+++ myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTableHack.java Fri Apr 23 21:52:24 2010
@@ -27,10 +27,11 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import javax.el.ValueExpression;
 import javax.faces.application.FacesMessage;
 import javax.faces.component.EditableValueHolder;
-import javax.faces.component.NamingContainer;
 import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
 import javax.faces.context.FacesContext;
 import javax.faces.el.ValueBinding;
 import javax.faces.model.ArrayDataModel;
@@ -41,8 +42,6 @@ import javax.faces.model.ResultSetDataMo
 import javax.faces.model.ScalarDataModel;
 import javax.servlet.jsp.jstl.sql.Result;
 
-import org.apache.myfaces.component.ForceIdAware;
-import org.apache.myfaces.component.html.ext.HtmlCommandButton.PropertyKeys;
 import org.apache.myfaces.component.html.util.HtmlComponentUtils;
 import org.apache.myfaces.custom.ExtendedComponentBase;
 
@@ -61,13 +60,14 @@ public abstract class HtmlDataTableHack 
                 ExtendedComponentBase
                 
 {
-    private Map _dataModelMap = new HashMap();
+    @SuppressWarnings("unchecked")
+    private Map<String, DataModel> _dataModelMap = new HashMap<String, DataModel>();
 
     // will be set to false if the data should not be refreshed at the beginning of the encode phase
     private boolean _isValidChilds = true;
 
     // holds for each row the states of the child components of this UIData
-    private Map _rowStates = new HashMap();
+    private Map<String, Object> _rowStates = new HashMap<String, Object>();
 
     // contains the initial row state which is used to initialize each row
     private Object _initialDescendantComponentState = null;
@@ -76,6 +76,7 @@ public abstract class HtmlDataTableHack 
     // Every field and method from here is identical to UIData !!!!!!!!!
     // EXCEPTION: we can create a DataModel from a Collection
 
+    @SuppressWarnings("unchecked")
     private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
 
     private static final boolean DEFAULT_PRESERVEROWSTATES = false;
@@ -118,7 +119,8 @@ public abstract class HtmlDataTableHack 
             return clientId;
         }
         // the following code tries to avoid rowindex to be twice in the client id
-        int index = clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
+        char separator = UINamingContainer.getSeparatorChar(context);
+        int index = clientId.lastIndexOf(separator);
         if(index != -1)
         {
             String rowIndexString = clientId.substring(index + 1);
@@ -131,10 +133,10 @@ public abstract class HtmlDataTableHack 
             }
             catch(NumberFormatException e)
             {
-                return clientId + NamingContainer.SEPARATOR_CHAR + rowIndex;
+                return clientId + separator + rowIndex;
             }
         }
-        return clientId + NamingContainer.SEPARATOR_CHAR + rowIndex;
+        return clientId + separator + rowIndex;
     }
 
     /**
@@ -228,7 +230,7 @@ public abstract class HtmlDataTableHack 
 
     protected boolean hasErrorMessages(FacesContext context)
     {
-        for(Iterator iter = context.getMessages(); iter.hasNext();)
+        for(Iterator<FacesMessage> iter = context.getMessages(); iter.hasNext();)
         {
             FacesMessage message = (FacesMessage) iter.next();
             if(FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0)
@@ -248,6 +250,7 @@ public abstract class HtmlDataTableHack 
         super.encodeEnd(context);
     }
 
+    @SuppressWarnings("unchecked")
     public void setRowIndex(int rowIndex)
     {
         if (rowIndex < -1)
@@ -329,7 +332,8 @@ public abstract class HtmlDataTableHack 
         }
     }
 
-    protected void restoreDescendantComponentStates(Iterator childIterator,
+    @SuppressWarnings("unchecked")
+    protected void restoreDescendantComponentStates(Iterator<UIComponent> childIterator,
             Object state, boolean restoreChildFacets)
     {
         Iterator descendantStateIterator = null;
@@ -358,7 +362,7 @@ public abstract class HtmlDataTableHack 
                     ((EditableValueHolderState) childState)
                             .restoreState((EditableValueHolder) component);
                 }
-                Iterator childsIterator;
+                Iterator<UIComponent> childsIterator;
                 if (restoreChildFacets)
                 {
                     childsIterator = component.getFacetsAndChildren();
@@ -373,7 +377,8 @@ public abstract class HtmlDataTableHack 
         }
     }
 
-    protected Object saveDescendantComponentStates(Iterator childIterator,
+    @SuppressWarnings("unchecked")
+    protected Object saveDescendantComponentStates(Iterator<UIComponent> childIterator,
             boolean saveChildFacets)
     {
         Collection childStates = null;
@@ -386,7 +391,7 @@ public abstract class HtmlDataTableHack 
             UIComponent child = (UIComponent) childIterator.next();
             if(!child.isTransient())
             {
-                Iterator childsIterator;
+                Iterator<UIComponent> childsIterator;
                 if (saveChildFacets)
                 {
                     childsIterator = child.getFacetsAndChildren();
@@ -426,6 +431,24 @@ public abstract class HtmlDataTableHack 
         }
         super.setValueBinding(name, binding);
     }
+    
+    public void setValueExpression(String name, ValueExpression binding)
+    {
+        if (name == null)
+        {
+            throw new NullPointerException("name");
+        }
+        else if (name.equals("value"))
+        {
+            _dataModelMap.clear();
+        }
+        else if (name.equals("var") || name.equals("rowIndex"))
+        {
+            throw new IllegalArgumentException(
+                    "You can never set the 'rowIndex' or the 'var' attribute as a value-binding. Set the property directly instead. Name " + name);
+        }
+        super.setValueExpression(name, binding);
+    }
 
     /**
      * @see javax.faces.component.UIData#setValue(java.lang.Object)
@@ -438,6 +461,7 @@ public abstract class HtmlDataTableHack 
         _isValidChilds = true;
     }
 
+    @SuppressWarnings("unchecked")
     protected DataModel getDataModel()
     {
         DataModel dataModel = null;
@@ -458,6 +482,7 @@ public abstract class HtmlDataTableHack 
         return dataModel;
     }
 
+    @SuppressWarnings("unchecked")
     protected void setDataModel(DataModel datamodel)
     {
         UIComponent parent = getParent();
@@ -472,6 +497,7 @@ public abstract class HtmlDataTableHack 
     /**
      * Creates a new DataModel around the current value.
      */
+    @SuppressWarnings("unchecked")
     protected DataModel createDataModel()
     {
         Object value = getValue();
@@ -510,6 +536,7 @@ public abstract class HtmlDataTableHack 
         }
     }
     
+    @SuppressWarnings("unchecked")
     private static final DataModel EMPTY_DATA_MODEL = new _SerializableDataModel()
     {
         public boolean isRowAvailable()
@@ -631,20 +658,6 @@ public abstract class HtmlDataTableHack 
         getStateHelper().put(PropertyKeys.forceIdIndex, forceIdIndex );
     }
     
-    private static boolean booleanFromObject(Object obj, boolean defaultValue)
-    {
-        if(obj instanceof Boolean)
-        {
-            return ((Boolean) obj).booleanValue();
-        }
-        else if(obj instanceof String)
-        {
-            return Boolean.valueOf(((String) obj)).booleanValue();
-        }
-
-        return defaultValue;
-    }
-
     /**
      * Remove all preserved row state for the dataTable
      */