You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by im...@apache.org on 2008/02/06 20:20:48 UTC

svn commit: r619111 - in /myfaces: shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/ tomahawk/trunk/core/src/main/java/org/apache/myfaces/component/html/ext/ tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/ex...

Author: imario
Date: Wed Feb  6 11:20:40 2008
New Revision: 619111

URL: http://svn.apache.org/viewvc?rev=619111&view=rev
Log:
TOMAHAWK-1181: allow to embed the child table within the parent to share the same layout.

Three new attribute on the datatable have been added:
embedded true|false
Render the table in the embedded mode (no table/thead/tfoot/th tags will be used)

detailStampLocation after|before
Render the detailStamp after of before the row of the master table.
"before" allow you to treat the master table as a list of summs of the child tables data. 

detailStampExpandedDefault true|false
Render all the details by default.

Modified:
    myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTable.java
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/ext/HtmlTableRenderer.java
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/taglib/html/ext/HtmlDataTableTag.java
    myfaces/tomahawk/trunk/core/src/main/tld/entities/extended_data_table_attributes.xml
    myfaces/tomahawk/trunk/examples/simple/src/main/webapp/masterDetail.jsp

Modified: myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java?rev=619111&r1=619110&r2=619111&view=diff
==============================================================================
--- myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java (original)
+++ myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlTableRendererBase.java Wed Feb  6 11:20:40 2008
@@ -18,9 +18,12 @@
  */
 package org.apache.myfaces.shared.renderkit.html;
 
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.shared.renderkit.JSFAttr;
+import org.apache.myfaces.shared.renderkit.RendererUtils;
+import org.apache.myfaces.shared.util.ArrayUtils;
+import org.apache.myfaces.shared.util.StringUtils;
 
 import javax.faces.component.UIColumn;
 import javax.faces.component.UIComponent;
@@ -28,18 +31,14 @@
 import javax.faces.component.html.HtmlDataTable;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.myfaces.shared.renderkit.JSFAttr;
-import org.apache.myfaces.shared.renderkit.RendererUtils;
-import org.apache.myfaces.shared.util.ArrayUtils;
-import org.apache.myfaces.shared.util.StringUtils;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * Common methods for renderers for components that subclass the standard
  * JSF HtmlDataTable component.
- * 
+ *
  * @author Thomas Spiegl (latest modification by $Author$)
  * @version $Revision$ $Date$
  */
@@ -50,7 +49,7 @@
 
     /** Footer facet name. */
     protected static final String FOOTER_FACET_NAME = "footer";
-    
+
     /** The logger. */
     private static final Log log = LogFactory.getLog(HtmlTableRendererBase.class);
 
@@ -96,26 +95,33 @@
 
     /**
      * Render the necessary bits that come before any actual <i>rows</i> in the table.
-     * 
+     *
      * @see javax.faces.render.Renderer#encodeBegin(FacesContext, UIComponent)
      */
     public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
     {
         RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
 
-        ResponseWriter writer = facesContext.getResponseWriter();
-
         beforeTable(facesContext, (UIData) uiComponent);
 
-        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
-        writer.startElement(HTML.TABLE_ELEM, uiComponent);
-        HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
-        HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, org.apache.myfaces.shared.renderkit.html.HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
+		startTable(facesContext, uiComponent);
     }
 
-    /**
+	/**
+	 * actually render the start of the table
+	 */
+	protected void startTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
+	{
+		ResponseWriter writer = facesContext.getResponseWriter();
+		HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+		writer.startElement(HTML.TABLE_ELEM, uiComponent);
+		HtmlRendererUtils.writeIdIfNecessary(writer, uiComponent, facesContext);
+		HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
+	}
+
+	/**
      * Render the TBODY section of the html table. See also method encodeInnerHtml.
-     * 
+     *
      * @see javax.faces.render.Renderer#encodeChildren(FacesContext, UIComponent)
      */
     public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
@@ -136,8 +142,8 @@
         writer.endElement(HTML.TBODY_ELEM);
 
         afterBody(facesContext, (UIData) component);
-    }  
-    
+    }
+
     /**
      * Gets styles for the specified component.
      */
