Hi,

the attachment contains the patches and new files (based on the current cvs) for a new component to make cross tables work.

An example is also included ;)

Mathias
Index: conf/faces-config.xml
===================================================================
RCS file: /home/cvspublic/incubator-myfaces/conf/faces-config.xml,v
retrieving revision 1.114
diff -u -r1.114 faces-config.xml
--- conf/faces-config.xml       15 Mar 2005 21:11:39 -0000      1.114
+++ conf/faces-config.xml       24 Mar 2005 13:59:56 -0000
@@ -281,6 +281,10 @@
     
<component-class>org.apache.myfaces.custom.swapimage.HtmlSwapImage</component-class>
   </component>
 
+       <component>
+               <component-type>org.apache.myfaces.Columns</component-type>
+               
<component-class>org.apache.myfaces.component.UIColumns</component-class>
+       </component>
 
     <!-- additional "by type" converters -->
 
Index: HtmlDataTable.java
===================================================================
RCS file: 
/home/cvspublic/incubator-myfaces/src/components/org/apache/myfaces/component/html/ext/HtmlDataTable.java,v
retrieving revision 1.19
diff -u -r1.19 HtmlDataTable.java
--- HtmlDataTable.java  21 Mar 2005 12:33:46 -0000      1.19
+++ HtmlDataTable.java  24 Mar 2005 14:02:29 -0000
@@ -17,6 +17,7 @@
 
 import org.apache.myfaces.component.UserRoleAware;
 import org.apache.myfaces.component.UserRoleUtils;
+import org.apache.myfaces.component.UIColumns;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -28,6 +29,7 @@
 import javax.faces.event.FacesEvent;
 import javax.faces.model.DataModel;
 import javax.faces.render.Renderer;
+
 import java.io.IOException;
 import java.sql.ResultSet;
 import java.util.Iterator;
