Index: modules/toolbar/toolbar.admin.css
===================================================================
RCS file: modules/toolbar/toolbar.admin.css
diff -N modules/toolbar/toolbar.admin.css
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/toolbar/toolbar.admin.css	9 Oct 2009 12:08:05 -0000
@@ -0,0 +1,10 @@
+h4.shortcuts-set,
+div.shortcuts-change-set {
+  display: inline;
+}
+.toolbar-slot-hidden {
+  display: none;
+}
+div.form-item-set div.form-item-new {
+  display: inline;
+}
\ No newline at end of file
Index: modules/toolbar/toolbar.admin.inc
===================================================================
RCS file: modules/toolbar/toolbar.admin.inc
diff -N modules/toolbar/toolbar.admin.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/toolbar/toolbar.admin.inc	9 Oct 2009 12:08:06 -0000
@@ -0,0 +1,303 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Administrative items for the toolbar module.
+ */
+
+/**
+ * Main administration page for shortcuts.
+ */
+function toolbar_admin_shortcuts($form, &$form_state) {
+  $set = toolbar_set_load(toolbar_current_set());
+  $form = array();
+  $form['set'] = array(
+    '#markup' => t('Using set "@set"', array('@set' => $set['name'])),
+    '#prefix' => '<h4 class="shortcuts-set">',
+    '#suffix' => '</h4>',
+    '#weight' => -100,
+  );
+
+  $form['change_set'] = array(
+    '#markup' => l('Change set', 'admin/config/system/shortcuts/switch-set'),
+    '#prefix' => ' <div class="shortcuts-change-set">(',
+    '#suffix' => ')</div>',
+    '#weight' => -99,
+    '#access' => user_access('choose toolbar shortcut set'),
+  );
+
+  $form['shortcuts']['#tree'] = TRUE;
+  $form['shortcuts']['#theme'] = 'toolbar_admin_shortcuts_table';
+  $form['shortcuts']['enabled'] = $form['shortcuts']['disabled'] = array();
+  foreach ($set['shortcuts'] as $shortcut) {
+    $scid = $shortcut['scid'];
+    $status = ($shortcut['status'] ? 'enabled' : 'disabled');
+    $form['shortcuts'][$status][$scid]['name']['#markup'] = l($shortcut['name'], $shortcut['path']);
+    $form['shortcuts'][$status][$scid]['weight'] = array(
+      '#type' => 'weight',
+      '#title' => t('Weight'),
+      '#delta' => 50,
+      '#default_value' => $shortcut['weight'],
+      '#attributes' => array('class' => array('shortcut-weight')),
+    );
+    $form['shortcuts'][$status][$scid]['status'] = array(
+      '#type' => 'select',
+      '#title' => t('Status'),
+      '#options' => array('disabled' => t('Disabled'), 'enabled' => t('Enabled')),
+      '#default_value' => $status,
+      '#attributes' => array('class' => array('shortcut-status-select')),
+    );
+    
+    $form['shortcuts'][$status][$scid]['edit']['#markup'] = l(t('edit'), 'admin/config/system/shortcuts/shortcut/' . $scid);
+    $form['shortcuts'][$status][$scid]['delete']['#markup'] = l(t('delete'), 'admin/config/system/shortcuts/shortcut/' . $scid . '/delete');
+  }
+
+  $form['submit'] = array(
+    '#type' => 'submit', 
+    '#value' => t('Save Changes'),
+  );
+
+  return $form;
+}
+
+function toolbar_admin_shortcuts_submit($form, &$form_state) {
+  $map = array('enabled' => 1, 'disabled' => 0);
+  foreach (array('enabled', 'disabled') as $status) {
+    if (!empty($form_state['values']['shortcuts'][$status])) {
+      foreach ($form_state['values']['shortcuts'][$status] as $scid => $shortcut) {
+        $loaded_shortcut = toolbar_shortcut_load($scid);
+        $loaded_shortcut['status'] = $map[$shortcut['status']];
+        $loaded_shortcut['weight'] = $shortcut['weight'];
+        toolbar_shortcut_save($loaded_shortcut);
+      }
+    }
+  }
+}
+
+/**
+ * Add a new link to the current set.
+ */
+function toolbar_admin_shortcut_add_link() {
+  // Knock an enabled one out if we have to.
+  $set = toolbar_set_load(toolbar_current_set(), TRUE);
+  // Too many, knock one out.
+  while (count($set['shortcuts']) >= TOOLBAR_MAX_SLOTS) {
+    $disable = array_pop($set['shortcuts']);
+    $disable['status'] = 0;
+    toolbar_shortcut_save($disable);
+  }
+  $largest_weight = -50;
+  foreach ($set['shortcuts'] as $shortcut) {
+    $largest_weight = max($shortcut['weight'], $largest_weight);
+  }
+  toolbar_shortcut_save(array(
+    'sid'    => toolbar_current_set(),
+    'weight' => $largest_weight + 1,
+    'path'   => $_GET['link'],
+    'name'   => $_GET['name'],
+    'status' => 1,
+  ));
+  drupal_goto('admin/config/system/shortcuts');
+}
+
+
+/**
+ * Switch toolbar sets.
+ */
+function toolbar_admin_shortcuts_switch_set($form, &$form_state) {
+  $form = array();
+  $sets = toolbar_set_list();
+  $options = array();
+  foreach ($sets as $sid => $set) {
+    $options[$sid] = check_plain($set['name']);
+  }
+  // This is translated again in the theme function, so that the textfield can
+  // be added.
+  $options['new'] = t('New set: !textfield', array('!textfield' => ''));
+  $form['set'] = array(
+    '#type' => 'radios',
+    '#title' => t('Choose a set'),
+    '#options' => $options,
+    '#default_value' => toolbar_current_set(),
+  );
+
+  $form['new'] = array(
+    '#type' => 'textfield',
+    '#description' => t('The new set is created by copying items from the Default set.'),
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit', 
+    '#value' => t('Save configuration'),
+  );
+  return $form;
+}
+
+function toolbar_admin_shortcuts_switch_set_submit($form, &$form_state) {
+  global $user;
+
+  if ($form_state['values']['set'] == 'new') {
+    $set = toolbar_set_save(array(
+      'name' => $form_state['values']['new'],
+    ));
+    drupal_set_message(t('A new shortcut set called %name was created with the default shortcut items. Edits of this shortcut set will only have local effects.', array('%name' => $form_state['values']['new'])));
+  }
+  else {
+    $set = $form_state['values']['set'];
+  }
+  db_merge('toolbar_set_users')
+    ->key(array('uid' => $user->uid))
+    ->fields(array(
+      'sid' => $set,
+    ))
+    ->execute();
+
+  $form_state['redirect'] = 'admin/config/system/shortcuts';
+}
+
+/**
+ * Shortcut editing screen.
+ */
+function toolbar_admin_shortcut_edit($form, &$form_state, $shortcut = NULL) { 
+  if (!isset($shortcut)) {
+    $shortcut = array('name' => t(''), 'path' => '');
+    drupal_set_title(t('Add new shortcut'));
+  }
+  else {
+    drupal_set_title(t('Edit %shortcut', array('%shortcut' => $shortcut['name'])));
+  }
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Name'),
+    '#description' => t('The name of the shortcut.'),
+    '#size' => 40,
+    '#maxlength' => 255,
+    '#default_value' => $shortcut['name'],
+  );
+
+  $form['path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Path'),
+    '#description' => t('The path to the shortcut.'),
+    '#size' => 40,
+    '#maxlength' => 255,
+    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
+    '#default_value' => $shortcut['path'],
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit', 
+    '#value' => t('Save'),
+  );
+
+  $form_state['shortcut'] = $shortcut;
+
+  return $form;
+}
+
+function toolbar_admin_shortcut_edit_submit($form, &$form_state) {
+  $form_state['shortcut']['path'] = $form_state['values']['path'];
+  $form_state['shortcut']['name'] = $form_state['values']['name'];
+  toolbar_shortcut_save($form_state['shortcut']);
+  $form_state['redirect'] = 'admin/config/system/shortcuts';
+}
+
+/**
+ * Shortcut deleting screen.
+ */
+function toolbar_admin_shortcut_delete($form, &$form_state, $shortcut) {
+  $form = array();
+
+  $form['scid'] = array(
+    '#type' => 'value',
+    '#value' => $shortcut['scid'],
+  );
+
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the shortcut %name?', array('%name' => $shortcut['name'])),
+    'admin/config/system/shortcuts',
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+function toolbar_admin_shortcut_delete_submit($form, &$form_state) {
+  toolbar_shortcut_delete($form_state['values']['scid']);
+  $form_state['redirect'] = 'admin/config/system/shortcuts';
+}
+
+/**
+ * Theme function for set switching page.
+ * 
+ * @see toolbar_admin_shortcuts_switch_set
+ * @ingroup themable
+ */
+function theme_toolbar_admin_shortcuts_switch_set($variables) {
+  $form = $variables['form'];
+  drupal_add_css(drupal_get_path('module', 'toolbar') . '/toolbar.admin.css');
+  drupal_add_js(drupal_get_path('module', 'toolbar') . '/toolbar.admin.js');
+  $form['set']['new']['#title'] = t('New set: !textfield', array('!textfield' => drupal_render($form['new'])));
+  return drupal_render_children($form);
+}
+
+/**
+ * Theme function for the main shortcut administration page.
+ * 
+ * @see toolbar_admin_shortcuts
+ * @ingroup themable
+ */
+function theme_toolbar_admin_shortcuts_table($variables) {
+  $form = $variables['form'];
+  drupal_add_css(drupal_get_path('module', 'toolbar') . '/toolbar.admin.css');
+  drupal_add_js(drupal_get_path('module', 'toolbar') . '/toolbar.admin.js');
+  $map = array('disabled' => t('Disabled'), 'enabled' => t('Enabled'));
+
+  $rows = array();
+  foreach (array('enabled', 'disabled') as $status) {
+    drupal_add_tabledrag('shortcuts', 'match', 'sibling', 'shortcut-status-select');
+    drupal_add_tabledrag('shortcuts', 'order', 'sibling', 'shortcut-weight');
+    $rows[] = array(
+      'data' => array(array(
+        'colspan' => 5,
+        'data' => '<strong>' . $map[$status] . '</strong>',
+      )),
+      'class' => array('toolbar-status', 'toolbar-status-' . $status),
+    );
+    foreach (element_children($form[$status]) as $key) {
+      $shortcut = &$form[$status][$key];
+      $row = array();
+      $row[] = drupal_render($shortcut['name']);
+      $row[] = drupal_render($shortcut['weight']);
+      $row[] = drupal_render($shortcut['status']);
+      $row[] = drupal_render($shortcut['edit']);
+      $row[] = drupal_render($shortcut['delete']);
+      $rows[] = array(
+        'data' => $row,
+        'class' => array('draggable'),
+      );
+    }
+    if ($status == 'enabled') {
+      for ($i = 0; $i < TOOLBAR_MAX_SLOTS; $i++) {
+        $rows['empty-' . $i] = array(
+          'data' => array(array(
+            'colspan' => 5,
+            'data' => '<em>' . t('Empty') . '</em>',
+          )),
+          'class' => array('toolbar-slot-empty'),
+        );
+      }
+      $count_shortcuts = count(element_children($form[$status]));
+      if (!empty($count_shortcuts)) {
+        for ($i = 0; $i < min($count_shortcuts, TOOLBAR_MAX_SLOTS); $i++) {
+          $rows['empty-' . $i]['class'][] = 'toolbar-slot-hidden';
+        }
+      }
+    }
+  }
+  $header = array(t('Name'), t('Weight'), t('Status'), array('data' => t('Operations'), 'colspan' => 2));
+  return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'shortcuts')));
+}
Index: modules/toolbar/toolbar.admin.js
===================================================================
RCS file: modules/toolbar/toolbar.admin.js
diff -N modules/toolbar/toolbar.admin.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/toolbar/toolbar.admin.js	9 Oct 2009 12:08:06 -0000
@@ -0,0 +1,100 @@
+// $Id: toolbar.js,v 1.10 2009/08/04 06:26:52 webchick Exp $
+(function ($) {
+
+/**
+ * Handle the concept of a fixed number of slots.
+ *
+ * This behavior is dependent on the tableDrag behavior, since it uses the
+ * objects initialized in that behavior to update the row.
+ */
+Drupal.behaviors.shortcutDrag = {
+  attach: function (context, settings) {
+    if (Drupal.tableDrag) {
+      var table = $('table#shortcuts'),
+        visibleLength = 0,
+        slots = 0,
+        tableDrag = Drupal.tableDrag.shortcuts;
+      $('> tbody > tr, > tr', table)
+        .filter(':visible')
+          .filter(':odd').filter('.odd')
+            .removeClass('odd').addClass('even')
+          .end().end()
+          .filter(':even').filter('.even')
+            .removeClass('even').addClass('odd')
+          .end().end()
+        .end()
+        .filter('.toolbar-slot-empty').each(function(index) {
+          if ($(this).is(':visible')) {
+            visibleLength++;
+          }
+          slots++;
+        });
+
+      // Add a handler for when a row is swapped.
+      tableDrag.row.prototype.onSwap = function (swappedRow) {
+        var disabledIndex = $(table).find('tr').index($(table).find('tr.toolbar-status-disabled')) - slots - 2,
+          count = 0;
+        $(table).find('tr.toolbar-status-enabled').nextAll().filter(':not(.toolbar-slot-empty)').each(function(index) {
+          if (index < disabledIndex) {
+            count++;
+          }
+        });
+        var total = slots - count;
+        if (total == -1) {
+          var disabled = $(table).find('tr.toolbar-status-disabled');
+          disabled.after(disabled.prevAll().filter(':not(.toolbar-slot-empty)').get(0));
+        }
+        else if (total != visibleLength) {
+          if (total > visibleLength) {
+            // Less slots on screen than needed.
+            $('.toolbar-slot-empty:hidden:last').show();
+            visibleLength++;
+          }
+          else {
+            // More slots on screen than needed.
+            $('.toolbar-slot-empty:visible:last').hide();
+            visibleLength--;
+          }
+        }
+      };
+
+      // Add a handler so when a row is dropped, update fields dropped into new regions.
+      tableDrag.onDrop = function () {
+        // Use "status-message" row instead of "status" row because
+        // "status-{status_name}-message" is less prone to regexp match errors.
+        var statusRow = $(this.rowObject.element).prevAll('tr.toolbar-status').get(0);
+        var statusName = statusRow.className.replace(/([^ ]+[ ]+)*toolbar-status-([^ ]+)([ ]+[^ ]+)*/, '$2');
+        var statusField = $('select.shortcut-status-select', this.rowObject.element);
+        statusField.val(statusName);
+        return true;
+      };
+
+      tableDrag.restripeTable = function () {
+        // :even and :odd are reversed because jQuery counts from 0 and
+        // we count from 1, so we're out of sync.
+        // Match immediate children of the parent element to allow nesting.
+        $('> tbody > tr:visible, > tr:visible', this.table)
+          .filter(':odd').filter('.odd')
+            .removeClass('odd').addClass('even')
+          .end().end()
+          .filter(':even').filter('.even')
+            .removeClass('even').addClass('odd');
+      };
+    }
+  }
+};
+
+/**
+ * Make it so when you enter text into the "New set" textfield, the
+ * corresponding radio button gets selected.
+ */
+Drupal.behaviors.newSet = {
+  attach: function (context, settings) {
+    var selectDefault = function() {
+      $($(this).parents('div.form-item').get(1)).find('> label > input').attr('checked', 'checked');
+    };
+    $('div.form-item-new input').focus(selectDefault).keyup(selectDefault);
+  }
+};
+
+})(jQuery);
Index: modules/toolbar/toolbar.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.css,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 toolbar.css
--- modules/toolbar/toolbar.css	15 Sep 2009 03:38:06 -0000	1.4
+++ modules/toolbar/toolbar.css	9 Oct 2009 12:08:06 -0000
@@ -123,6 +123,7 @@ div#toolbar div.toolbar-menu ul li a.act
 div#toolbar div.toolbar-shortcuts {
   position: relative;
   padding: 0 10px;
