Index: profiles/standard/standard.install
===================================================================
RCS file: /cvs/drupal/drupal/profiles/standard/standard.install,v
retrieving revision 1.8
diff -u -r1.8 standard.install
--- profiles/standard/standard.install	11 Mar 2010 22:48:34 -0000	1.8
+++ profiles/standard/standard.install	22 Mar 2010 00:21:44 -0000
@@ -408,6 +408,7 @@
   // Create a default role for site administrators, with all available permissions assigned.
   $admin_role = new stdClass();
   $admin_role->name = 'administrator';
+  $admin_role->weight = 2;
   user_role_save($admin_role);
   user_role_grant_permissions($admin_role->rid, array_keys(module_invoke_all('permission')));
   // Set this as the administrator role.
Index: modules/user/user.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.install,v
retrieving revision 1.40
diff -u -r1.40 user.install
--- modules/user/user.install	1 Mar 2010 07:39:12 -0000	1.40
+++ modules/user/user.install	22 Mar 2010 00:21:42 -0000
@@ -98,11 +98,20 @@
         'default' => '',
         'description' => 'Unique role name.',
       ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The weight of this role in listings and the user interface.',
+      ),
     ),
     'unique keys' => array(
       'name' => array('name'),
     ),
     'primary key' => array('rid'),
+    'indexes' => array(
+      'name_weight' => array('name', 'weight'),
+    ),
   );
 
   $schema['users'] = array(
@@ -280,10 +289,10 @@
 
   // Built-in roles.
   $rid_anonymous = db_insert('role')
-    ->fields(array('name' => 'anonymous user'))
+    ->fields(array('name' => 'anonymous user', 'weight' => 0))
     ->execute();
   $rid_authenticated = db_insert('role')
-    ->fields(array('name' => 'authenticated user'))
+    ->fields(array('name' => 'authenticated user', 'weight' => 1))
     ->execute();
 
   // Sanity check to ensure the anonymous and authenticated role IDs are the
@@ -545,11 +554,6 @@
 }
 
 /**
- * @} End of "defgroup user-updates-6.x-to-7.x"
- * The next series of updates should start at 8000.
- */
-
-/**
  * Add module data to {role_permission}.
  */
 function user_update_7006(&$sandbox) {
@@ -574,3 +578,16 @@
       ->execute();
   }
 }
+
+/**
+ * Add a weight column to user roles.
+ */
+function user_update_7007() {
+  db_add_field('role', 'weight', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
+  db_add_index('role', 'name_weight', array('name', 'weight'));
+}
+
+/**
+ * @} End of "defgroup user-updates-6.x-to-7.x"
+ * The next series of updates should start at 8000.
+ */
Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.102
diff -u -r1.102 user.admin.inc
--- modules/user/user.admin.inc	21 Mar 2010 21:20:43 -0000	1.102
+++ modules/user/user.admin.inc	22 Mar 2010 00:21:42 -0000
@@ -801,57 +801,141 @@
 }
 
 /**
- * Menu callback: administer roles.
+ * Form to re-order roles or add a new one.
  *
  * @ingroup forms
- * @see user_admin_role_validate()
- * @see user_admin_role_submit()
- * @see theme_user_admin_new_role()
+ * @see theme_user_admin_roles()
  */