@@ -94,6 +96,10 @@
 {
     private static final Log log = LogFactory.getLog(HtmlDataTable.class);
 
+    private static final int PROCESS_DECODES = 1;
+    private static final int PROCESS_VALIDATORS = 2;
+    private static final int PROCESS_UPDATES = 3;
+
     private static final boolean DEFAULT_SORTASCENDING = true;
     private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
 
@@ -186,12 +192,122 @@
 
     public void processDecodes(FacesContext context)
     {
+        if(!isRendered())
+        {
+          return;
+        }
         super.processDecodes(context);
+        setRowIndex(-1);
+        processColumnsFacets(context, PROCESS_DECODES);
+        processColumnsChildren(context, PROCESS_DECODES);
+        setRowIndex(-1);
+    }
+
+    /**
+     * @param context
+     * @param processAction
+     */
+    private void processColumnsChildren(FacesContext context, int 
processAction)
+    {
+      int first = getFirst();
+      int rows = getRows();
+      int last;
+      if (rows == 0)
+      {
+        last = getRowCount();
+      }
+      else
+      {
+        last = first + rows;
+      }
+      for (int rowIndex = first; rowIndex < last; rowIndex++)
+      {
+        setRowIndex(rowIndex);
+        if (isRowAvailable())
+        {
+          for (Iterator it = getChildren().iterator(); it.hasNext();)
+          {
+            UIComponent child = (UIComponent) it.next();
+            if (child instanceof UIColumns)
+            {
+              if (child.isRendered())
+              {
+                UIColumns columns = (UIColumns) child;
+                for (int colIndex = 0, size = columns.getRowCount(); colIndex 
< size; colIndex++)
+                {
+                  columns.setRowIndex(colIndex);
+                  for (Iterator columnChildIter = 
child.getChildren().iterator(); columnChildIter
+                      .hasNext();)
+                  {
+                    UIComponent columnChild = (UIComponent) 
columnChildIter.next();
+                    process(context, columnChild, processAction);
+                  }
+                }
+                columns.setRowIndex(-1);
+              }
+            }
+          }
+        }
+      }
+    }
+
+
+    /**
+     * @param context
+     * @param processAction
+     */
+    private void processColumnsFacets(FacesContext context, int processAction)
+    {
+      for (Iterator childIter = getChildren().iterator(); childIter.hasNext();)
+      {
+        UIComponent child = (UIComponent) childIter.next();
+        if (child instanceof UIColumns)
+        {
+          if(child.isRendered())
+          {
+            UIColumns columns = (UIColumns) child;
+            for (int i = 0, size = columns.getRowCount(); i < size; i++)
+            {
+              columns.setRowIndex(i);
+              for (Iterator facetsIter = 
child.getFacets().values().iterator(); facetsIter.hasNext();)
+              {
+                UIComponent facet = (UIComponent) facetsIter.next();
+                process(context, facet, processAction);
+              }
+            }
+            columns.setRowIndex(-1);
+          }
+        }
+      }
+    }
+
+    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 processValidators(FacesContext context)
     {
-        super.processValidators(context);
+      if(!isRendered())
+      {
+        return;
+      }
+      super.processValidators(context);
+      setRowIndex(-1);
+      processColumnsFacets(context, PROCESS_VALIDATORS);
+      processColumnsChildren(context, PROCESS_VALIDATORS);
+      setRowIndex(-1);
     }
 
     public Object processSaveState(FacesContext context)
@@ -206,7 +322,15 @@
 
     public void processUpdates(FacesContext context)
     {
+        if(!isRendered())
+        {
+          return;
+        }
         super.processUpdates(context);
+        setRowIndex(-1);
+        processColumnsFacets(context, PROCESS_UPDATES);
+        processColumnsChildren(context, PROCESS_UPDATES);
+        setRowIndex(-1);
 
         if (_isDataModelRestored)
         {
Index: HtmlTableRendererBase.java
===================================================================
RCS file: 
/home/cvspublic/incubator-myfaces/src/share/org/apache/myfaces/renderkit/html/HtmlTableRendererBase.java,v
retrieving revision 1.8
diff -u -r1.8 HtmlTableRendererBase.java
--- HtmlTableRendererBase.java  11 Feb 2005 16:03:00 -0000      1.8
+++ HtmlTableRendererBase.java  24 Mar 2005 14:05:09 -0000
@@ -19,6 +19,7 @@
 import org.apache.myfaces.renderkit.RendererUtils;
 import org.apache.myfaces.util.ArrayUtils;
 import org.apache.myfaces.util.StringUtils;
+import org.apache.myfaces.component.UIColumns;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -148,10 +149,24 @@
             for (int j = 0, size = component.getChildCount(); j < size; j++)
             {
                 UIComponent child = (UIComponent) children.get(j);
-                if (child instanceof UIColumn && ((UIColumn) 
child).isRendered())
+                if(child.isRendered())
                 {
-                       String columnStyle = styles.getColumnStyle(j);
-                    renderColumnBody(facesContext, writer, uiData, (UIColumn) 
child, columnStyle);
+                    if (child instanceof UIColumn)
+                    {
+                        String columnStyle = styles.getColumnStyle(j);
+                          renderColumnBody(facesContext, writer, uiData, 
child, columnStyle);
+                    }
+                    else if (child instanceof UIColumns)
+                    {
+                        UIColumns columns = (UIColumns) child;
+                        for (int k = 0, colSize = columns.getRowCount(); k < 
colSize; k++)
+                        {
+                            columns.setRowIndex(k);
+                            String columnStyle = styles.getColumnStyle(j);
+                            renderColumnBody(facesContext, writer, uiData, 
child, columnStyle);

+                        }
+                        columns.setRowIndex(-1);
+                    }
                 }
             }
             renderRowEnd(facesContext, writer, uiData);
@@ -166,7 +181,7 @@
      * @param facesContext the <code>FacesContext</code>.
      * @param writer the <code>ResponseWriter</code>.
      * @param uiData the <code>UIData</code> being rendered.
-     * @param column the <code>UIColumn</code> to render.
+     * @param component the <code>UIComponent</code> to render.
      * @param columnStyleClass the styleClass of the <code>UIColumn</code> or 
<code>null</code> if
      * there is none.
      * @throws IOException if an exception occurs.
@@ -175,7 +190,7 @@
                FacesContext facesContext,
                ResponseWriter writer,
                UIData uiData,
-               UIColumn column,
+               UIComponent component,
                String columnStyleClass) throws IOException
        {
                writer.startElement(HTML.TD_ELEM, uiData);
@@ -184,7 +199,7 @@
                        writer.writeAttribute(HTML.CLASS_ATTR, 
columnStyleClass, null);
                }
                
-        RendererUtils.renderChild(facesContext, column);
+        RendererUtils.renderChild(facesContext, component);
         writer.endElement(HTML.TD_ELEM);
        }
     
@@ -291,14 +306,26 @@
         for (Iterator it = component.getChildren().iterator(); it.hasNext();)
         {
             UIComponent uiComponent = (UIComponent) it.next();
-            if (uiComponent instanceof UIColumn && ((UIColumn) 
uiComponent).isRendered())
+            if(uiComponent.isRendered())
             {
-                colspan++;
-                if (!hasColumnFacet)
-                {
-                    hasColumnFacet = header ? ((UIColumn) 
uiComponent).getHeader() != null : ((UIColumn) uiComponent)
-                            .getFooter() != null;
-                }
+              if (uiComponent instanceof UIColumn)
+              {
+                  colspan++;
+                  if (!hasColumnFacet)
+                  {
+                      hasColumnFacet = header ? ((UIColumn) 
uiComponent).getHeader() != null : ((UIColumn) uiComponent)
+                              .getFooter() != null;
+                  }
+              }
+              else if (uiComponent instanceof UIColumns)
+              {
+                  UIColumns columns = (UIColumns) uiComponent;
+                  colspan += columns.getRowCount();
+                  if (!hasColumnFacet)
+                  {
+                      hasColumnFacet = header ? columns.getHeader() != null : 
columns.getFooter() != null;
+                  }
+              }
             }
         }
 
@@ -420,8 +447,8 @@
         writer.endElement(HTML.TR_ELEM);
     }
 
