diff --git a/includes/nodequeue.admin.inc b/includes/nodequeue.admin.inc
index 06fca99..3ada83b 100644
--- a/includes/nodequeue.admin.inc
+++ b/includes/nodequeue.admin.inc
@@ -35,6 +35,12 @@ function nodequeue_admin_settings($form, &$form_state) {
       If you wish to have fewer views, you can disable this option and use a single view with an argument for the qid."),
     '#default_value' => variable_get('nodequeue_view_per_queue', 1),
   );
+  $form['nodequeue_show_contextual_links'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Display contextual links.'),
+    '#description' => t("A contextual link to edit the nodequeue will be displayed on Views that have a nodequeue relationship."),
+    '#default_value' => variable_get('nodequeue_show_contextual_links', TRUE),
+  );
   return system_settings_form($form);
 }
 
diff --git a/includes/views/nodequeue.views.inc b/includes/views/nodequeue.views.inc
index a7ea7cb..72c873e 100644
--- a/includes/views/nodequeue.views.inc
+++ b/includes/views/nodequeue.views.inc
@@ -269,3 +269,85 @@ function nodequeue_views_data_alter(&$data) {
     ),
   );
 }
+
+
+
+/**
+ * Implements hook_contextual_links_view_alter().
+ */
+function nodequeue_contextual_links_view_alter(&$element, $items) {
+  if (empty($element['#element']['#contextual_links']['views_ui'])) {
+    return;
+  }
+  if (!variable_get('nodequeue_show_contextual_links', TRUE)) {
+    return;
+  }
+
+  // If this is a block placed by Context then the View info is stored in
+  // a slightly different place
+  $views_info = empty($element['#element']['#views_contextual_links_info'])
+    ? $element['#element']['content']['#views_contextual_links_info']
+    : $element['#element']['#views_contextual_links_info'];
+
+  $display_id = $views_info['views_ui']['view_display_id'];
+  $view_name = $views_info['views_ui']['view_name'];
+  $view = views_get_view($view_name, TRUE);
+
+  // If the view is empty, e.g. it wasn't saved yet and has no display
+  // objects, this won't work.
+  if (empty($view)) {
+    return;
+  }
+  $view->build($display_id);
+
+  $nodequeue_rels = array(
+    'nodequeue_handler_relationship_nodequeue'
+  );
+  $subqueue_arg_titles = array(
+    'Subqueue reference',
+    'Subqueue reference (optional)',
+  );
+
+  // Cycle through all the relationships to find ones provided by nodequeue.
+  // We'll use this as a trigger to attach the links.
+  foreach ($view->relationship as $rel) {
+    if (!in_array(get_class($rel), $nodequeue_rels, TRUE)) {
+      continue;
+    }
+
+    foreach ($rel->options['names'] as $queue_name) {
+      if (gettype($queue_name) != 'string') {
+        continue;
+      }
+      $qid_map = nodequeue_get_qid_map();
+      $qid = $qid_map[$queue_name];
+      $queue = nodequeue_load($qid);
+      $element['#links'][$queue_name] = array(
+        'title' => t('Edit queue: !queue_name', array('!queue_name' => $queue->title)),
+        'href' => 'admin/structure/nodequeue/' . $qid . '/view',
+        'query' => array('destination' => current_path()),
+      );
+
+      // Cycle through all arguments to find ones that limit us by subqueue.
+      // If we find some, add further links to subqueues.
+      foreach ($view->argument as $arg) {
+        $is_subqueue_arg = $arg->options['relationship'] == $rel->options['id']
+          && in_array($arg->definition['title'], $subqueue_arg_titles, TRUE);
+
+        if (!$is_subqueue_arg) {
+          continue;
+        }
+
+        // Provide contextual links for each of the subqueues.
+        $subqueues = nodequeue_load_subqueues_by_reference(array($qid => $arg->value));
+        foreach ($subqueues as $sqid => $subqueue) {
+          $element['#links'][$queue_name . '_' . $sqid] = array(
+            'title' => t('Edit subqueue: !queue_name > !subqueue_title', array('!queue_name' => $queue->title, '!subqueue_title' => $subqueue->title)),
+            'href' => 'admin/structure/nodequeue/' . $qid . '/view/' . $sqid,
+            'query' => array('destination' => current_path()),
+          );
+        }
+      }
+    }
+  }
+}