-function user_admin_role() {
-  $rid = arg(5);
-  if ($rid) {
-    if ($rid == DRUPAL_ANONYMOUS_RID || $rid == DRUPAL_AUTHENTICATED_RID) {
-      drupal_goto('admin/people/permissions/roles');
-    }
-    // Display the edit role form.
-    $role = db_query('SELECT * FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchObject();
-    $form['name'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Role name'),
-      '#default_value' => $role->name,
-      '#size' => 30,
-      '#required' => TRUE,
-      '#maxlength' => 64,
-      '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'),
-    );
-    $form['rid'] = array(
-      '#type' => 'value',
-      '#value' => $rid,
-    );
-    $form['actions'] = array('#type' => 'container', '#attributes' => array('class' => array('form-actions')));
-    $form['actions']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Save role'),
-    );
-    $form['actions']['delete'] = array(
-      '#type' => 'submit',
-      '#value' => t('Delete role'),
+function user_admin_roles($form, $form_state) {
+  $roles = user_roles();
+
+  $form['roles'] = array(
+    '#tree' => TRUE,
+  );
+  $order = 0;
+  foreach ($roles as $rid => $name) {
+    $form['roles'][$rid]['#role'] = (object) array(
+      'rid' => $rid,
+      'name' => $name,
+      'weight' => $order,
     );
-  }
-  else {
-    $form['name'] = array(
+    $form['roles'][$rid]['#weight'] = $order;
+    $form['roles'][$rid]['weight'] = array(
       '#type' => 'textfield',
-      '#size' => 32,
-      '#maxlength' => 64,
-    );
-    $form['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Add role'),
-    );
-    $form['#submit'][] = 'user_admin_role_submit';
-    $form['#validate'][] = 'user_admin_role_validate';
+      '#size' => 4,
+      '#default_value' => $order,
+      '#attributes' => array('class' => array('role-weight')),
+    );
+    $order++;
+  }
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#size' => 32,
+    '#maxlength' => 64,
+  );
+  $form['add'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add role'),
+    '#validate' => array('user_admin_role_validate'),
+    '#submit' => array('user_admin_role_submit'),
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save order'),
+    '#submit' => array('user_admin_roles_order_submit'),
+  );
+
+  return $form;
+}
+
+/**
+ * Form submit function. Update the role weights.
+ */
+function user_admin_roles_order_submit($form, &$form_state) {
+  foreach ($form_state['values']['roles'] as $rid => $role_values) {
+    $role = $form['roles'][$rid]['#role'];
+    $role->weight = $role_values['weight'];
+    user_role_save($role);
   }
+}
+
+/**
+ * Theme the role order and new role form.
+ *
+ * @ingroup themeable
+ */
+function theme_user_admin_roles($variables) {
+  $form = $variables['form'];
+
+  $header = array(t('Name'), t('Weight'), array('data' => t('Operations'), 'colspan' => 2));
+  foreach (element_children($form['roles']) as $rid) {
+    $name = $form['roles'][$rid]['#role']->name;
+    $row = array();
+    if (in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+      $row[] = t('@name <em>(locked)</em>', array('@name' => $name));
+      $row[] = drupal_render($form['roles'][$rid]['weight']);
+      $row[] = '';
+      $row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
+    }
+    else {
+      $row[] = check_plain($name);
+      $row[] = drupal_render($form['roles'][$rid]['weight']);
+      $row[] = l(t('edit role'), 'admin/people/permissions/roles/edit/' . $rid);
+      $row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
+    }
+    $rows[] = array('data' => $row, 'class' => array('draggable'));
+  }
+  $rows[] = array(array('data' => drupal_render($form['name']) . drupal_render($form['add']), 'colspan' => 4, 'class' => 'edit-name'));
+
+  drupal_add_tabledrag('user-roles', 'order', 'sibling', 'role-weight');
+
+  $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'user-roles')));
+  $output .= drupal_render_children($form);
+
+  return $output;
+}
+
+/**
+ * Form to configure a single role.
+ *
+ * @ingroup forms
+ * @see user_admin_role_validate()
+ * @see user_admin_role_submit()
+ */
+function user_admin_role($form, $form_state, $role) {
+  if ($role->rid == DRUPAL_ANONYMOUS_RID || $role->rid == DRUPAL_AUTHENTICATED_RID) {
+    drupal_goto('admin/people/permissions/roles');
+  }
+
+  // Display the edit role form.
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Role name'),
+    '#default_value' => $role->name,
+    '#size' => 30,
+    '#required' => TRUE,
+    '#maxlength' => 64,
+    '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'),
+  );
+  $form['rid'] = array(
+    '#type' => 'value',
+    '#value' => $role->rid,
+  );
+  $form['weight'] = array(
+    '#type' => 'value',
+    '#value' => $role->weight,
+  );
+  $form['actions'] = array('#type' => 'container', '#attributes' => array('class' => array('form-actions')));
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save role'),
+  );
+  $form['actions']['delete'] = array(
+    '#type' => 'submit',
+    '#value' => t('Delete role'),
+  );
+
   return $form;
 }
 