-    private void renderColumnHeaderOrFooterRow(FacesContext facesContext, 
ResponseWriter writer, UIComponent component,
-            String styleClass, boolean header) throws IOException
+    private void renderColumnHeaderOrFooterRow(FacesContext facesContext, 
ResponseWriter writer, 
+            UIComponent component, String styleClass, boolean header) throws 
IOException
     {
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
 
@@ -429,35 +456,76 @@
         for (Iterator it = component.getChildren().iterator(); it.hasNext();)
         {
             UIComponent uiComponent = (UIComponent) it.next();
-            if (uiComponent instanceof UIColumn && ((UIColumn) 
uiComponent).isRendered())
+            if(uiComponent.isRendered())
             {
-                if (header)
-                {
-                    renderColumnHeaderCell(facesContext, writer, (UIColumn) 
uiComponent, styleClass, 0);
-                }
-                else
-                {
-                    renderColumnFooterCell(facesContext, writer, (UIColumn) 
uiComponent, styleClass, 0);
-                }
+              if (uiComponent instanceof UIColumn)
+              {
+                  if (header)
+                  {
+                      renderColumnHeaderCell(facesContext, writer, 
uiComponent, 
+                          ((UIColumn) uiComponent).getHeader(), styleClass, 0);
+                  }
+                  else
+                  {
+                      renderColumnFooterCell(facesContext, writer, 
uiComponent, 
+                          ((UIColumn) uiComponent).getFooter(), styleClass, 0);
+                  }
+              }
+              else if (uiComponent instanceof UIColumns)
+              {
+                  UIColumns columns = (UIColumns) uiComponent;
+                  for (int i = 0, size = columns.getRowCount(); i < size; i++)
+                  {
+                      columns.setRowIndex(i);
+                      if (header)
+                      {
+                          renderColumnHeaderCell(facesContext, writer, 
columns, columns.getHeader(),
+                              styleClass, 0);
+                      }
+                      else
+                      {
+                          renderColumnFooterCell(facesContext, writer, 
columns, columns.getFooter(),
+                              styleClass, 0);
+                      }
+                  }
+                  columns.setRowIndex(-1);
+              }
             }
         }
         writer.endElement(HTML.TR_ELEM);
     }
 
-       /**
+    /**
+     * Renders the header facet for the given <code>UIColumn</code>.
+     * @param facesContext the <code>FacesContext</code>.
+     * @param writer the <code>ResponseWriter</code>.
+     * @param uiColumn the <code>UIColumn</code>.
+     * @param headerStyleClass the styleClass of the header facet.
+     * @param colspan the colspan for the tableData element in which the 
header facet
+     * will be wrapped.
+     * @throws IOException
+     */
+    protected void renderColumnHeaderCell(FacesContext facesContext, 
ResponseWriter writer, UIColumn uiColumn, 
+            String headerStyleClass, int colspan) throws IOException
+    {
+      renderColumnHeaderCell(facesContext, writer, uiColumn, 
uiColumn.getHeader(), headerStyleClass, colspan);
+    }
+
+    /**
         * Renders the header facet for the given <code>UIColumn</code>.
         * @param facesContext the <code>FacesContext</code>.
         * @param writer the <code>ResponseWriter</code>.
-        * @param uiColumn the <code>UIColumn</code>.
+        * @param uiComponent the <code>UIComponent</code> to render the facet 
for.
+     * @param facet the <code>UIComponent</code> to render as facet.
         * @param headerStyleClass the styleClass of the header facet.
         * @param colspan the colspan for the tableData element in which the 
header facet
         * will be wrapped.
         * @throws IOException
         */