@@ -199,7 +205,7 @@
     /**
      * Renders everything inside the TBODY tag by iterating over the row objects
      * between offsets first and first+rows and applying the UIColumn components
-     * to those objects. 
+     * to those objects.
      * <p>
      * This method is separated from the encodeChildren so that it can be overridden by
      * subclasses. One class that uses this functionality is autoUpdateDataTable.
@@ -261,7 +267,7 @@
                     currentRow = nr * newspaperColumns + nc + first;
                 else
                     currentRow = nc * newspaperRows + nr + first;
-                
+
                 // if this row is not to be rendered
                 if(currentRow >= last) continue;
 
@@ -279,7 +285,7 @@
                     HtmlRendererUtils.writePrettyLineSeparator(facesContext);
                     renderRowStart(facesContext, writer, uiData, styles, nr);
                 }
-    
+
                 List children = getChildren(component);
                 for (int j = 0, size = getChildCount(component); j < size; j++)
                 {
@@ -287,12 +293,12 @@
                     if (child.isRendered())
                     {
                         boolean columnRendering = child instanceof UIColumn;
-                        
+
                         if (columnRendering)
                             beforeColumn(facesContext, uiData, j);
-                           
-                        encodeColumnChild(facesContext, writer, uiData, child, styles, nc * uiData.getChildCount() + j);                    
-                       
+
+                        encodeColumnChild(facesContext, writer, uiData, child, styles, nc * uiData.getChildCount() + j);
+
                         if (columnRendering)
                             afterColumn(facesContext, uiData, j);
                     }
@@ -314,8 +320,8 @@
         UIData uiData, UIComponent component, Styles styles, int columnStyleIndex) throws IOException
     {
         if (component instanceof UIColumn)
-        {            
-            renderColumnBody(facesContext, writer, uiData, component, styles, columnStyleIndex);            
+        {
+            renderColumnBody(facesContext, writer, uiData, component, styles, columnStyleIndex);
         }
     }
 
@@ -324,7 +330,7 @@
      * the header and footer facets). This emits a TD cell, whose contents
      * are the result of calling encodeBegin, encodeChildren and
      * encodeEnd methods on the component (or its associated renderer).
-     * 
+     *
      * @param facesContext the <code>FacesContext</code>.
      * @param writer the <code>ResponseWriter</code>.
      * @param uiData the <code>UIData</code> being rendered.
@@ -345,7 +351,7 @@
         {
             writer.writeAttribute(HTML.CLASS_ATTR, styles.getColumnStyle(columnStyleIndex), null);
         }
-    
+
         RendererUtils.renderChild(facesContext, component);
         writer.endElement(HTML.TD_ELEM);
     }
@@ -366,9 +372,9 @@
         Styles styles, int rowStyleIndex) throws IOException
     {
         writer.startElement(HTML.TR_ELEM, uiData);
-        
+
         renderRowStyle(facesContext, writer, uiData, styles, rowStyleIndex);
-        
+
         Object rowId = uiData.getAttributes().get(org.apache.myfaces.shared.renderkit.JSFAttr.ROW_ID);
 
         if (rowId != null)
@@ -459,7 +465,7 @@
      * @param columnIndex the index of the currenly rendered column
      */
     protected void beforeColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