@@ -893,32 +977,6 @@
 }
 
 /**
- * Theme the new-role form.
- *
- * @ingroup themeable
- */
-function theme_user_admin_new_role($variables) {
-  $form = $variables['form'];
-
-  $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => 2));
-  foreach (user_roles() as $rid => $name) {
-    $edit_permissions = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
-    if (in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
-      $rows[] = array(t('!name %locked', array('!name' => $name, '%locked' => t('(locked)'))), '', $edit_permissions);
-    }
-    else {
-      $rows[] = array($name, l(t('edit role'), 'admin/people/permissions/roles/edit/' . $rid), $edit_permissions);
-    }
-  }
-  $rows[] = array(array('data' => drupal_render($form['name']) . drupal_render($form['submit']), 'colspan' => 3, 'class' => 'edit-name'));
-
-  $output = drupal_render_children($form);
-  $output .= theme('table', array('header' => $header, 'rows' => $rows));
-
-  return $output;
-}
-
-/**
  * Theme user administration filter selector.
  *
  * @ingroup themeable
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.1141
diff -u -r1.1141 user.module
--- modules/user/user.module	21 Mar 2010 21:20:43 -0000	1.1141
+++ modules/user/user.module	22 Mar 2010 00:21:44 -0000
@@ -42,7 +42,7 @@
     case 'admin/people/permissions':
       return '<p>' . t('Permissions let you control what users can do and see on your site. You can define a specific set of permissions for each role. (See the <a href="@role">Roles</a> page to create a role). Two important roles to consider are Authenticated Users and Administrators. Any permissions granted to the Authenticated Users role will be given to any user who can log into your site.  You can make any role the Administrator role for the site, meaning this will be granted all new permissions automatically. You can do this on the <a href="@settings">User Settings</a> page. You should be careful to ensure that only trusted users are given this access and level of control of your site.', array('@role' => url('admin/people/permissions/roles'), '@settings' => url('admin/config/people/accounts'))) . '</p>';
     case 'admin/people/permissions/roles':
-      $output = '<p>' . t('Roles allow you to fine tune the security and administration of Drupal. A role defines a group of users that have certain privileges as defined in <a href="@permissions">user permissions</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the <em>role names</em> of the various roles. To delete a role choose "edit".', array('@permissions' => url('admin/people/permissions'))) . '</p>';
+      $output = '<p>' . t('Roles allow you to fine tune the security and administration of Drupal. A role defines a group of users that have certain privileges as defined on the <a href="@permissions">permissions page</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the <em>role names</em> of the various roles and the order of these roles when displayed in the user interface. To delete a role choose "edit role".', array('@permissions' => url('admin/people/permissions'))) . '</p>';
       $output .= '<p>'. t('By default, Drupal comes with two user roles:') . '</p>';
       $output .= '<ul>';
       $output .= '<li>' . t("Anonymous user: this role is used for users that don't have a user account or that are not authenticated.") . '</li>';
@@ -102,7 +102,7 @@
       'render element' => 'form',
       'file' => 'user.admin.inc',
     ),
-    'user_admin_new_role' => array(
+    'user_admin_roles' => array(
       'render element' => 'form',
       'file' => 'user.admin.inc',
     ),
@@ -1504,6 +1504,8 @@
     'weight' => -10,
     'file' => 'user.admin.inc',
   );
+
+  // Permissions and role forms.
   $items['admin/people/permissions'] = array(
     'title' => 'Permissions',
     'description' => 'Determine access to features by selecting permissions for roles.',
@@ -1523,20 +1525,20 @@
     'title' => 'Roles',
     'description' => 'List, edit, or add user roles.',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('user_admin_new_role'),
+    'page arguments' => array('user_admin_roles'),
     'access arguments' => array('administer permissions'),
     'file' => 'user.admin.inc',
     'type' => MENU_LOCAL_TASK,
     'weight' => -5,
   );
-  $items['admin/people/permissions/roles/edit'] = array(
+  $items['admin/people/permissions/roles/edit/%user_role'] = array(
     'title' => 'Edit role',
-    'page arguments' => array('user_admin_role'),
+    'page arguments' => array('user_admin_role', 5),
     'access arguments' => array('administer permissions'),
     'type' => MENU_CALLBACK,
   );
 
-
+  // Add a new user form.
   $items['admin/people/create'] = array(
     'title' => 'Add user',
     'page arguments' => array('create'),
@@ -2498,17 +2500,11 @@
  *   value.
  */
 function user_roles($membersonly = FALSE, $permission = NULL) {
-  // System roles take the first two positions.
-  $roles = array(
-    DRUPAL_ANONYMOUS_RID => NULL,
-    DRUPAL_AUTHENTICATED_RID => NULL,
-  );
-
   if (!empty($permission)) {
-    $result = db_query("SELECT r.* FROM {role} r INNER JOIN {role_permission} p ON r.rid = p.rid WHERE p.permission = :permission ORDER BY r.name", array(':permission' => $permission));
+    $result = db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {role_permission} p ON r.rid = p.rid WHERE p.permission = :permission ORDER BY r.weight, r.name", array(':permission' => $permission));
   }
   else {
-    $result = db_query('SELECT * FROM {role} ORDER BY name');
+    $result = db_query('SELECT rid, name FROM {role} ORDER BY weight, name');
   }
 
   foreach ($result as $role) {
@@ -2527,8 +2523,7 @@
     }
   }
 
