Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.788
diff -u -r1.788 common.inc
--- includes/common.inc	21 Aug 2008 19:36:36 -0000	1.788
+++ includes/common.inc	23 Aug 2008 15:05:30 -0000
@@ -2812,7 +2812,10 @@
     }
     $prefix = isset($elements['#prefix']) ? $elements['#prefix'] : '';
     $suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
-    return $prefix . $content . $suffix;
+    $content = $prefix . $content . $suffix;
+    // Store the rendered content, so higher level elements can reuse it.
+    $elements['#content'] = $content;
+    return $content;
   }
 }
 
@@ -3050,6 +3053,9 @@
     'file' => array(
       'arguments' => array('element' => NULL),
     ),
+    'tableselect' => array(
+      'arguments' => array('element' => NULL),
+    ),
     'form_element' => array(
       'arguments' => array('element' => NULL, 'value' => NULL),
     ),
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.281
diff -u -r1.281 form.inc
--- includes/form.inc	17 Aug 2008 11:08:23 -0000	1.281
+++ includes/form.inc	23 Aug 2008 15:05:30 -0000
@@ -1911,6 +1911,82 @@
 }
 
 /**
+ * Render the element as a table, with the expanded children in the first row.
+ *
+ * @param $element
+ *   An associative array containing the properties of the element.
+ *
+ * @return
+ *   A themed HTML string representing the table.
+ *
+ * @ingroup themeable
+ */
+function theme_tableselect($element) {
+  $rows = array();
+  foreach ($element['#options'] as $key => $value) {
+    $row = array();
+
+    // Render the checkbox / radio element.
+    $row[] = $element[$key]['#content'];
+
+    foreach ($element['#header'] as $fieldname => $title) {
+      $row[] = $element['#options'][$key][$fieldname];
+    }
+    $rows[] = $row;
+  }
+  $first_col = $element['#advanced_select'] ? array(theme('table_select_header_cell')) : array('');
+  $header = array_merge($first_col, $element['#header']);
+  return theme('table', $header, $rows);
+}
+
+/**
+ * Create the right amount of checkboxes or radios to populate the table.
+ */
+function expand_tableselect($element) {
+
+  if ($element['#multiple']) {
+    $value = is_array($element['#value']) ? $element['#value'] : array();
+  }
+  else {
+    // Advanced select is only possible if #multiple is true.
+    $element['#advanced_select'] = FALSE;
+  }
+
+  $element['#tree'] = TRUE;
+
+  if (count($element['#options']) > 0) {
+    if (!isset($element['#default_value']) || $element['#default_value'] === 0) {
+      $element['#default_value'] = array();
+    }
+
+    foreach ($element['#options'] as $key => $choice) {
+      if ($element['#multiple']) {
+        $element[$key] = array(
+          '#type' => 'checkbox',
+          '#processed' => TRUE,
+          '#title' => '',
+          '#return_value' => $key,
+          '#default_value' => isset($value[$key]),
+          '#attributes' => $element['#attributes'],
+        );
+      }
+      else {
+        $element[$key] = array(
+          '#type' => 'radio',
+          '#title' => '',
+          '#return_value' => $key,
+          '#default_value' => ($element['#default_value'] == $key) ? $key : NULL,
+          '#attributes' => $element['#attributes'],
+          '#parents' => $element['#parents'],
+          '#spawned' => TRUE,
+        );
+      }
+    }
+  }
+  return $element;
+}
+
+/**
  * Theme a form submit button.
  *
  * @ingroup themeable
Index: includes/tablesort.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/tablesort.inc,v
retrieving revision 1.48
diff -u -r1.48 tablesort.inc
--- includes/tablesort.inc	14 Apr 2008 17:48:33 -0000	1.48
+++ includes/tablesort.inc	23 Aug 2008 15:05:30 -0000
@@ -165,13 +165,14 @@
     return $default;
   }
   else {
-    // The first column specified is initial 'order by' field unless otherwise specified
-    if (is_array($headers[0])) {
-      $headers[0] += array('data' => NULL, 'field' => NULL);
-      return array('name' => $headers[0]['data'], 'sql' => $headers[0]['field']);
+    // The first column specified is the initial 'order by' field unless otherwise specified.
+    $first = current($headers);
+    if (is_array($first)) {
+      $first += array('data' => NULL, 'field' => NULL);
+      return array('name' => $first['data'], 'sql' => $first['field']);
     }
     else {
-      return array('name' => $headers[0]);
+      return array('name' => $first, 'sql' => '');
     }
   }
 }
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.613
diff -u -r1.613 system.module
--- modules/system/system.module	21 Aug 2008 19:36:38 -0000	1.613
+++ modules/system/system.module	23 Aug 2008 15:05:30 -0000
@@ -290,6 +290,14 @@
     '#size' => 60,
   );
 
+  $type['tableselect'] = array(
+    '#input' => TRUE,
+    '#advanced_select' => TRUE,
+    '#multiple' => TRUE,
+    '#process' => array('expand_tableselect'),
+    '#options' => array(),
+  );
+
 
   /**
    * Form structure.
Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.24
diff -u -r1.24 user.admin.inc
--- modules/user/user.admin.inc	24 Jul 2008 16:28:52 -0000	1.24
+++ modules/user/user.admin.inc	23 Aug 2008 15:09:26 -0000
@@ -130,13 +130,12 @@
   $filter = user_build_filter_query();
 
   $header = array(
-    array(),
-    array('data' => t('Username'), 'field' => 'u.name'),
-    array('data' => t('Status'), 'field' => 'u.status'),
-    t('Roles'),
-    array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
-    array('data' => t('Last access'), 'field' => 'u.access'),
-    t('Operations')
+    'username' => array('data' => t('Username'), 'field' => 'u.name'),
+    'status' => array('data' => t('Status'), 'field' => 'u.status'),
+    'roles' => t('Roles'),
+    'member_for' => array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
+    'last_access' => array('data' => t('Last access'), 'field' => 'u.access'),
+    'operations' => t('Operations'),
   );
 
   $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.created, u.access FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid ' . $filter['join'] . ' WHERE u.uid != 0 ' . $filter['where'];