-    protected void renderColumnHeaderCell(FacesContext facesContext, 
ResponseWriter writer, UIColumn uiColumn,
-            String headerStyleClass, int colspan) throws IOException
+    protected void renderColumnHeaderCell(FacesContext facesContext, 
ResponseWriter writer, UIComponent uiComponent, 
+            UIComponent facet, String headerStyleClass, int colspan) throws 
IOException
     {
-        writer.startElement(HTML.TH_ELEM, uiColumn);
+        writer.startElement(HTML.TH_ELEM, uiComponent);
         if (colspan > 1)
         {
             writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), 
null);
@@ -466,7 +534,6 @@
         {
             writer.writeAttribute(HTML.CLASS_ATTR, headerStyleClass, null);
         }
-        UIComponent facet = uiColumn.getHeader();
         if (facet != null)
         {
             RendererUtils.renderChild(facesContext, facet);
@@ -474,20 +541,37 @@
         writer.endElement(HTML.TH_ELEM);
     }
 
+    /**
+     * Renders the footer facet for the given <code>UIColumn</code>.
+     * @param facesContext the <code>FacesContext</code>.
+     * @param writer the <code>ResponseWriter</code>.
+     * @param uiColumn the <code>UIComponent</code>.
+     * @param footerStyleClass the styleClass of the footer facet.
+     * @param colspan the colspan for the tableData element in which the 
footer facet
+     * will be wrapped.
+     * @throws IOException
+     */
+    protected void renderColumnFooterCell(FacesContext facesContext, 
ResponseWriter writer, UIColumn uiColumn, 
+        String footerStyleClass, int colspan) throws IOException
+    {      
+      renderColumnFooterCell(facesContext, writer, uiColumn, 
uiColumn.getFooter(), footerStyleClass, colspan);
+    }
+    
        /**
         * Renders the footer facet for the given <code>UIColumn</code>.
         * @param facesContext the <code>FacesContext</code>.
         * @param writer the <code>ResponseWriter</code>.
-        * @param uiColumn the <code>UIColumn</code>.
+        * @param uiComponent the <code>UIComponent</code> to render the facet 
for.
+     * @param facet the <code>UIComponent</code> to render as facet.
         * @param footerStyleClass the styleClass of the footer facet.
         * @param colspan the colspan for the tableData element in which the 
footer facet
         * will be wrapped.
         * @throws IOException
         */
-    protected void renderColumnFooterCell(FacesContext facesContext, 
ResponseWriter writer, UIColumn uiColumn,
-            String footerStyleClass, int colspan) throws IOException
+    protected void renderColumnFooterCell(FacesContext facesContext, 
ResponseWriter writer, UIComponent uiComponent, 
+        UIComponent facet, String footerStyleClass, int colspan) throws 
IOException
     {
-        writer.startElement(HTML.TD_ELEM, uiColumn);
+        writer.startElement(HTML.TD_ELEM, uiComponent);
         if (colspan > 1)
         {
             writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), 
null);
@@ -496,7 +580,6 @@
         {
             writer.writeAttribute(HTML.CLASS_ATTR, footerStyleClass, null);
         }
