Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.570
diff -u -r1.570 theme.inc
--- includes/theme.inc	25 Jan 2010 10:38:34 -0000	1.570
+++ includes/theme.inc	28 Jan 2010 15:23:43 -0000
@@ -1616,6 +1616,8 @@ - rows: An array of table rows.
  *       )
  *     );
  *     @endcode
+ *     Note that when rowgroups are used rows need to grouped using an extra
+ *     associative array. See colgroups variable for more info.
  *   - attributes: An array of HTML attributes to apply to the table tag.
  *   - caption: A localized string to use for the <caption> tag.
  *   - colgroups: An array of column groups. Each element of the array can be
@@ -1626,9 +1628,9 @@
  *       include a "data" attribute. To add attributes to COL elements, set the
  *       "data" attribute with an array of columns, each of which is an
  *       associative array of HTML attributes.
- *     Here's an example for $colgroup:
+ *     Here's an example for $colgroups:
  *     @code
- *     $colgroup = array(
+ *     $colgroups = array(
  *       // COLGROUP with one COL element.
  *       array(
  *         array(
@@ -1649,6 +1651,43 @@
  *     These optional tags are used to group and set properties on columns
  *     within a table. For example, one may easily group three columns and
  *     apply same background style to all.
+ *   - rowgroup: An array of attributes applied to the TBODY element(s).
+ *     Rowgroup specific attributes set in rowgroups override these attributes.
+ *   - rowgroups: An associative array of row groups. Each element represents a
+ *     rowgroup identifiable by it's key. When this variable is set, rows are
+ *     expected to be grouped by rowgroup using an associative array while their
+ *     keys point to the keys of this variable. Elements of this variable are
+ *     expected to be an array of attributes which will be applied to the TBODY
+ *     element representing that rowgroup.
+ *     Here's an example for $rows combined with $rowgroups:
+ *     @code
+ *     $rowgroups = array(
+ *       'funky' => array( // Attributes for the TBODY element.
+ *         'title' => 'Funky rows',
+ *         'class' => array('funky'),
+ *       ),
+ *       'jazzy' => array( // Attributes for the TBODY element.
+ *         'title' => 'Jazzy rows',
+ *         'class' => array('jazzy'),
+ *       ),
+ *     );
+ *     $rows = array(
+ *       // Rows of the funky rowgroup.
+ *       'funky' => array(
+ *         // Simple row
+ *         array(
+ *           'Cell 1', 'Cell 2', 'Cell 3'
+ *         ),
+ *       ),
+ *       // Rows of the jazzy rowgroup.
+ *       'jazzy' => array(
+ *         // Row with attributes on the row and some of its cells.
+ *         array(
+ *           'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => array('funky')
+ *         ),
+ *       ),
+ *     );
+ *     @endcode
  *   - sticky: Use a "sticky" table header.
  *   - empty: The message to display in an extra row if table does not have any
  *     rows.
@@ -1662,6 +1701,8 @@
   $attributes = $variables['attributes'];
   $caption = $variables['caption'];
   $colgroups = $variables['colgroups'];
+  $rowgroup = $variables['rowgroup'];
+  $rowgroups = $variables['rowgroups'];
   $sticky = $variables['sticky'];
   $empty = $variables['empty'];
 
@@ -1736,44 +1777,56 @@
     $rows[] = array(array('data' => $empty, 'colspan' => count($header), 'class' => array('empty', 'message')));
   }
 
-  // Format the table rows:
-  if (count($rows)) {
-    $output .= "<tbody>\n";
-    $flip = array('even' => 'odd', 'odd' => 'even');
-    $class = 'even';
-    foreach ($rows as $number => $row) {
-      $attributes = array();
+  if (!is_array($rowgroups)) {
+    $rowgroups = array();
+    $rows_by_groups = array($rows);
+  }
+  else {
+    $rows_by_groups = $rows;
+  }
 
-      // Check if we're dealing with a simple or complex row
-      if (isset($row['data'])) {
-        foreach ($row as $key => $value) {
-          if ($key == 'data') {
-            $cells = $value;
-          }
-          else {
-            $attributes[$key] = $value;
+  // Format the table rows:
+  foreach ($rowgroups as $rowgroup_id => $rows) {
+    if (count($rows)) {
+      $attributes = isset($rowgroups[$rowgroup_id]) ? $rowgroup + $rowgroups[$rowgroup_id] : $rowgroup;
+      $output .= '<tbody' . drupal_attributes($attributes) . ">\n";
+
+      $flip = array('even' => 'odd', 'odd' => 'even');
+      $class = 'even';
+      foreach ($rows as $number => $row) {
+        $attributes = array();
+
+        // Check if we're dealing with a simple or complex row
+        if (isset($row['data'])) {
+          foreach ($row as $key => $value) {
+            if ($key == 'data') {
+              $cells = $value;
+            }
+            else {
+              $attributes[$key] = $value;
+            }
           }
         }
-      }
-      else {
-        $cells = $row;
-      }
-      if (count($cells)) {
-        // Add odd/even class
-        $class = $flip[$class];
-        $attributes['class'][] = $class;
-
-        // Build row
-        $output .= ' <tr' . drupal_attributes($attributes) . '>';
-        $i = 0;
-        foreach ($cells as $cell) {
-          $cell = tablesort_cell($cell, $header, $ts, $i++);
-          $output .= _theme_table_cell($cell);
+        else {
+          $cells = $row;
+        }
+        if (count($cells)) {
+          // Add odd/even class
+          $class = $flip[$class];
+          $attributes['class'][] = $class;
+
+          // Build row
+          $output .= ' <tr' . drupal_attributes($attributes) . '>';
+          $i = 0;
+          foreach ($cells as $cell) {
+            $cell = tablesort_cell($cell, $header, $ts, $i++);
+            $output .= _theme_table_cell($cell);
+          }
+          $output .= " </tr>\n";
         }
-        $output .= " </tr>\n";
       }
+      $output .= "</tbody>\n";
     }
-    $output .= "</tbody>\n";
   }
 
   $output .= "</table>\n";