-  // Filter to remove unmatched system roles.
-  return array_filter($roles);
+  return $roles;
 }
 
 /**
@@ -2541,7 +2536,7 @@
  *   exists, FALSE otherwise.
  */
 function user_role_load($role) {
-  $field = is_int($role) ? 'rid' : 'name';
+  $field = is_numeric($role) ? 'rid' : 'name';
   return db_select('role', 'r')
     ->fields('r')
     ->condition($field, $role)
@@ -2565,6 +2560,12 @@
     // Prevent leading and trailing spaces in role names.
     $role->name = trim($role->name);
   }
+  if (!isset($role->weight)) {
+    // Set a role weight to make this new role last.
+    $query = db_select('role');
+    $query->addExpression('MAX(weight)');
+    $role->weight = $query->execute()->fetchField() + 1;
+  }
   if (!empty($role->rid) && $role->name) {
     $status = drupal_write_record('role', $role, 'rid');
     module_invoke_all('user_role_update', $role);
@@ -3049,7 +3050,6 @@
 function user_forms() {
   $forms['user_admin_access_add_form']['callback'] = 'user_admin_access_form';
   $forms['user_admin_access_edit_form']['callback'] = 'user_admin_access_form';
-  $forms['user_admin_new_role']['callback'] = 'user_admin_role';
   return $forms;
 }
 
Index: modules/user/user.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.css,v
retrieving revision 1.19
diff -u -r1.19 user.css
--- modules/user/user.css	30 Jan 2010 07:59:26 -0000	1.19
+++ modules/user/user.css	22 Mar 2010 00:21:42 -0000
@@ -33,10 +33,10 @@
  * Override default textfield float to put the "Add role" button next to
  * the input textfield.
  */
-#user-admin-new-role td.edit-name {
+#user-admin-roles td.edit-name {
   clear: both;
 }
-#user-admin-new-role .form-item-name {
+#user-admin-roles .form-item-name {
   float: left;
   margin-right: 1em;
 }
