Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.843
diff -u -r1.843 common.inc
--- includes/common.inc	8 Jan 2009 19:09:49 -0000	1.843
+++ includes/common.inc	9 Jan 2009 08:47:50 -0000
@@ -3282,7 +3282,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;
   }
 }
 
@@ -3534,6 +3537,9 @@
     'file' => array(
       'arguments' => array('element' => NULL),
     ),
+    'tableselect' => array(
+      'arguments' => array('element' => NULL),
+    ),
     'form_element' => array(
       'arguments' => array('element' => NULL, 'value' => NULL),
     ),
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	9 Jan 2009 08:47:51 -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: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.310
diff -u -r1.310 form.inc
--- includes/form.inc	30 Dec 2008 16:43:14 -0000	1.310
+++ includes/form.inc	9 Jan 2009 08:47:51 -0000
@@ -2034,6 +2034,91 @@
 }
 
 /**
+ * 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();
+  if (!empty($element['#options'])) {
+    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']);
+  }
+  else {
+    $header = $element['#header'];
+    $rows[] = array(array('data' => $element['#empty'], 'colspan' => count($header)));
+  }
+  return theme('table', $header, $rows);
+}
+
+/**
+ * Create the right amount of checkboxes or radios to populate the table.
+ */
+function form_process_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,
+        );
+      }
+    }
+  }
+  else {
+    $element['#value'] = array();
+  }
+  return $element;
+}
+
+/**
  * Theme a form submit button.
  *
  * @ingroup themeable
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.681
diff -u -r1.681 comment.module
--- modules/comment/comment.module	8 Jan 2009 08:42:12 -0000	1.681
+++ modules/comment/comment.module	9 Jan 2009 08:47:51 -0000
@@ -118,9 +118,6 @@
     'comment_block' => array(
       'arguments' => array(),
     ),
-    'comment_admin_overview' => array(
-      'arguments' => array('form' => NULL),
-    ),
     'comment_preview' => array(
       'arguments' => array('comment' => NULL, 'node' => NULL, 'links' => array(), 'visible' => 1),
     ),
Index: modules/comment/comment.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.admin.inc,v
retrieving revision 1.12
diff -u -r1.12 comment.admin.inc
--- modules/comment/comment.admin.inc	3 Dec 2008 16:32:21 -0000	1.12
+++ modules/comment/comment.admin.inc	9 Jan 2009 08:47:51 -0000
@@ -58,43 +58,37 @@
 
   // Load the comments that need to be displayed.
   $status = ($arg == 'approval') ? COMMENT_NOT_PUBLISHED : COMMENT_PUBLISHED;
-  $form['header'] = array(
-    '#type' => 'value',
-    '#value' => array(
-      theme('table_select_header_cell'),
-      array('data' => t('Subject'), 'field' => 'subject'),
-      array('data' => t('Author'), 'field' => 'name'),
-      array('data' => t('Posted in'), 'field' => 'node_title'),
-      array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
-      array('data' => t('Operations')),
-  ));
-  $result = pager_query('SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid, n.title as node_title FROM {comment} c INNER JOIN {users} u ON u.uid = c.uid INNER JOIN {node} n ON n.nid = c.nid WHERE c.status = %d' . tablesort_sql($form['header']['#value']), 50, 0, NULL, $status);
+  $header = array(
+    'subject' => array('data' => t('Subject'), 'field' => 'subject'),
+    'author' => array('data' => t('Author'), 'field' => 'name'),
+    'posted_in' => array('data' => t('Posted in'), 'field' => 'node_title'),
+    'time' => array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
+    'operations' => array('data' => t('Operations')),
+  );
+
+  $result = pager_query('SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid, n.title as node_title FROM {comment} c INNER JOIN {users} u ON u.uid = c.uid INNER JOIN {node} n ON n.nid = c.nid WHERE c.status = %d' . tablesort_sql($header), 50, 0, NULL, $status);
 
   // Build a table listing the appropriate comments.
+  $options = array();
   $destination = drupal_get_destination();
+
   while ($comment = db_fetch_object($result)) {
-    $comments[$comment->cid] = '';
-    $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
-    $form['subject'][$comment->cid] = array(
-      '#markup' => l($comment->subject, 'node/' . $comment->nid, array('attributes' => array('title' => truncate_utf8($comment->comment, 128)), 'fragment' => 'comment-' . $comment->cid))
-    );
-    $form['username'][$comment->cid] = array(
-      '#markup' => theme('username', $comment)
-    );
-    $form['node_title'][$comment->cid] = array(
-      '#markup' => l($comment->node_title, 'node/' . $comment->nid)
-    );
-    $form['timestamp'][$comment->cid] = array(
-      '#markup' => format_date($comment->timestamp, 'small')
-    );
-    $form['operations'][$comment->cid] = array(
-      '#markup' => l(t('edit'), 'comment/edit/' . $comment->cid, array('query' => $destination))
+    $options[$comment->cid] = array(
+      'subject' => l($comment->subject, 'node/' . $comment->nid, array('attributes' => array('title' => truncate_utf8($comment->comment, 128)), 'fragment' => 'comment-' . $comment->cid)),
+      'author' => theme('username', $comment),
+      'posted_in' => l($comment->node_title, 'node/' . $comment->nid),
+      'time' => format_date($comment->timestamp, 'small'),
+      'operations' => l(t('edit'), 'comment/edit/' . $comment->cid, array('query' => $destination)),
     );
   }
+
   $form['comments'] = array(
-    '#type' => 'checkboxes',
-    '#options' => isset($comments) ? $comments: array()
+    '#type' => 'tableselect',
+    '#header' => $header,
+    '#options' => $options,
+    '#empty' => t('No comments available.'),
   );
+
   $form['pager'] = array(
     '#markup' => theme('pager', NULL, 50, 0)
   );
@@ -146,41 +140,6 @@
 }
 
 /**
- * Theme the comment admin form.
- *
- * @param $form
- *   An associative array containing the structure of the form.
- * @ingroup themeable
- */
-function theme_comment_admin_overview($form) {
-  $output = drupal_render($form['options']);
-  if (isset($form['subject']) && is_array($form['subject'])) {
-    foreach (element_children($form['subject']) as $key) {
-      $row = array();
-      $row[] = drupal_render($form['comments'][$key]);
-      $row[] = drupal_render($form['subject'][$key]);
-      $row[] = drupal_render($form['username'][$key]);
-      $row[] = drupal_render($form['node_title'][$key]);
-      $row[] = drupal_render($form['timestamp'][$key]);
-      $row[] = drupal_render($form['operations'][$key]);
-      $rows[] = $row;
-    }
-  }
-  else {
-    $rows[] = array(array('data' => t('No comments available.'), 'colspan' => '6'));
-  }
-
-  $output .= theme('table', $form['header']['#value'], $rows);
-  if ($form['pager']['#markup']) {
-    $output .= drupal_render($form['pager']);
-  }
-
-  $output .= drupal_render($form);
-
-  return $output;
-}
-
-/**
  * List the selected comments and verify that the admin wants to delete them.
  *
  * @param $form_state
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.953
diff -u -r1.953 user.module
--- modules/user/user.module	8 Jan 2009 08:42:13 -0000	1.953
+++ modules/user/user.module	9 Jan 2009 08:47:51 -0000
@@ -65,10 +65,6 @@
       'arguments' => array('form' => NULL),
       'file' => 'user.admin.inc',
     ),
-    'user_admin_account' => array(
-      'arguments' => array('form' => NULL),
-      'file' => 'user.admin.inc',
-    ),
     'user_filter_form' => array(
       'arguments' => array('form' => NULL),
       'file' => 'user.admin.inc',
Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.34
diff -u -r1.34 user.admin.inc
--- modules/user/user.admin.inc	8 Jan 2009 08:42:13 -0000	1.34
+++ modules/user/user.admin.inc	9 Jan 2009 08:47:51 -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'];
@@ -168,26 +167,41 @@
 
   $status = array(t('blocked'), t('active'));
   $roles = user_roles(TRUE);
-  $accounts = array();
+
+
+  $options = array();
+
   while ($account = db_fetch_object($result)) {
-    $accounts[$account->uid] = '';
-    $form['name'][$account->uid] = array('#markup' => theme('username', $account));
-    $form['status'][$account->uid] =  array('#markup' => $status[$account->status]);
+    $options[$account->uid] = array(
+      'username' => theme('username', $account),
+      'status' => $status[$account->status],
+      'member_for' => format_interval(time() - $account->created),
+      'last_access' => $account->access ? t('@time ago', array('@time' => format_interval(time() - $account->access))) : t('never'),
+      'operations' => l(t('edit'), "user/$account->uid/edit", array('query' => $destination)),
+    );
+
     $users_roles = array();
     $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = %d', $account->uid);
     while ($user_role = db_fetch_object($roles_result)) {
       $users_roles[] = $roles[$user_role->rid];
     }
     asort($users_roles);
-    $form['roles'][$account->uid][0] = array('#markup' => theme('item_list', $users_roles));
-    $form['member_for'][$account->uid] = array('#markup' => format_interval(REQUEST_TIME - $account->created));
-    $form['last_access'][$account->uid] =  array('#markup' => $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access))) : t('never'));
-    $form['operations'][$account->uid] = array('#markup' => l(t('edit'), "user/$account->uid/edit", array('query' => $destination)));
-  }
-  $form['accounts'] = array(
-    '#type' => 'checkboxes',
-    '#options' => $accounts
-  );
+    $options[$account->uid]['roles'] = theme('item_list', $users_roles);
+  }
+
+  if (empty($options)) {
+    $rows[] = array(array('data' => t('No users available.'), 'colspan' => '7'));
+    $form['accounts'] = array(
+      '#markup' => theme('table', $header, $rows),
+    );
+  }
+  else {
+    $form['accounts'] = array(
+      '#type' => 'tableselect',
+      '#header' => $header,
+      '#options' => $options,
+    );
+  }
   $form['pager'] = array('#markup' => theme('pager', NULL, 50, 0));
 
   return $form;
@@ -744,51 +758,6 @@
 }
 
 /**
- * Theme user administration overview.
- *
- * @ingroup themeable
- */
-function theme_user_admin_account($form) {
-  // Overview table:
-  $header = array(
-    theme('table_select_header_cell'),
-    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')
-  );
-
-  $output = drupal_render($form['options']);
-  if (isset($form['name']) && is_array($form['name'])) {
-    foreach (element_children($form['name']) as $key) {
-      $rows[] = array(
-        drupal_render($form['accounts'][$key]),
-        drupal_render($form['name'][$key]),
-        drupal_render($form['status'][$key]),
-        drupal_render($form['roles'][$key]),
-        drupal_render($form['member_for'][$key]),
-        drupal_render($form['last_access'][$key]),
-        drupal_render($form['operations'][$key]),
-      );
-    }
-  }
-  else {
-    $rows[] = array(array('data' => t('No users available.'), 'colspan' => '7'));
-  }
-
-  $output .= theme('table', $header, $rows);
-  if ($form['pager']['#markup']) {
-    $output .= drupal_render($form['pager']);
-  }
-
-  $output .= drupal_render($form);
-
-  return $output;
-}
-
-/**
  * Theme the new-role form.
  *
  * @ingroup themeable
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.656
diff -u -r1.656 system.module
--- modules/system/system.module	5 Jan 2009 02:52:43 -0000	1.656
+++ modules/system/system.module	9 Jan 2009 08:47:51 -0000
@@ -342,6 +342,15 @@
     '#size' => 60,
   );
 
+  $type['tableselect'] = array(
+    '#input' => TRUE,
+    '#advanced_select' => TRUE,
+    '#multiple' => TRUE,
+    '#process' => array('form_process_tableselect'),
+    '#options' => array(),
+    '#empty' => '',
+  );
+
 
   /**
    * Form structure.