-    {        
+    {
     }
     /**
      * Perform any operations necessary immediately after each column child is rendered
@@ -469,7 +475,7 @@
      * @param columnIndex the index of the currenly rendered column
      */
     protected void afterColumn(FacesContext facesContext, UIData uiData, int columnIndex) throws IOException
-    {        
+    {
     }
     /**
      *Perform any operations necessary immediately before each column child's header or footer is rendered
@@ -480,7 +486,7 @@
      * @param columnIndex the index of the currenly rendered column
      */
     protected void beforeColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header, int columnIndex) throws IOException
-    {         
+    {
     }
     /**
      * Perform any operations necessary immediately after each column child's header of footer is rendered
@@ -491,7 +497,7 @@
      * @param columnIndex the index of the currenly rendered column
      */
     protected void afterColumnHeaderOrFooter(FacesContext facesContext, UIData uiData, boolean header, int columnIndex) throws IOException
-    {         
+    {
     }
 
     /**
@@ -533,14 +539,22 @@
     {
         RendererUtils.checkParamValidity(facesContext, uiComponent, UIData.class);
 
-        ResponseWriter writer = facesContext.getResponseWriter();
-        writer.endElement(HTML.TABLE_ELEM);
-        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+		endTable(facesContext, uiComponent);
 
         afterTable(facesContext, (UIData) uiComponent);
     }
 
-    /**
+	/**
+	 * actually render the end of the table
+	 */
+	protected void endTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
+	{
+		ResponseWriter writer = facesContext.getResponseWriter();
+		writer.endElement(HTML.TABLE_ELEM);
+		HtmlRendererUtils.writePrettyLineSeparator(facesContext);
+	}
+
+	/**
      * Renders either the header or the footer facets for the UIData component
      * and all the child UIColumn components, as a THEAD or TFOOT element
      * containing TR (row) elements.
@@ -551,8 +565,8 @@
      * entire width of the table.
      * <p>
      * If any child column has a header or footer then a TR is rendered
-     * with a TH cell for each column child. 
-     * 
+     * with a TH cell for each column child.
+     *
      * @param facesContext the <code>FacesContext</code>.
      * @param writer the <code>ResponseWriter</code>.
      * @param component the UIData component
@@ -588,11 +602,14 @@
         {
             // Header or Footer present on either the UIData or a column, so we
             // definitely need to render the THEAD or TFOOT section.
-            String elemName = header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
+            String elemName = determineHeaderFooterTag(facesContext, component, header);
 
             HtmlRendererUtils.writePrettyLineSeparator(facesContext);
-            writer.startElement(elemName, component);
-            if (header)
+			if (elemName != null)
+			{
+				writer.startElement(elemName, component);
+			}
+			if (header)
             {
                 String headerStyleClass = getHeaderClass(component);
                 if (facet != null)
@@ -608,11 +625,19 @@
                 if (facet != null)
                     renderTableFooterRow(facesContext, writer, component, facet, footerStyleClass, colspan);
             }
-            writer.endElement(elemName);
-        }
+			if (elemName != null)
+			{
+	            writer.endElement(elemName);
+			}
+		}
     }
 
-    /**
+	protected String determineHeaderFooterTag(FacesContext facesContext, UIComponent component, boolean header)
+	{
+		return header ? HTML.THEAD_ELEM : HTML.TFOOT_ELEM;
+	}
+
+	/**
      * @param header
      * @param uiComponent
      * @return boolean
@@ -635,7 +660,7 @@
      * is rendered as one column, every other child type is not rendered
      * (ie spans zero columns). However custom subclasses of this renderer may
      * override this method to handle cases where a single component renders
-     * as multiple columns. 
+     * as multiple columns.
      */
     protected int determineChildColSpan(UIComponent uiComponent)
     {
@@ -660,7 +685,7 @@
     protected void renderTableHeaderRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
             UIComponent headerFacet, String headerStyleClass, int colspan) throws IOException
     {
-        renderTableHeaderOrFooterRow(facesContext, writer, component, headerFacet, headerStyleClass, HTML.TH_ELEM,
+        renderTableHeaderOrFooterRow(facesContext, writer, component, headerFacet, headerStyleClass, determineHeaderCellTag(facesContext, component),
                 colspan);
     }
 
@@ -685,7 +710,7 @@
     /**
      * Renders the header row for the columns, which is a separate row from the header row for the
      * <code>UIData</code> header facet.
-     * 
+     *
      * @param facesContext the <code>FacesContext</code>.
      * @param writer the <code>ResponseWriter</code>.
      * @param component the UIData component for whom a table is being rendered.
@@ -713,13 +738,13 @@
         renderColumnHeaderOrFooterRow(facesContext, writer, component, footerStyleClass, false);
     }
 
-    private void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
+    protected void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component,
             UIComponent facet, String styleClass, String colElementName, int colspan) throws IOException
     {
         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
         writer.startElement(HTML.TR_ELEM, component);
         writer.startElement(colElementName, component);
-        if (colElementName.equals(HTML.TH_ELEM))
+        if (colElementName.equals(determineHeaderCellTag(facesContext, component)))
         {
             writer.writeAttribute(HTML.SCOPE_ATTR, HTML.SCOPE_COLGROUP_VALUE, null);
         }
@@ -764,9 +789,9 @@
                 {
                     if (component instanceof UIData && uiComponent instanceof UIColumn)
                         beforeColumnHeaderOrFooter(facesContext, (UIData)component, header, columnIndex);
-                
+
                 	renderColumnChildHeaderOrFooterRow(facesContext, writer, uiComponent, styleClass, header);
-                    
+
                     if (component instanceof UIData && uiComponent instanceof UIColumn)
                         afterColumnHeaderOrFooter(facesContext, (UIData)component, header, columnIndex);
                 }
@@ -788,7 +813,7 @@
     protected void renderSpacerCell(FacesContext facesContext, ResponseWriter writer, UIComponent component) throws IOException {
         UIComponent spacer = getNewspaperTableSpacer(component);
         if(spacer == null) return;
-         
+
          writer.startElement(HTML.TD_ELEM, component);
          RendererUtils.renderChild(facesContext, spacer);
          writer.endElement(HTML.TD_ELEM);
@@ -833,7 +858,7 @@
      * UIColumn object does have a header facet, then that facet is rendered
      * within the cell, otherwise the cell is left blank (though any specified
      * style class is still applied to empty cells).
-     * 
+     *
      * @param facesContext the <code>FacesContext</code>.
      * @param writer the <code>ResponseWriter</code>.
      * @param uiComponent the <code>UIComponent</code> to render the facet for.
@@ -846,7 +871,7 @@
     protected void renderColumnHeaderCell(FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
             UIComponent facet, String headerStyleClass, int colspan) throws IOException
     {
-        writer.startElement(HTML.TH_ELEM, uiComponent);
+        writer.startElement(determineHeaderCellTag(facesContext, uiComponent.getParent()), uiComponent);
         if (colspan > 1)
         {
             writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan), null);
@@ -859,10 +884,15 @@
         {
             RendererUtils.renderChild(facesContext, facet);
         }
-        writer.endElement(HTML.TH_ELEM);
+        writer.endElement(determineHeaderCellTag(facesContext, uiComponent.getParent()));
     }
 
-    /**
+	protected String determineHeaderCellTag(FacesContext facesContext, UIComponent uiComponent)
+	{
+		return 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>.

Modified: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTable.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTable.java?rev=619111&r1=619110&r2=619111&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTable.java (original)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/component/html/ext/HtmlDataTable.java Wed Feb  6 11:20:40 2008
@@ -23,22 +23,32 @@
 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.*;
-import javax.faces.application.Application;
-import javax.faces.component.*;
-
-import org.apache.myfaces.custom.column.HtmlSimpleColumn;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 /**
  * @author Thomas Spiegl (latest modification by $Author$)
@@ -55,10 +65,13 @@
 
     private static final boolean DEFAULT_SORTASCENDING = true;
     private static final boolean DEFAULT_SORTABLE = false;
-    private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
+	private static final boolean DEFAULT_EMBEDDED = false;
+	private static final boolean DEFAULT_DETAILSTAMP_EXPANDED = false;
+	private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
 
     private static final Integer DEFAULT_NEWSPAPER_COLUMNS = new Integer(1);
     private static final String DEFAULT_NEWSPAPER_ORIENTATION = "vertical";
+	private static final String DEFAULT_DETAILSTAMP_LOCATION = "after";
 
     /**
      * the property names
@@ -83,6 +96,9 @@
     private Boolean _sortAscending = null;
     private String _sortProperty = null;
     private Boolean _sortable = null;
+	private Boolean _embedded = null;
+	private Boolean _detailStampExpandedDefault = null;
+	private String _detailStampLocation = null;
     private String _rowOnClick = null;
     private String _rowOnDblClick = null;
     private String _rowOnMouseDown = null;
@@ -105,7 +121,7 @@
 
     private boolean _isValidChildren = true;
 
-    private Set _expandedNodes = new HashSet();
+    private Map _expandedNodes = new HashMap();
 
     private Map _detailRowStates = new HashMap();
 
@@ -774,7 +790,7 @@
     {
         boolean preserveSort = isPreserveSort();
 
-        Object values[] = new Object[36];
+        Object values[] = new Object[39];
         values[0] = super.saveState(context);
         values[1] = _preserveDataModel;
 
@@ -825,6 +841,9 @@
         values[33] = _newspaperOrientation;
         values[34] = _bodyStyle;
         values[35] = _bodyStyleClass;
+		values[36] = _embedded;
+		values[37] = _detailStampLocation;
+		values[38] = _detailStampExpandedDefault;
 
         return values;
     }
@@ -948,7 +967,7 @@
         }
 
         _varDetailToggler = (String) values[26];
-        _expandedNodes = (Set) values[27];
+        _expandedNodes = (Map) values[27];
         _rowGroupStyle = (String) values[28];
         _rowGroupStyleClass = (String) values[29];
         _sortedColumnVar = (String) values[30];
@@ -957,6 +976,9 @@
         _newspaperOrientation = (String) values[33];
         _bodyStyle = (String) values[34];
         _bodyStyleClass = (String) values[35];
+		_embedded = (Boolean) values[36];
+		_detailStampLocation = (String) values[37];
+		_detailStampExpandedDefault = (Boolean) values[38];
     }
 
     public _SerializableDataModel getSerializableDataModel()
@@ -1120,7 +1142,46 @@
         return v != null ? v.booleanValue() : DEFAULT_SORTABLE;
     }
 
-    public void setRowOnMouseOver(String rowOnMouseOver)
+	public void setEmbedded(boolean embedded)
+	{
+		_embedded = embedded ? Boolean.TRUE : Boolean.FALSE;
+	}
+
+	public boolean isEmbedded()
+	{
+		if (_embedded != null) return _embedded.booleanValue();
+		ValueBinding vb = getValueBinding("embedded");
+		Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
+		return v != null ? v.booleanValue() : DEFAULT_EMBEDDED;
+	}
+
+	public void setDetailStampExpandedDefault(boolean detailStampExpandedDefault)
+	{
+		_detailStampExpandedDefault = detailStampExpandedDefault ? Boolean.TRUE : Boolean.FALSE;
+	}
+
+	public boolean isDetailStampExpandedDefault()
+	{
+		if (_detailStampExpandedDefault != null) return _detailStampExpandedDefault.booleanValue();
+		ValueBinding vb = getValueBinding("detailStampExpandedDefault");
+		Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
+		return v != null ? v.booleanValue() : DEFAULT_DETAILSTAMP_EXPANDED;
+	}
+
+	public void setEmbedded(String detailStampLocation)
+	{
+		_detailStampLocation = detailStampLocation;
+	}
+
+	public String getDetailStampLocation()
+	{
+		if (_detailStampLocation != null) return _detailStampLocation;
+		ValueBinding vb = getValueBinding("detailStampLocation");
+		String v = vb != null ? (String) vb.getValue(getFacesContext()) : null;
+		return v != null ? v : DEFAULT_DETAILSTAMP_LOCATION;
+	}
+
+	public void setRowOnMouseOver(String rowOnMouseOver)
     {
         _rowOnMouseOver = rowOnMouseOver;
     }
@@ -1239,7 +1300,7 @@
     {
         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)
@@ -1321,7 +1382,13 @@
 
     public boolean isCurrentDetailExpanded()
     {
-        return _expandedNodes.contains(new Integer(getRowIndex()));
+		Boolean expanded = (Boolean) _expandedNodes.get(new Integer(getRowIndex()));
+		if (expanded != null)
+		{
+			return expanded.booleanValue();
+		}
+
+		return isDetailStampExpandedDefault();
     }
 
     public void setVarDetailToggler(String varDetailToggler)
@@ -1402,14 +1469,38 @@
     {
         Integer rowIndex = new Integer(getRowIndex());
 
-        if (_expandedNodes.contains(rowIndex))
-        {
-            _expandedNodes.remove(rowIndex);
-        }
+		// get the current expanded state of the row
+		boolean expanded = isDetailExpanded();
+		if (expanded)
+        {
+			// toggle to "collapsed"
+
+			if (isDetailStampExpandedDefault())
+			{
+				// if default is expanded we have to override with FALSE here
+				_expandedNodes.put(rowIndex, Boolean.FALSE);
+			}
+			else
+			{
+				// if default is collapsed we can fallback to this default
+				_expandedNodes.remove(rowIndex);
+			}
+		}
         else
         {
-            _expandedNodes.add(rowIndex);
-        }
+			// toggle to "expanded"
+
+			if (isDetailStampExpandedDefault())
+			{
+				// if default is expanded we can fallback to this default
+				_expandedNodes.remove(rowIndex);
+			}
+			else
+			{
+				// if default is collapsed we have to override with TRUE
+				_expandedNodes.put(rowIndex, Boolean.TRUE);
+			}
+		}
     }
 
     /**
@@ -1421,8 +1512,14 @@
     {
         Integer rowIndex = new Integer(getRowIndex());
 
-        return _expandedNodes.contains(rowIndex);
-    }
+        Boolean expanded = (Boolean) _expandedNodes.get(rowIndex);
+		if (expanded == null)
+		{
+			return isDetailStampExpandedDefault();
+		}
+
+		return expanded.booleanValue();
+	}
 
     public int getSortColumnIndex()
     {
@@ -1463,7 +1560,7 @@
 	public String getNewspaperOrientation() {
 		if(_newspaperOrientation != null)
 			return _newspaperOrientation;
-		
+
 		ValueBinding vb = getValueBinding(NEWSPAPER_ORIENTATION_PROPERTY);
 		String v = vb != null ? (String)vb.getValue(getFacesContext()) : DEFAULT_NEWSPAPER_ORIENTATION;
 		return v;
@@ -1492,7 +1589,7 @@
         _expandedNodes.clear();
         for (int row = 0; row < rowCount; row++)
         {
-            _expandedNodes.add(new Integer(row));
+            _expandedNodes.put(new Integer(row), Boolean.TRUE);
         }
     }
 

Modified: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/ext/HtmlTableRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/ext/HtmlTableRenderer.java?rev=619111&r1=619110&r2=619111&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/ext/HtmlTableRenderer.java (original)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/ext/HtmlTableRenderer.java Wed Feb  6 11:20:40 2008
@@ -119,11 +119,97 @@
         return super.isNewspaperHorizontalOrientation(component);
     }
 
-    protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException {
+	protected void startTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
+	{
+		boolean embedded = isEmbeddedTable(uiComponent);
+
+		if (!embedded)
+		{
+			super.startTable(facesContext, uiComponent);
+		}
+	}
+
+	protected String determineHeaderFooterTag(FacesContext facesContext, UIComponent component, boolean header)
+	{
+		if (isEmbeddedTable(component))
+		{
+			// we are embedded, so do not render the tfoot/thead stuff
+			return null;
+		}
+
+		return super.determineHeaderFooterTag(facesContext, component, header);
+	}
+
+	protected String determineHeaderCellTag(FacesContext facesContext, UIComponent component)
+	{
+		if (isEmbeddedTable(component))
+		{
+			return HTML.TD_ELEM;
+		}
+
+		return HTML.TH_ELEM;
+	}
+
+	protected void renderTableHeaderOrFooterRow(FacesContext facesContext, ResponseWriter writer, UIComponent component, UIComponent facet, String styleClass, String colElementName, int colspan) throws IOException
+	{
+		if (isEmbeddedTable(component))
+		{
+			// embedded tables render the header/footer stuff using TD only
+			colElementName = HTML.TD_ELEM;
+		}
+
+		super.renderTableHeaderOrFooterRow(facesContext, writer, component, facet, styleClass, colElementName, colspan);
+	}
+
+	protected boolean isEmbeddedTable(UIComponent uiComponent)
+	{
+		boolean embedded = false;
+		if (uiComponent instanceof HtmlDataTable)
+		{
+			HtmlDataTable table = (HtmlDataTable) uiComponent;
+			embedded = table.isEmbedded();
+		}
+		return embedded;
+	}
+
+	protected boolean isDetailStampAfterRow(UIComponent uiComponent)
+	{
+		if (uiComponent instanceof HtmlDataTable)
+		{
+			return "after".equals(((HtmlDataTable) uiComponent).getDetailStampLocation());
+		}
+
+		return true;
+	}
+
+	protected void endTable(FacesContext facesContext, UIComponent uiComponent) throws IOException
+	{
+		boolean embedded = isEmbeddedTable(uiComponent);
+
+		if (!embedded)
+		{
+			super.endTable(facesContext, uiComponent);
+		}
+	}
+
+	protected void beforeRow(FacesContext facesContext, UIData uiData) throws IOException
+	{
+		super.beforeRow(facesContext, uiData);
+
+		if (!isDetailStampAfterRow(uiData))
+		{
+			renderDetailRow(facesContext, uiData);
+		}
+	}
+
+	protected void afterRow(FacesContext facesContext, UIData uiData) throws IOException {
         super.afterRow(facesContext, uiData);
 
-        renderDetailRow(facesContext, uiData);
-    }
+		if (isDetailStampAfterRow(uiData))
+		{
+			renderDetailRow(facesContext, uiData);
+		}
+	}
 
     /**
      *
@@ -138,18 +224,32 @@
             HtmlDataTable htmlDataTable = (HtmlDataTable)uiData;
 
             if(htmlDataTable.isCurrentDetailExpanded()){
-                ResponseWriter writer = facesContext.getResponseWriter();
-                writer.startElement(HTML.TR_ELEM,uiData);
-                writer.startElement(HTML.TD_ELEM,uiData);
-                writer.writeAttribute(HTML.COLSPAN_ATTR,new Integer(uiData.getChildren().size()) ,null);
 
-                if(detailStampFacet!=null){
+				boolean embedded = false;
+				if (detailStampFacet != null)
+				{
+					embedded = isEmbeddedTable(detailStampFacet);
+				}
+
+				ResponseWriter writer = facesContext.getResponseWriter();
+
+				if (!embedded)
+				{
+					writer.startElement(HTML.TR_ELEM,uiData);
+					writer.startElement(HTML.TD_ELEM,uiData);
+					writer.writeAttribute(HTML.COLSPAN_ATTR,new Integer(uiData.getChildren().size()) ,null);
+				}
+
+				if(detailStampFacet!=null){
                     RendererUtils.renderChild(facesContext, detailStampFacet);
                 }
 
-                writer.endElement(HTML.TD_ELEM);
-                writer.endElement(HTML.TR_ELEM);
-            }
+				if (!embedded)
+				{
+	                writer.endElement(HTML.TD_ELEM);
+	                writer.endElement(HTML.TR_ELEM);
+				}
+			}
         }
     }
 
@@ -734,7 +834,7 @@
         {
             if (amISpannedOver("header", uiComponent))
                 return;
-            writer.startElement(HTML.TH_ELEM, uiComponent);
+            writer.startElement(determineHeaderCellTag(facesContext, uiComponent.getParent()), uiComponent);
             if (colspan > 1)
             {
                 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(colspan),
@@ -755,7 +855,7 @@
             {
                 RendererUtils.renderChild(facesContext, facet);
             }
-            writer.endElement(HTML.TH_ELEM);
+            writer.endElement(determineHeaderCellTag(facesContext, uiComponent.getParent()));
         }
         else
         {

Modified: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/taglib/html/ext/HtmlDataTableTag.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/taglib/html/ext/HtmlDataTableTag.java?rev=619111&r1=619110&r2=619111&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/taglib/html/ext/HtmlDataTableTag.java (original)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/taglib/html/ext/HtmlDataTableTag.java Wed Feb  6 11:20:40 2008
@@ -48,7 +48,7 @@
     private String _preserveRowStates;
     private String _forceIdIndexFormula;
     private String _sortColumn;
-    private String _sortAscending;    
+    private String _sortAscending;
     private String _sortable;
     private String _preserveSort;
     private String _enabledOnUserRole;
@@ -70,7 +70,7 @@
     private String _rowOnKeyUp;
     private String _rowId;
     private String _varDetailToggler;
-    
+
     private String _rowStyleClass;
     private String _rowStyle;
     private String _rowGroupStyle;
@@ -83,8 +83,12 @@
     private String _newspaperColumns = null;
     /** the orientation of the newspaper table - horizontal/vertical */
     private String _newspaperOrientation = null;
-    
-    public void release() 
+
+	private String _embedded = null;
+	private String _detailStampExpandedDefault = null;
+	private String _detailStampLocation = null;
+
+	public void release()
     {
         super.release();
 
@@ -92,7 +96,7 @@
         _preserveRowStates = null;
         _forceIdIndexFormula=null;
         _sortColumn=null;
-        _sortAscending=null;        
+        _sortAscending=null;
         _sortable=null;
         _preserveSort=null;
         _enabledOnUserRole=null;
@@ -119,13 +123,17 @@
         _rowStyle = null;
         _rowGroupStyle = null;
         _rowGroupStyleClass = null;
-        
+
         _newspaperColumns = null;
         _newspaperOrientation = null;
 
         _bodyStyle = null;
         _bodyStyleClass = null;
-    }
+
+		_embedded = null;
+		_detailStampExpandedDefault = null;
+		_detailStampLocation = null;
+	}
 
     protected void setProperties(UIComponent component)
     {
@@ -155,9 +163,9 @@
         setStringProperty(component, "rowOnKeyPress", _rowOnKeyPress);
         setStringProperty(component, "rowOnKeyDown", _rowOnKeyDown);
         setStringProperty(component, "rowOnKeyUp", _rowOnKeyUp);
-        setStringProperty(component, JSFAttr.ROW_ID, _rowId);        
+        setStringProperty(component, JSFAttr.ROW_ID, _rowId);
         setStringProperty(component,"varDetailToggler",_varDetailToggler);
-        
+
         setStringProperty(component, JSFAttr.ROW_STYLECLASS_ATTR, _rowStyleClass);
         setStringProperty(component, JSFAttr.ROW_STYLE_ATTR, _rowStyle);
         setStringProperty(component, "rowGroupStyle", _rowGroupStyle);
@@ -168,6 +176,10 @@
 
         setIntegerProperty(component, HtmlDataTable.NEWSPAPER_COLUMNS_PROPERTY, _newspaperColumns);
         setStringProperty(component, HtmlDataTable.NEWSPAPER_ORIENTATION_PROPERTY, _newspaperOrientation);
+
+		setBooleanProperty(component, "embedded", _embedded);
+		setBooleanProperty(component, "detailStampExpandedDefault", _detailStampExpandedDefault);
+		setStringProperty(component, "detailStampLocation", _detailStampLocation);
     }
 
     public void setPreserveDataModel(String preserveDataModel)
@@ -184,7 +196,7 @@
     {
         _forceIdIndexFormula = forceIdIndexFormula;
     }
-    
+
     public void setSortColumn(String sortColumn)
     {
         _sortColumn = sortColumn;
@@ -194,7 +206,7 @@
     {
         _sortAscending = sortAscending;
     }
-      
+
     public void setSortable(String sortable)
     {
         _sortable = sortable;
@@ -234,7 +246,7 @@
     {
         _previousRowDataVar = previousRowDataVar;
     }
-    
+
     public void setSortedColumnVar(String sortedColumnVar)
     {
         _sortedColumnVar = sortedColumnVar;
@@ -254,22 +266,22 @@
     {
       _rowOnClick = rowOnClick;
     }
-    
+
     public void setRowOnDblClick(String rowOnDblClick)
     {
       _rowOnDblClick = rowOnDblClick;
     }
-    
+
     public void setRowOnKeyDown(String rowOnKeyDown)
     {
       _rowOnKeyDown = rowOnKeyDown;
     }
-    
+
     public void setRowOnKeyPress(String rowOnKeyPress)
     {
       _rowOnKeyPress = rowOnKeyPress;
     }
-    
+
     public void setRowOnKeyUp(String rowOnKeyUp)
     {
       _rowOnKeyUp = rowOnKeyUp;
@@ -289,17 +301,17 @@
     {
       _rowOnMouseUp = rowOnMouseUp;
     }
-    
+
     public void setRowId(String rowId)
     {
       _rowId = rowId;
     }
-    
+
     public void setRowStyleClass(String rowStyleClass)
     {
       _rowStyleClass = rowStyleClass;
     }
-    
+
     public void setRowStyle(String rowStyle)
     {
       _rowStyle = rowStyle;
@@ -322,11 +334,11 @@
 	public void setVarDetailToggler(String varDetailToggler) {
 		_varDetailToggler = varDetailToggler;
 	}
-    
+
     public void setNewspaperColumns(String newspaperColumns) {
         this._newspaperColumns = newspaperColumns;
     }
-    
+
     public void setNewspaperOrientation(String newspaperOrientation) {
         this._newspaperOrientation = newspaperOrientation;
     }
@@ -345,5 +357,35 @@
 
     public void setBodyStyleClass(String bodyStyleClass) {
         _bodyStyleClass = bodyStyleClass;
+	}
+
+	public String getEmbedded()
+	{
+		return _embedded;
+	}
+
+	public void setEmbedded(String embedded)
+	{
+		this._embedded = embedded;
+	}
+
+	public String getDetailStampExpandedDefault()
+	{
+		return _detailStampExpandedDefault;
+	}
+
+	public void setDetailStampExpandedDefault(String detailStampExpandedDefault)
+	{
+		this._detailStampExpandedDefault = detailStampExpandedDefault;
+	}
+
+	public String getDetailStampLocation()
+	{
+		return _detailStampLocation;
+	}
+
+	public void setDetailStampLocation(String detailStampLocation)
+	{
+		this._detailStampLocation = detailStampLocation;
 	}
 }

Modified: myfaces/tomahawk/trunk/core/src/main/tld/entities/extended_data_table_attributes.xml
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/tld/entities/extended_data_table_attributes.xml?rev=619111&r1=619110&r2=619111&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/tld/entities/extended_data_table_attributes.xml (original)
+++ myfaces/tomahawk/trunk/core/src/main/tld/entities/extended_data_table_attributes.xml Wed Feb  6 11:20:40 2008
@@ -5,15 +5,15 @@
             <description>
                 Indicates whether the state of the whole DataModel should be saved and
                 restored. When set to false, the value-binding for the "value" attribute
-                of this table is executed each time the page is rendered. When set to 
+                of this table is executed each time the page is rendered. When set to
                 true, that value-binding is only executed when the component is first
                 created, and the DataModel state is thereafter saved/restored automatically
                 by the component.
-                
+
                 When column sorting is used for a table this property needs to be false
                 so that the DataModel can be updated to reflect any changes in the
                 sort criteria.
-                
+
                 Default: false
             </description>
         </attribute>
@@ -22,14 +22,14 @@
             <required>false</required>
             <rtexprvalue>false</rtexprvalue>
             <description>
-                Indicates whether the state for each row should not be discarded before 
+                Indicates whether the state for each row should not be discarded before
                 the datatable is rendered again. Setting this to true might be hepful if
                 an input component inside the datatable has no valuebinding and the value
-                entered in there should be displayed again. 
+                entered in there should be displayed again.
                 This will only work reliable if the datamodel of the datatable did not change
                 either by sorting, removing or adding rows.
-                                
-                Default: false 
+
+                Default: false
             </description>
         </attribute>
         <attribute>
@@ -67,11 +67,11 @@
                 used) is expected to use this property to determine how to sort the DataModel's
                 contents.
             </description>
-        </attribute>        
+        </attribute>
          <attribute>
             <name>sortable</name>
             <required>false</required>
-            <rtexprvalue>false</rtexprvalue>            
+            <rtexprvalue>false</rtexprvalue>
             <description></description>
         </attribute>
         <attribute>
@@ -272,4 +272,24 @@
             <rtexprvalue>false</rtexprvalue>
             <description>Corresponds to the HTML style attribute for the table body tag.</description>
         </attribute>
-      
\ No newline at end of file
+		<attribute>
+		   <name>embedded</name>
+		   <required>false</required>
+		   <rtexprvalue>false</rtexprvalue>
+		   <description>Avoids rendering the html table tags, thus, giving you a table rendering just rows.
+		   You can use this together with the detailStamp faces of the parent datatable to render
+		   child-tables using the same layout as the parent. Notice: You have to ensure both tables do have
+		   the same number of columns. Using the colspan attribute of the column tag might help alot.</description>
+	   </attribute>
+		<attribute>
+		   <name>detailStampLocation</name>
+		   <required>false</required>
+		   <rtexprvalue>false</rtexprvalue>
+		   <description>before|after - where to render the detailStamp, before the actual row or after it. default: after</description>
+	   </attribute>
+		<attribute>
+		   <name>detailStampExpandedDefault</name>
+		   <required>false</required>
+		   <rtexprvalue>false</rtexprvalue>
+		   <description>true|false - true if the detailStamp should be expanded by default. default: false</description>
+	   </attribute>

Modified: myfaces/tomahawk/trunk/examples/simple/src/main/webapp/masterDetail.jsp
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/examples/simple/src/main/webapp/masterDetail.jsp?rev=619111&r1=619110&r2=619111&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/examples/simple/src/main/webapp/masterDetail.jsp (original)
+++ myfaces/tomahawk/trunk/examples/simple/src/main/webapp/masterDetail.jsp Wed Feb  6 11:20:40 2008
@@ -47,6 +47,12 @@
 						<br>
 					</f:verbatim>
 
+					<f:verbatim>
+						A table rendering the details using an independent table within an cell of the master table.
+						As a resulting effect the each child table will have its own cell width.
+						<br />
+					</f:verbatim>
+
 					<t:dataTable id="data" styleClass="standardTable" headerClass="standardTable_Header" footerClass="standardTable_Header" rowClasses="standardTable_Row1,standardTable_Row2"
 						columnClasses="standardTable_Column,standardTable_ColumnCentered,standardTable_Column" var="currentCountry" value="#{countryList.countries}" preserveDataModel="true" varDetailToggler="detailToggler">
 						<h:column>
@@ -93,13 +99,80 @@
 							</t:dataTable>
 						</f:facet>
 					</t:dataTable>
-					
+
 					<f:verbatim>
 						<br>
 					</f:verbatim>
 
+
+					<f:verbatim>
+						A table rendering the details using an "embedded" table. (embedded="true" at the child datatable).
+						In contrast to the above example this will result in a combined table sharing the same layout.
+						All cells in on collumn will have the same width.<br />
+						To achive this the child table will not renter a table start/end tag and, also the rendering of
+						any thead/tfoot/th will be supressed. You have to take care about that fact in your stylesheet(s).
+						<br />
+					</f:verbatim>
+
+					<t:dataTable id="data2" styleClass="standardTable" detailStampExpandedDefault="true" headerClass="standardTable_Header" footerClass="standardTable_Header" rowClasses="standardTable_Row1,standardTable_Row2"
+						columnClasses="standardTable_Column,standardTable_ColumnCentered,standardTable_Column" var="currentCountry" value="#{countryList.countries}" preserveDataModel="true" varDetailToggler="detailToggler">
+						<h:column>
+							<f:facet name="header">
+								<h:outputText value="#{example_messages['label_country_name']}" />
+							</f:facet>
+							<t:commandLink action="go_country" immediate="true">
+								<h:outputText value="#{currentCountry.name}" />
+								<!-- for convenience: MyFaces extension. sets id of current row in countryForm -->
+								<!-- you don't have to implement a custom action! -->
+								<t:updateActionListener property="#{countryForm.id}" value="#{currentCountry.id}" />
+							</t:commandLink>
+						</h:column>
+
+						<h:column>
+							<f:facet name="header">
+								<h:outputText value="#{example_messages['label_country_iso']}" />
+							</f:facet>
+							<h:outputText value="#{currentCountry.isoCode}" />
+						</h:column>
+
+						<h:column>
+							<f:facet name="header">
+								<h:outputText value="#{example_messages['label_country_cities']}" />
+							</f:facet>
+							<h:commandLink rendered="#{detailToggler.currentDetailExpanded}" action="#{detailToggler.toggleDetail}">
+								<h:outputText value="Hide" />
+							</h:commandLink>
+							<h:commandLink rendered="#{!detailToggler.currentDetailExpanded}" action="#{detailToggler.toggleDetail}">
+								<h:outputText value="Show" />
+							</h:commandLink>
+						</h:column>
+
+						<f:facet name="detailStamp">
+							<t:dataTable id="cities2" embedded="true" var="city" value="#{currentCountry.cities}">
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="city" />
+									</f:facet>
+									<h:outputText value="#{city}" style="font-size: 11px" />
+								</h:column>
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="selected" />
+									</f:facet>
+									<h:selectBooleanCheckbox value="#{city.selected}"></h:selectBooleanCheckbox>
+								</h:column>
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="unselect" />
+									</f:facet>
+									<h:commandLink action="#{city.unselect}" value="Unselect"/>
+								</h:column>
+							</t:dataTable>
+						</f:facet>
+					</t:dataTable>
+
 				</h:panelGroup>
-				
+
 			</h:form>
 
             <jsp:include page="inc/mbean_source.jsp"/>