+  height: 50px;
 }
 
 div#toolbar div.toolbar-shortcuts ul {
@@ -161,6 +162,49 @@ div#toolbar div.toolbar-shortcuts span.i
   -webkit-border-radius: 5px;
 }
 
+div#toolbar a#toolbar-customize {
+  float: right;
+}
+
+div.toolbar-add-to-shortcuts a {
+  min-width: 12px;
+  height: 12px;
+  background: url(toolbar.png) no-repeat -50px -60px;
+  display: block;
+  text-decoration: none;
+}
+
+div.toolbar-add-to-shortcuts a span.icon {
+  display: block;
+  width: 12px;
+  background: url(toolbar.png) no-repeat -50px -60px;
+  height: 12px;
+  float: left;
+}
+
+div.toolbar-add-to-shortcuts a:hover span.icon {
+  background-position: -50px -72px;
+}
+
+div.toolbar-add-to-shortcuts a span.text {
+  float: left;
+  display: none;
+}
+
+div.toolbar-add-to-shortcuts a:hover span.text {
+  font-size: 10px;
+  line-height: 12px;
+  color: #fff;
+  background-color: #5f605b;
+  display: block;
+  padding-right: 6px;
+  cursor: pointer;
+  -moz-border-radius-topright: 5px;
+  -moz-border-radius-bottomright: 5px;
+  -webkit-border-top-right-radius: 5px;
+  -webkit-border-bottom-right-radius: 5px;
+}
+
 /**
  * IE 6 Fixes.
  *
Index: modules/toolbar/toolbar.info
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.info,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 toolbar.info
--- modules/toolbar/toolbar.info	6 Jul 2009 13:54:21 -0000	1.2
+++ modules/toolbar/toolbar.info	9 Oct 2009 12:08:06 -0000
@@ -1,9 +1,9 @@
 ; $Id: toolbar.info,v 1.2 2009/07/06 13:54:21 dries Exp $
 name = Toolbar
-description = Toolbar exposing the top level administration menu items
+description = Toolbar exposing the top level administration menu items.
 core = 7.x
 package = Core
 version = VERSION
 files[] = toolbar.install
 files[] = toolbar.module
-dependencies[] = menu
+files[] = toolbar.admin.inc
Index: modules/toolbar/toolbar.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.install,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 toolbar.install
--- modules/toolbar/toolbar.install	31 Aug 2009 17:09:01 -0000	1.4
+++ modules/toolbar/toolbar.install	9 Oct 2009 12:08:06 -0000
@@ -7,51 +7,171 @@
  */
 
 /**
- * Implementation of hook_install().
- *
- * @todo
- *   Implement role based shortcut bars. 
+ * Implementat hook_install().
  */
 function toolbar_install() {
-  $t = get_t();
-  $query = db_insert('menu_custom')
-    ->fields(array(
-      'menu_name' => 'admin_shortcuts',
-      'title' => $t('Administration shortcuts'),
-      'description' => $t('The <em>Admininstration shortcuts</em> menu contains commonly used links for administrative tasks.')
-    ))
-    ->execute();
-
-  // Add starter convenience shortcuts.
-  menu_rebuild();
-  $items = array(
-    'node/add' => 'Add content',
-    'admin/content' => 'Find content',
-    'admin' => 'Dashboard',
-  );
-  $weight = -20;
-  foreach ($items as $path => $title) {
-    $link = array(
-      'mlid' => 0,
-      'link_title' => $title,
-      'link_path' => $path,
-      'router_path' => $path,
-      'menu_name' => 'admin_shortcuts',
-      'module' => 'menu',
-      'weight' => $weight,
+  include_once DRUPAL_ROOT . '/modules/toolbar/toolbar.module';
+  $sid = toolbar_set_save(array('name' => t('Default')));
+  variable_set('toolbar_shortcuts_default_set', $sid);
+  toolbar_shortcut_save(array(
+    'sid'    => $sid,
+    'weight' => -50,
+    'path'   => 'node/add',
+    'name'   => t('Add'),
+    'status' => 1,
+  ));
+  toolbar_shortcut_save(array(
+    'sid'    => $sid,
+    'weight' => -49,
+    'path'   => 'admin/content',
+    'name'   => t('Find Content'),
+    'status' => 1,
+  ));
+  toolbar_shortcut_save(array(
+    'sid'    => $sid,
+    'weight' => -48,
+    'path'   => 'admin',
+    'name'   => t('Dashboard'),
+    'status' => 1,
+  ));
+}
+
+
+/**
+ * Implement hook_schema().
+ */
+function toolbar_schema() {
+  $schema = array();
+
+  $schema['toolbar_sets'] = array(
+    'description' => 'Stores configuration options for toolbar shortcut sets.',
+    'fields' => array(
+      'sid' => array(
+        'description' => 'The primary identifier for the set.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'name' => array(
+        'description' => 'The set name.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('sid'),
+    'indexes' => array(
+      'name' => array('name'),
+    ),
     );
 
-    // Check for an existing menu item before attempting to create a new one.
-    $menu_link = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :path AND menu_name = :menu_name", array(
-      ':path' => $link['link_path'],
-      ':menu_name' => $link['menu_name']
-    ))
-    ->fetchField();
-    if (!$menu_link) {
-      menu_link_save($link);
-    }
-
-    // Increment weight so items can be displayed in desired order.
-    $weight++;
-  }
+  $schema['toolbar_shortcuts'] = array(
+    'description' => 'Stores shortcuts in toolbar sets.',
+    'fields' => array(
+      'scid' => array(
+        'description' => 'The primary identifier for the shortcut.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'sid' => array(
+        'description' => 'The {toolbar_sets}.sid for this shortcut.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'weight' => array(
+        'description' => 'The weight of the set in the shortcut.',
+        'type' => 'int',
+        'unsigned' => FALSE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'path' => array(
+        'description' => 'The path of the shortcut.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'name' => array(
+        'description' => 'The name of the shortcut.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'status' => array(
+        'description' => 'Boolean indicating whether or not this shortcut is enabled.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('scid'),
+    'indexes' => array(
+      'sid' => array('sid'),
+      'weight' => array('weight'),
+    ),
+    'foreign keys' => array(
+      'sid' => array('toolbar_sets' => 'sid'),
+    ),
+  );
+
+  $schema['toolbar_set_users'] = array(
+    'description' => 'Maps users to toolbar sets.',
+    'fields' => array(
+      'uid' => array(
+        'description' => 'The {user}.uid for this set.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'sid' => array(
+        'description' => 'The {toolbar_sets}.sid for this user.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('uid'),
+    'indexes' => array(
+      'sid' => array('sid'),
+    ),
+    'foreign keys' => array(
+      'sid' => array('toolbar_sets' => 'sid'),
+      'uid' => array('users' => 'uid'),
+    ),
+  );
+
+  $schema['toolbar_set_roles'] = array(
+    'description' => 'Maps roles to toolbar sets.',
+    'fields' => array(
+      'rid' => array(
+        'description' => 'The {role}.rid for this set.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'sid' => array(
+        'description' => 'The {toolbar_sets}.sid for this role.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('rid'),
+    'indexes' => array(
+      'sid' => array('sid'),
+    ),
+    'foreign keys' => array(
+      'sid' => array('toolbar_sets' => 'sid'),
+      'rid' => array('role' => 'rid'),
+    ),
+  );
+
+  return $schema;
 }
Index: modules/toolbar/toolbar.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.module,v
retrieving revision 1.13
diff -u -p -u -p -r1.13 toolbar.module
--- modules/toolbar/toolbar.module	15 Sep 2009 20:50:48 -0000	1.13
+++ modules/toolbar/toolbar.module	9 Oct 2009 12:08:06 -0000
@@ -7,7 +7,70 @@
  */
 
 /**
- * Implementation of hook_permission().
+ * Maximum number of slots in the toolbar.
+ */
+define('TOOLBAR_MAX_SLOTS', 7);
+
+/**
+ * Implement hook_menu().
+ */
+function toolbar_menu() {
+  $items = array();
+  $items['admin/config/system/shortcuts'] = array(
+    'title' => 'Shortcuts',
+    'description' => 'Configure shortcuts displayed in the administration toolbar.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('toolbar_admin_shortcuts'),
+    'access arguments' => array('customize toolbar shortcuts'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'toolbar.admin.inc',
+  );
+  $items['admin/config/system/shortcuts/add-link'] = array(
+    'title' => 'Add shortcut',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('toolbar_admin_shortcut_edit'),
+    'access arguments' => array('customize toolbar shortcuts'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'toolbar.admin.inc',
+  );
+  $items['admin/config/system/shortcuts/switch-set'] = array(
+    'title' => 'Switch set',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('toolbar_admin_shortcuts_switch_set'),
+    'access arguments' => array('choose toolbar shortcut set'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'toolbar.admin.inc',
+  );
+  $items['admin/config/system/shortcuts/shortcut/%toolbar_shortcut'] = array(
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('toolbar_admin_shortcut_edit', 5),
+    'access arguments' => array('customize toolbar shortcuts'),
+    'type' => MENU_CALLBACK,
+    'file' => 'toolbar.admin.inc',
+  );
+  $items['admin/config/system/shortcuts/shortcut/%toolbar_shortcut/edit'] = array(
+    'title' => 'Edit',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('toolbar_admin_shortcut_edit', 5),
+    'access arguments' => array('customize toolbar shortcuts'),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'file' => 'toolbar.admin.inc',
+    'weight' => 0,
+  );
+  $items['admin/config/system/shortcuts/shortcut/%toolbar_shortcut/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('toolbar_admin_shortcut_delete', 5),
+    'access arguments' => array('customize toolbar shortcuts'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'toolbar.admin.inc',
+    'weight' => 1,
+  );
+  return $items;
+}
+
+/**
+ * Implement hook_permission().
  */
 function toolbar_permission() {
   return array(
@@ -15,6 +78,18 @@ function toolbar_permission() {
       'title' => t('Access administration toolbar'),
       'description' => t('Access the persistent administration toolbar displayed on all pages.'),
     ),
+    'customize toolbar shortcuts' => array(
+      'title' => t('Customize toolbar shortcuts'),
+      'description' => t('Customize the shortcuts in the toolbar displayed on all pages.')
+    ),
+    'choose toolbar shortcut set' => array(
+      'title' => t('Choose toolbar shortcut set'),
+      'description' => t('Choose which set of toolbar shortcuts appear in the user\'s toolbar.')
+    ),
+    'administer toolbar shortcut sets' => array(
+      'title' => t('Administer toolbar shortcut sets'),
+      'description' => t('Administer per-role assignment of shortcut sets and create new sets.')
+    ),
   );
 }
 
@@ -27,6 +102,14 @@ function toolbar_theme($existing, $type,
     'template' => 'toolbar',
     'path' => drupal_get_path('module', 'toolbar'),
   );
+  $items['toolbar_admin_shortcuts_table'] = array(
+    'arguments' => array('form' => NULL),
+    'file' => 'toolbar.admin.inc',
+  );
+  $items['toolbar_admin_shortcuts_switch_set'] = array(
+    'arguments' => array('form' => NULL),
+    'file' => 'toolbar.admin.inc',
+  );
   return $items;
 }
 
@@ -38,17 +121,167 @@ function toolbar_theme($existing, $type,
 function toolbar_page_build(&$page) {
   if (user_access('access toolbar')) {
     $page['page_top']['toolbar'] = toolbar_build();
+    if (user_access('customize toolbar shortcuts')) {
+      // $_GET['q'] is the unaliased version.
+      $get = $_GET;
+      unset($get['q']);
+      $link = $_GET['q'];
+      if (!empty($get)) {
+        $link .= '?' . drupal_http_build_query($get);
+      }
+      $query = array(
+        'link' => $link,
+        'name' => drupal_get_title(),
+      );
+      $page['add_to_shortcuts'] = array(
+        '#prefix' => '<div class="toolbar-add-to-shortcuts">',
+        '#markup' => l('<span class="icon"></span><span class="text">' . t('Add to shortcuts') . '</span>', 'admin/config/system/shortcuts/add-link', array('query' => $query, 'html' => TRUE)),
+        '#suffix' => '</div>',
+      );
+    }
   }
 }
 
 /**
- * Implement hook_preprocess_page().
+ * Implement hook_preprocess_html().
  *
  * Add some page classes, so global page theming can adjust to the toolbar.
  */
 function toolbar_preprocess_html(&$vars) {
   if (user_access('access toolbar')) {
     $vars['classes_array'][] = 'toolbar toolbar-shortcuts';
+    if (user_access('customize toolbar shortcuts')) {
+      $vars['add_to_shortcuts'] = drupal_render($vars['page']['add_to_shortcuts']);
+    }
+  }
+}
+
+/**
+ * Implement hook_preprocess_page().
+ *
+ * Add the add_to_shortcuts variable.
+ */
+function toolbar_preprocess_page(&$vars) {
+  if (user_access('access toolbar') && user_access('customize toolbar shortcuts')) {
+    $vars['add_to_shortcuts'] = drupal_render($vars['page']['add_to_shortcuts']);
+  }
+}
+
+/**
+ * Find the set for the current user.
+ */
+function toolbar_current_set($account = NULL) {
+  if (!isset($account)) {
+    global $user;
+    $account = $user;
+  }
+  $user_set = db_select('toolbar_set_users')
+    ->fields('toolbar_set_users')
+    ->condition('uid', $account->uid)
+    ->execute()
+    ->fetchAssoc();
+  if ($user_set) {
+    return $user_set['sid'];
+  }
+  return variable_get('toolbar_shortcuts_default_set', 1);
+}
+
+/**
+ * Load a toolbar shortcut by ID.
+ */
+function toolbar_shortcut_load($scid) {
+  return db_select('toolbar_shortcuts')
+    ->fields('toolbar_shortcuts')
+    ->condition('scid', $scid)
+    ->execute()
+    ->fetchAssoc();
+}
+
+/**
+ * Save a toolbar shortcut.
+ */
+function toolbar_shortcut_save($shortcut) {
+  if (isset($shortcut['scid'])) {
+    $scid = $shortcut['scid'];
+    unset($shortcut['scid']);
+    db_update('toolbar_shortcuts')
+      ->fields($shortcut)
+      ->condition('scid', $scid)
+      ->execute();
+    return $scid;
+  }
+  else {
+    return db_insert('toolbar_shortcuts')
+      ->fields($shortcut)
+      ->execute();
+  }
+}
+
+/**
+ * Delete a toolbar shortcut.
+ */
+function toolbar_shortcut_delete($scid) {
+  return db_delete('toolbar_shortcuts')
+    ->condition('scid', $scid)
+    ->execute();
+}
+
+/**
+ * List all toolbar sets.
+ */
+function toolbar_set_list() {
+  return db_select('toolbar_sets')
+    ->fields('toolbar_sets')
+    ->execute()
+    ->fetchAllAssoc('sid', PDO::FETCH_ASSOC);
+}
+
+/**
+ * Load a toolbar set by ID.
+ * 
+ * @param $sid
+ *   The ID of the set to load.
+ * @param $enabled_shortcuts
+ *   Whether to return only enabled shortcuts (defaults to FALSE).
+ */
+function toolbar_set_load($sid, $enabled_shortcuts = FALSE) {
+  $set = db_select('toolbar_sets')
+    ->fields('toolbar_sets')
+    ->condition('sid', $sid)
+    ->execute()
+    ->fetchAssoc();
+  $query = db_select('toolbar_shortcuts')
+    ->fields('toolbar_shortcuts')
+    ->condition('sid', $sid);
+  if ($enabled_shortcuts) {
+    $query->condition('status', 1);
+  }
+  $set['shortcuts'] = $query->execute()
+    ->fetchAllAssoc('scid', PDO::FETCH_ASSOC);
+  uasort($set['shortcuts'], 'drupal_sort_weight');
+  return $set;
+}
+
+/**
+ * Save a toolbar set.
+ */
+function toolbar_set_save($set) {
+  if (isset($set['sid'])) {
+    $sid = $set['sid'];
+    unset($set['sid']);
+    db_update('toolbar_sets')
+      ->fields($set)
+      ->condition('sid', $sid)
+      ->execute;
+    return $sid;
+  }
+  else {
+    $new_sid = db_insert('toolbar_sets')
+      ->fields($set)
+      ->execute();
+    // @todo: figure out how to do this without MySQLisms (with db_insert()?).
+    db_query('INSERT INTO {toolbar_shortcuts} (sid, weight, path, name, status) SELECT :new_sid, weight, path, name, status FROM {toolbar_shortcuts} WHERE sid = :default_sid', array(':new_sid' => $new_sid, ':default_sid' => variable_get('toolbar_shortcuts_default_set', 1)));
+    return $new_sid;
   }
 }
 
@@ -102,12 +335,33 @@ function toolbar_build() {
   );
 
   // Add convenience shortcut links.
-  $shortcuts = menu_tree_all_data('admin_shortcuts');
-  $shortcuts = toolbar_menu_navigation_links($shortcuts);
+  $set = toolbar_set_load(toolbar_current_set(), TRUE);
+  $shortcuts = array();
+  foreach ($set['shortcuts'] as $shortcut) {
+    $class = '';
+    // Make sure we have a path specific ID in place, so we can attach icons
+    // and behaviors to the items.
+    $id = str_replace(array('/', '<', '>'), array('-', '', ''), $shortcut['path']);
+    $class = ' path-' . $id;
+    if (toolbar_in_active_trail($shortcut['path'])) {
+      $class .= ' active-trail';
+    }
+    $shortcuts[$shortcut['scid']] = array(
+      'href' => $shortcut['path'],
+      'title' => '<span class="icon"></span>' . $shortcut['name'],
+      'html' => TRUE,
+      'attributes' => array('id' => 'toolbar-link-' . $id, 'class' => array('to-overlay')),
+    );
+  }
   $build['toolbar_shortcuts'] = array(
-    '#theme' => 'links',
-    '#links' => $shortcuts,
-    '#attributes' => array('id' => 'toolbar-shortcuts'),
+    'shortcuts' => array(
+      '#theme' => 'links',
+      '#links' => $shortcuts,
+      '#attributes' => array('id' => 'toolbar-shortcuts'),
+    ),
+    'configure' => array(
+      '#markup' => l(t('edit shortcuts'), 'admin/config/system/shortcuts', array('attributes' => array('id' => 'toolbar-customize'))),
+    ),
   );
 
   return $build;
@@ -159,7 +413,7 @@ function toolbar_menu_navigation_links($
       if (toolbar_in_active_trail($item['link']['href'])) {
         $class .= ' active-trail';
       }
-      $links['menu-' . $item['link']['mlid'] . $class] = $link;
+      $links[$item['link']['mlid']] = $link;
     }
   }
   return $links;
Index: modules/toolbar/toolbar.png
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.png,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 toolbar.png
Binary files /tmp/cvsjTV1oI and toolbar.png differ
Index: themes/seven/page.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/seven/page.tpl.php,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 page.tpl.php
--- themes/seven/page.tpl.php	15 Sep 2009 17:10:39 -0000	1.4
+++ themes/seven/page.tpl.php	9 Oct 2009 12:08:06 -0000
@@ -4,6 +4,7 @@
   <div id="branding" class="clearfix">
     <?php print $breadcrumb; ?>
     <?php if ($title): ?><h1 class="page-title"><?php print $title; ?></h1><?php endif; ?>
+    <?php if ($add_to_shortcuts): ?><?php print $add_to_shortcuts; ?><?php endif; ?>
     <?php if ($primary_local_tasks): ?><ul class="tabs primary"><?php print $primary_local_tasks; ?></ul><?php endif; ?>
   </div>
 
Index: themes/seven/style.css
===================================================================
RCS file: /cvs/drupal/drupal/themes/seven/style.css,v
retrieving revision 1.18
diff -u -p -u -p -r1.18 style.css
--- themes/seven/style.css	11 Sep 2009 13:48:44 -0000	1.18
+++ themes/seven/style.css	9 Oct 2009 12:08:06 -0000
@@ -735,3 +735,10 @@ body.overlay #page {
 body.overlay #block-system-main {
   padding: 20px;
 }
+
+/* Shortcut theming */
+div.toolbar-add-to-shortcuts {
+  float: left;
+  margin-left: 6px;
+  margin-top: 6px;
+}