-        UIComponent facet = uiColumn.getFooter();
         if (facet != null)
         {
             RendererUtils.renderChild(facesContext, facet);
Index: tlds/myfaces_ext.tld
===================================================================
RCS file: /home/cvspublic/incubator-myfaces/tlds/myfaces_ext.tld,v
retrieving revision 1.182
diff -u -r1.182 myfaces_ext.tld
--- tlds/myfaces_ext.tld        22 Mar 2005 02:13:28 -0000      1.182
+++ tlds/myfaces_ext.tld        24 Mar 2005 14:00:02 -0000
@@ -2153,4 +2153,24 @@
         <attribute><name>onkeyup</name>    <required>false</required>  
<rtexprvalue>false</rtexprvalue></attribute>
     </tag>
 
+       <!-- columns -->
+    <tag>
+        <name>columns</name>
+        
<tag-class>org.apache.myfaces.custom.crosstable.HtmlColumnsTag</tag-class>
+        <body-content>JSP</body-content>
+        &ui_component_attributes;
+        &ui_column_attributes;
+        <attribute>
+            <name>value</name>
+            <required>true</required>
+            <rtexprvalue>false</rtexprvalue>
+            <description>Supported types see JSF Spec 4.1.3</description>
+        </attribute>
+        <attribute>
+            <name>var</name>
+            <required>true</required>
+            <rtexprvalue>false</rtexprvalue>
+        </attribute>
+     </tag>
+
 </taglib>
Index: webapps/examples/WEB-INF/examples-config.xml
===================================================================
RCS file: 
/home/cvspublic/incubator-myfaces/webapps/examples/WEB-INF/examples-config.xml,v
retrieving revision 1.1
diff -u -r1.1 examples-config.xml
--- webapps/examples/WEB-INF/examples-config.xml        12 Mar 2005 11:40:07 
-0000      1.1
+++ webapps/examples/WEB-INF/examples-config.xml        24 Mar 2005 14:00:03 
-0000
@@ -241,7 +241,15 @@
         <managed-bean-class>java.util.HashMap</managed-bean-class>
         <managed-bean-scope>session</managed-bean-scope>
     </managed-bean>
-
+    
+    
+    <!-- Managed Beans for crosstable example -->
+
+    <managed-bean>
+        <managed-bean-name>crossDataTable</managed-bean-name>
+        
<managed-bean-class>org.apache.myfaces.examples.crosstable.DataBean</managed-bean-class>
+        <managed-bean-scope>session</managed-bean-scope>
+    </managed-bean>
 
 
     <navigation-rule>
@@ -413,6 +421,11 @@
             <to-view-id>/selectOneCountry.jsp</to-view-id>

         </navigation-case>
 
+        <navigation-case>
+            <from-outcome>go_crossDataTable</from-outcome>
+            <to-view-id>/crossDataTable.jsp</to-view-id>
+        </navigation-case>
+
     </navigation-rule>
 
     <navigation-rule>
Index: webapps/examples/inc/navigation.jsp
===================================================================
RCS file: 
/home/cvspublic/incubator-myfaces/webapps/examples/inc/navigation.jsp,v
retrieving revision 1.1
diff -u -r1.1 navigation.jsp
--- webapps/examples/inc/navigation.jsp 12 Mar 2005 11:40:06 -0000      1.1
+++ webapps/examples/inc/navigation.jsp 24 Mar 2005 14:00:03 -0000
@@ -39,6 +39,7 @@
             <x:commandNavigation id="nav_2_4_17" 
value="#{example_messages['nav_swapimage']}" action="go_swapimage" />
             <x:commandNavigation id="nav_2_4_18" 
value="#{example_messages['nav_forceId']}" action="go_forceId" />
             <x:commandNavigation id="nav_2_4_19" 
value="#{example_messages['nav_selectOneCountry']}" 
action="go_selectOneCountry" />
+            <x:commandNavigation id="nav_2_4_20" 
value="#{example_messages['nav_crossDataTable']}" action="go_crossDataTable" />
         </x:commandNavigation>
     </x:commandNavigation>
     <x:commandNavigation id="nav_3" 
value="#{example_messages['nav_Documentation']}" >
Index: 
webapps/src/org/apache/myfaces/examples/resource/example_messages.properties
===================================================================
RCS file: 
/home/cvspublic/incubator-myfaces/webapps/src/org/apache/myfaces/examples/resource/example_messages.properties,v
retrieving revision 1.1
diff -u -r1.1 example_messages.properties
--- 
webapps/src/org/apache/myfaces/examples/resource/example_messages.properties    
    12 Mar 2005 11:40:06 -0000      1.1
+++ 
webapps/src/org/apache/myfaces/examples/resource/example_messages.properties    
    24 Mar 2005 14:00:04 -0000
@@ -37,8 +37,9 @@
 nav_HtmlEditor         = Html Editor
 nav_forceId         = ForceId
 nav_selectOneCountry= Select a country box
-
 nav_swapimage       = SwapImage
+nav_crossDataTable  = Crosstable
+
 # buttons
 
 button_save = Save
@@ -162,4 +163,9 @@
 css_msg=A simple test for the 
 
 forceOne=Value 1
-forceTwo=Value 2 (with forceId)
\ No newline at end of file
+forceTwo=Value 2 (with forceId)
+
+crosstable_field_column=column label
+crosstable_add_column=add a column
+crosstable_remove_column=remove the column
+crosstable_save_values=save values
\ No newline at end of file
Index: 
webapps/src/org/apache/myfaces/examples/resource/example_messages_de.properties
===================================================================
RCS file: 
/home/cvspublic/incubator-myfaces/webapps/src/org/apache/myfaces/examples/resource/example_messages_de.properties,v
retrieving revision 1.1
diff -u -r1.1 example_messages_de.properties
--- 
webapps/src/org/apache/myfaces/examples/resource/example_messages_de.properties 
    12 Mar 2005 11:40:06 -0000      1.1
+++ 
webapps/src/org/apache/myfaces/examples/resource/example_messages_de.properties 
    24 Mar 2005 14:00:04 -0000
@@ -32,6 +32,7 @@
 nav_newspaperTable  = Newspaper Table
 nav_forceId         = ForceId
 nav_swapimage       = SwapImage
+nav_crossDataTable  = Kreuztabelle
 
 # buttons
 
@@ -105,3 +106,8 @@
 
 forceOne=Eingabe 1
 forceTwo=Eingabe 2 (mit forceId) 
+
+crosstable_field_column=Spaltenname
+crosstable_add_column=Spalte hinzuf�gen
+crosstable_remove_column=Spalte l�schen
+crosstable_save_values=Werte speichern
\ No newline at end of file
Index: src/components/org/apache/myfaces/custom/crosstable/HtmlColumnsTag.java
===================================================================
RCS file: 
src/components/org/apache/myfaces/custom/crosstable/HtmlColumnsTag.java
diff -N src/components/org/apache/myfaces/custom/crosstable/HtmlColumnsTag.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/components/org/apache/myfaces/custom/crosstable/HtmlColumnsTag.java     
1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.crosstable;
+
+import javax.faces.component.UIComponent;
+
+import org.apache.myfaces.component.UIColumns;
+import org.apache.myfaces.renderkit.JSFAttr;
+import org.apache.myfaces.taglib.html.HtmlComponentBodyTagBase;
+
+/**
+ * @author Mathias Broekelmann (latest modification by $Author: Mathias 
Broekelmann $)
+ * @version $Revision$ $Date$
+ * $Log$
+ */
+public class HtmlColumnsTag extends HtmlComponentBodyTagBase
+{
+  private String mVar;
+
+  /**
+   * @see javax.faces.webapp.UIComponentTag#getComponentType()
+   */
+  public String getComponentType()
+  {
+    return UIColumns.COMPONENT_TYPE;
+  }
+
+  /**
+   * @see javax.faces.webapp.UIComponentTag#getRendererType()
+   */
+  public String getRendererType()
+  {
+    return null;
+  }
+
+  public void setVar(String var)
+  {
+    mVar = var;
+  }
+
+  protected void setProperties(UIComponent component)
+  {
+    super.setProperties(component);
+
+    setStringProperty(component, JSFAttr.VAR_ATTR, mVar);
+  }
+}
Index: src/share/org/apache/myfaces/component/UIColumns.java
===================================================================
RCS file: src/share/org/apache/myfaces/component/UIColumns.java
diff -N src/share/org/apache/myfaces/component/UIColumns.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/share/org/apache/myfaces/component/UIColumns.java       1 Jan 1970 
00:00:00 -0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.component;
+
+import javax.faces.component.UIData;
+
+/**
+ * @author Mathias Broekelmann (latest modification by $Author: Mathias 
Broekelmann $)
+ * @version $Revision$ $Date$
+ * $Log$
+ */
+public class UIColumns extends UIData
+{
+  public static final String COMPONENT_TYPE = "org.apache.myfaces.Columns";
+  public static final String COMPONENT_FAMILY = UIData.COMPONENT_FAMILY;
+
+  /**
+   * 
+   */
+  public UIColumns()
+  {
+    super();
+  }
+  
+  /**
+   * @see javax.faces.component.UIComponentBase#getRendererType()
+   */
+  public String getRendererType()
+  {
+    return null;
+  }
+
+  /**
+   * @see javax.faces.component.UIComponent#getFamily()
+   */
+  public String getFamily()
+  {
+    return COMPONENT_FAMILY;
+  }
+}
Index: webapps/examples/crossDataTable.jsp
===================================================================
RCS file: webapps/examples/crossDataTable.jsp
diff -N webapps/examples/crossDataTable.jsp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ webapps/examples/crossDataTable.jsp 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,130 @@
+<%@ page session="false" contentType="text/html;charset=utf-8"%>
+<%@ taglib uri="http://java.sun.com/jsf/html"; prefix="h"%>
+<%@ taglib uri="http://java.sun.com/jsf/core"; prefix="f"%>
+<%@ taglib uri="http://myfaces.apache.org/extensions"; prefix="x"%>
+<html>
+
+<!--
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+//-->
+
+<[EMAIL PROTECTED] file="inc/head.inc"%>
+
+<body>
+
+<!--
+managed beans used:
+    countryList
+-->
+
+<f:view>
+
+       <f:loadBundle
+               basename="org.apache.myfaces.examples.resource.example_messages"
+               var="example_messages" />
+
+       <x:panelLayout id="page" layout="#{globalOptions.pageLayout}"
+               styleClass="pageLayout" headerClass="pageHeader"
+               navigationClass="pageNavigation" bodyClass="pageBody"
+               footerClass="pageFooter">
+
+               <f:facet name="header">
+                       <f:subview id="header">
+                               <jsp:include page="inc/page_header.jsp" />
+                       </f:subview>
+               </f:facet>
+
+               <f:facet name="navigation">
+                       <f:subview id="menu">
+                               <jsp:include page="inc/navigation.jsp" />
+                       </f:subview>
+               </f:facet>
+
+               <f:facet name="body">
+                       <h:form>
+                       <h:panelGroup id="body">
+
+                               <h:panelGrid columns="1">
+                                       <h:commandLink 
rendered="#{!crossDataTable.editValues}" action="#{crossDataTable.editValues}"
+                                               immediate="true">
+                                               <h:outputText 
value="#{example_messages['country_edit_table']}"
+                                                       styleClass="standard" />
+                                       </h:commandLink>
+                                       <h:panelGrid 
rendered="#{!crossDataTable.editValues}" columns="3">
+                                               <h:outputLabel 
for="columnLabel" value="#{example_messages['crosstable_field_column']}"/>
+                                               <h:inputText id="columnLabel" 
value="#{crossDataTable.columnLabel}" />
+                                               <h:commandLink 
action="#{crossDataTable.addColumn}">
+                                                       <h:outputText 
value="#{example_messages['crosstable_add_column']}"
+                                                               
styleClass="standard" />
+                                               </h:commandLink>
+                                       </h:panelGrid>
+                                       <h:commandLink 
rendered="#{crossDataTable.editValues}" action="#{crossDataTable.saveValues}">
+                                               <h:outputText 
value="#{example_messages['crosstable_save_values']}"
+                                                       styleClass="standard" />
+                                       </h:commandLink>
+                               </h:panelGrid>
+                               <f:verbatim>
+                                       <br>
+                               </f:verbatim>
+
+                               <x:dataTable id="data" 
styleClass="standardTable"
+                                       headerClass="standardTable_Header"
+                                       footerClass="standardTable_Header"
+                                       
rowClasses="standardTable_Row1,standardTable_Row2"
+                                       columnClasses="standardTable_Column" 
var="country"
+                                       
value="#{crossDataTable.countryDataModel}" preserveDataModel="false">
+                                       <h:column>
+                                               <f:facet name="header">
+                                                       <h:outputText 
value="#{example_messages['label_country_name']}" />
+                                               </f:facet>
+                                               <h:outputText 
value="#{country.name}" />
+                                       </h:column>
+
+                                       <x:columns 
value="#{crossDataTable.columnDataModel}" var="column">
+                                               <f:facet name="header">
+                                                       <h:panelGroup>
+                                                               <h:outputText 
value="#{column} " />
+                                                               <h:commandLink 
action="#{crossDataTable.removeColumn}">
+                                                                       
<h:outputText value="-" title="#{example_messages['crosstable_remove_column']}" 
/>
+                                                               </h:commandLink>
+                                                       </h:panelGroup>
+                                               </f:facet>
+                                               <h:outputText 
rendered="#{!crossDataTable.editValues}"
+                                                       
value="#{crossDataTable.columnValue}" />
+                                               <h:inputText 
rendered="#{crossDataTable.editValues}"
+                                                       
value="#{crossDataTable.columnValue}" />
+                                       </x:columns>
+
+                               </x:dataTable>
+
+                               <f:verbatim>
+                                       <br>
+                               </f:verbatim>
+
+                       </h:panelGroup>
+                       </h:form>
+               </f:facet>
+
+               <[EMAIL PROTECTED] file="inc/page_footer.jsp"%>
+
+       </x:panelLayout>
+
+</f:view>
+
+</body>
+
+</html>
Index: webapps/src/org/apache/myfaces/examples/crosstable/DataBean.java
===================================================================
RCS file: webapps/src/org/apache/myfaces/examples/crosstable/DataBean.java
diff -N webapps/src/org/apache/myfaces/examples/crosstable/DataBean.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ webapps/src/org/apache/myfaces/examples/crosstable/DataBean.java    1 Jan 
1970 00:00:00 -0000
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.examples.crosstable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.model.DataModel;
+import javax.faces.model.ListDataModel;
+
+import org.apache.myfaces.examples.listexample.SimpleCountry;
+import org.apache.myfaces.examples.listexample.SimpleCountryList;
+
+/**
+ * @author Mathias Broekelmann (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class DataBean extends SimpleCountryList
+{
+  private DataModel mColumns;
+  private DataModel mCountryDataModel;
+  private Map mValueMap = new HashMap();
+  private boolean mEditValues;
+  private String mColumnLabel;
+
+  /**
+   * 
+   */
+  public DataBean()
+  {
+    super();
+  }
+
+  public boolean isEditValues()
+  {
+    return mEditValues;
+  }
+
+  public String editValues()
+  {
+    mEditValues = true;
+    return null;
+  }
+
+  public String saveValues()
+  {
+    mEditValues = false;
+    return null;
+  }
+
+  public String addColumn()
+  {
+    if (mColumnLabel != null)
+    {
+      List columns = (List) getColumnDataModel().getWrappedData();
+      columns.add(mColumnLabel);
+    }
+    return null;
+  }
+
+  public String removeColumn()
+  {
+    if (mColumns != null && mColumns.isRowAvailable())
+    {
+      Object column = mColumns.getRowData();
+      List columns = (List) getColumnDataModel().getWrappedData();
+      columns.remove(column);
+    }
+    return null;
+  }
+
+  public String getColumnLabel()
+  {
+    return mColumnLabel;
+  }
+
+  public void setColumnLabel(String label)
+  {
+    mColumnLabel = label;
+  }
+
+  public DataModel getCountryDataModel()
+  {
+    if (mCountryDataModel == null)
+    {
+      mCountryDataModel = new ListDataModel(getCountries());
+    }
+    return mCountryDataModel;
+  }
+
+  public DataModel getColumnDataModel()
+  {
+    if (mColumns == null)
+    {
+      String[] result = new String[] {"2002", "2003", "2004"};
+      mColumns = new ListDataModel(new ArrayList(Arrays.asList(result)));
+    }
+    return mColumns;
+  }
+
+  public String getColumnValue()
+  {
+    DataModel countryDataModel = getCountryDataModel();
+    if (countryDataModel.isRowAvailable())
+    {
+      SimpleCountry row = (SimpleCountry) countryDataModel.getRowData();
+      DataModel columnDataModel = getColumnDataModel();
+      if (columnDataModel.isRowAvailable())
+      {
+        Object column = columnDataModel.getRowData();
+        Object key = new RowColumnKey(new Long(row.getId()), column);
+        if (!mValueMap.containsKey(key))
+        {
+          // initialize with random value
+          String randomValue = String.valueOf((int) (Math.random() * 5000) + 
5000);
+          mValueMap.put(key, randomValue);
+        }
+        return (String) mValueMap.get(key);
+      }
+    }
+    return null;
+  }
+
+  public void setColumnValue(String value)
+  {
+    DataModel countryDataModel = getCountryDataModel();
+    if (countryDataModel.isRowAvailable())
+    {
+      SimpleCountry row = (SimpleCountry) countryDataModel.getRowData();
+      DataModel columnDataModel = getColumnDataModel();
+      if (columnDataModel.isRowAvailable())
+      {
+        Object column = columnDataModel.getRowData();
+        Object key = new RowColumnKey(new Long(row.getId()), column);
+        mValueMap.put(key, value);
+      }
+    }
+  }
+
+  private class RowColumnKey
+  {
+    private final Object mRow;
+    private final Object mColumn;
+
+    /**
+     * @param row
+     * @param column
+     */
+    public RowColumnKey(Object row, Object column)
+    {
+      mRow = row;
+      mColumn = column;
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object obj)
+    {
+      if (obj == null)
+      {
+        return false;
+      }
+      if (obj == this)
+      {
+        return true;
+      }
+      if (obj instanceof RowColumnKey)
+      {
+        RowColumnKey other = (RowColumnKey) obj;
+        return other.mRow.equals(mRow) && other.mColumn.equals(mColumn);
+      }
+      return super.equals(obj);
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode()
+    {
+      return (37 * 3 + mRow.hashCode()) * (37 * 3 + mColumn.hashCode());
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+      return mRow.toString() + "," + mColumn.toString();
+    }
+  }
+}
+
+/**
+ * $Log$
+ */
 

Reply via email to