From 489a28a5e01b47bd949797bed5b98a800270edab Mon Sep 17 00:00:00 2001
From: "tim.plunkett" <tim.plunkett@241634.no-reply.drupal.org>
Date: Wed, 26 Sep 2012 22:26:34 +0200
Subject: [PATCH] Issue #1792860 by tim.plunkett, dawehner: Move procedural
 code from views_ui().module and admin.inc to ViewUI.

---
 includes/admin.inc                            | 2517 ++---------------
 lib/Drupal/views/Plugin/views/access/Role.php |    4 +-
 .../views/argument/ArgumentPluginBase.php     |   40 +-
 .../views/display/DisplayPluginBase.php       |   16 +-
 .../views/Plugin/views/display/Page.php       |    2 +-
 lib/Drupal/views/ViewExecutable.php           |   14 +-
 lib/Drupal/views/ViewListController.php       |    2 +-
 lib/Drupal/views/ViewStorage.php              |   13 +-
 lib/Drupal/views/ViewUI.php                   | 1873 ++++++++++++
 views_ui.module                               |   32 +-
 10 files changed, 2152 insertions(+), 2361 deletions(-)

diff --git a/includes/admin.inc b/includes/admin.inc
index 7ae715fee93e..a69cb080ee1e 100644
--- a/includes/admin.inc
+++ b/includes/admin.inc
@@ -6,72 +6,10 @@
  */
 
 use Drupal\Core\Database\Database;
-use Drupal\views\TempStore\UserTempStore;
-use Drupal\views\ViewExecutable;
 use Drupal\views\ViewUI;
 use Drupal\views\Analyzer;
 use Drupal\views\Plugin\views\wizard\WizardException;
 
-/**
- * Create an array of Views admin CSS for adding or attaching.
- *
- * This returns an array of arrays. Each array represents a single
- * file. The array format is:
- * - file: The fully qualified name of the file to send to drupal_add_css
- * - options: An array of options to pass to drupal_add_css.
- */
-function views_ui_get_admin_css() {
-  $module_path = drupal_get_path('module', 'views_ui');
-  $list = array();
-  $list[$module_path . '/css/views-admin.css'] = array();
-  $list[$module_path . '/css/views-admin.theme.css'] = array();
-
-  // Add in any theme specific CSS files we have
-  $themes = list_themes();
-  $theme_key = $GLOBALS['theme'];
-  while ($theme_key) {
-    // Try to find the admin css file for non-core themes.
-    if (!in_array($theme_key, array('seven', 'bartik'))) {
-      $theme_path = drupal_get_path('theme', $theme_key);
-      // First search in the css directory, then in the root folder of the theme.
-      if (file_exists($theme_path . "/css/views-admin.$theme_key.css")) {
-        $list[$theme_path . "/css/views-admin.$theme_key.css"] = array(
-          'group' => CSS_THEME,
-        );
-      }
-      elseif (file_exists($theme_path . "/views-admin.$theme_key.css")) {
-        $list[$theme_path . "/views-admin.$theme_key.css"] = array(
-          'group' => CSS_THEME,
-        );
-      }
-    }
-    else {
-      $list[$module_path . "/css/views-admin.$theme_key.css"] = array(
-        'group' => CSS_THEME,
-      );
-    }
-    $theme_key = isset($themes[$theme_key]->base_theme) ? $themes[$theme_key]->base_theme : '';
-  }
-  // Views contains style overrides for the following modules
-  $module_list = array('contextual', 'ctools');
-  foreach ($module_list as $module) {
-    if (module_exists($module)) {
-      $list[$module_path . '/css/views-admin.' . $module . '.css'] = array();
-    }
-  }
-
-  return $list;
-}
-
-/**
- * Adds standard Views administration CSS to the current page.
- */
-function views_ui_add_admin_css() {
-  foreach (views_ui_get_admin_css() as $file => $options) {
-    drupal_add_css($file, $options);
-  }
-}
-
 /**
  * Returns the results of the live preview.
  */
@@ -81,298 +19,17 @@ function views_ui_preview(ViewUI $view, $display_id, $args = array()) {
   if (!is_array($args)) {
     $args = array_slice(func_get_args(), 2);
   }
-
-  // Save the current path so it can be restored before returning from this function.
-  $old_q = current_path();
-
-  // Determine where the query and performance statistics should be output.
-  $config = config('views.settings');
-  $show_query = $config->get('ui.show.sql_query.enabled');
-  $show_info = $config->get('ui.show.preview_information');
-  $show_location = $config->get('ui.show.sql_query.where');
-
-  $show_stats = $config->get('ui.show.performance_statistics');
-  if ($show_stats) {
-    $show_stats = $config->get('ui.show.sql_query.where');
-  }
-
-  $combined = $show_query && $show_stats;
-
-  $rows = array('query' => array(), 'statistics' => array());
-  $output = '';
-
-  $errors = $view->validate();
-  if ($errors === TRUE) {
-    $view->ajax = TRUE;
-    $view->live_preview = TRUE;
-    $view->views_ui_context = TRUE;
-
-    // AJAX happens via $_POST but everything expects exposed data to
-    // be in GET. Copy stuff but remove ajax-framework specific keys.
-    // If we're clicking on links in a preview, though, we could actually
-    // still have some in $_GET, so we use $_REQUEST to ensure we get it all.
-    $exposed_input = drupal_container()->get('request')->request->all();
-    foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', 'ajax_html_ids', 'ajax_page_state', 'form_id', 'form_build_id', 'form_token') as $key) {
-      if (isset($exposed_input[$key])) {
-        unset($exposed_input[$key]);
-      }
-    }
-
-    $view->setExposedInput($exposed_input);
-
-    if (!$view->setDisplay($display_id)) {
-      return t('Invalid display id @display', array('@display' => $display_id));
-    }
-
-    $view->setArguments($args);
-
-    // Store the current view URL for later use:
-    if ($view->display_handler->getOption('path')) {
-      $path = $view->getUrl();
-    }
-
-    // Make view links come back to preview.
-    $view->override_path = 'admin/structure/views/nojs/preview/' . $view->storage->name . '/' . $display_id;
-
-    // Also override the current path so we get the pager.
-    $original_path = current_path();
-    $q = _current_path($view->override_path);
-    if ($args) {
-      $q .= '/' . implode('/', $args);
-      _current_path($q);
-    }
-
-    // Suppress contextual links of entities within the result set during a
-    // Preview.
-    // @todo We'll want to add contextual links specific to editing the View, so
-    //   the suppression may need to be moved deeper into the Preview pipeline.
-    views_ui_contextual_links_suppress_push();
-    $preview = $view->preview($display_id, $args);
-    views_ui_contextual_links_suppress_pop();
-
-    // Reset variables.
-    unset($view->override_path);
-    _current_path($original_path);
-
-    // Prepare the query information and statistics to show either above or
-    // below the view preview.
-    if ($show_info || $show_query || $show_stats) {
-      // Get information from the preview for display.
-      if (!empty($view->build_info['query'])) {
-        if ($show_query) {
-          $query = $view->build_info['query'];
-          // Only the sql default class has a method getArguments.
-          $quoted = array();
-
-          if (get_class($view->query) == 'views_plugin_query_default') {
-            $quoted = $query->getArguments();
-            $connection = Database::getConnection();
-            foreach ($quoted as $key => $val) {
-              if (is_array($val)) {
-                $quoted[$key] = implode(', ', array_map(array($connection, 'quote'), $val));
-              }
-              else {
-                $quoted[$key] = $connection->quote($val);
-              }
-            }
-          }
-          $rows['query'][] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain(strtr($query, $quoted)) . '</pre>');
-          if (!empty($view->additional_queries)) {
-            $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
-            foreach ($view->additional_queries as $query) {
-              if ($queries) {
-                $queries .= "\n";
-              }
-              $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . $query[0];
-            }
-
-            $rows['query'][] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
-          }
-        }
-        if ($show_info) {
-          $rows['query'][] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->getTitle()));
-          if (isset($path)) {
-            $path = l($path, $path);
-          }
-          else {
-            $path = t('This display has no path.');
-          }
-          $rows['query'][] = array('<strong>' . t('Path') . '</strong>', $path);
-        }
-
-        if ($show_stats) {
-          $rows['statistics'][] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100)));
-          $rows['statistics'][] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100)));
-          $rows['statistics'][] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($view->render_time * 100000) / 100)));
-
-        }
-        drupal_alter('views_preview_info', $rows, $view);
-      }
-      else {
-        // No query was run. Display that information in place of either the
-        // query or the performance statistics, whichever comes first.
-        if ($combined || ($show_location === 'above')) {
-          $rows['query'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
-        }
-        else {
-          $rows['statistics'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
-        }
-      }
-    }
-  }
-  else {
-    foreach ($errors as $error) {
-      drupal_set_message($error, 'error');
-    }
-    $preview = t('Unable to preview due to validation errors.');
-  }
-
-  // Assemble the preview, the query info, and the query statistics in the
-  // requested order.
-  if ($show_location === 'above') {
-    if ($combined) {
-      $output .= '<div class="views-query-info">' . theme('table', array('rows' => array_merge($rows['query'], $rows['statistics']))) . '</div>';
-    }
-    else {
-      $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['query'])) . '</div>';
-    }
-  }
-  elseif ($show_stats === 'above') {
-    $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['statistics'])) . '</div>';
-  }
-
-  $output .= $preview;
-
-  if ($show_location === 'below') {
-    if ($combined) {
-      $output .= '<div class="views-query-info">' . theme('table', array('rows' => array_merge($rows['query'], $rows['statistics']))) . '</div>';
-    }
-    else {
-      $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['query'])) . '</div>';
-    }
-  }
-  elseif ($show_stats === 'below') {
-    $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['statistics'])) . '</div>';
-  }
-
-  _current_path($old_q);
-  return $output;
+  return $view->renderPreview($display_id, $args);
 }
 
 /**
  * Page callback to add a new view.
  */
 function views_ui_add_page() {
-  views_ui_add_admin_css();
   drupal_set_title(t('Add new view'));
-  return drupal_get_form('views_ui_add_form');
-}
-
-/**
- * Form builder for the "add new view" page.
- */
-function views_ui_add_form($form, &$form_state) {
-  $form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
-  $form['#attributes']['class'] = array('views-admin');
-
-  $form['human_name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('View name'),
-    '#required' => TRUE,
-    '#size' => 32,
-    '#default_value' => !empty($form_state['view']) ? $form_state['view']->storage->getHumanName() : '',
-    '#maxlength' => 255,
-  );
-  $form['name'] = array(
-    '#type' => 'machine_name',
-    '#maxlength' => 128,
-    '#machine_name' => array(
-      'exists' => 'views_get_view',
-      'source' => array('human_name'),
-    ),
-    '#description' => t('A unique machine-readable name for this View. It must only contain lowercase letters, numbers, and underscores.'),
-  );
-
-  $form['description_enable'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Description'),
-  );
-  $form['description'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Provide description'),
-    '#title_display' => 'invisible',
-    '#size' => 64,
-    '#default_value' => !empty($form_state['view']) ? $form_state['view']->description : '',
-    '#states' => array(
-      'visible' => array(
-        ':input[name="description_enable"]' => array('checked' => TRUE),
-      ),
-    ),
-  );
-
-  // Create a wrapper for the entire dynamic portion of the form. Everything
-  // that can be updated by AJAX goes somewhere inside here. For example, this
-  // is needed by "Show" dropdown (below); it changes the base table of the
-  // view and therefore potentially requires all options on the form to be
-  // dynamically updated.
-  $form['displays'] = array();
-
-  // Create the part of the form that allows the user to select the basic
-  // properties of what the view will display.
-  $form['displays']['show'] = array(
-    '#type' => 'fieldset',
-    '#tree' => TRUE,
-    '#attributes' => array('class' => array('container-inline')),
-  );
-
-  // Create the "Show" dropdown, which allows the base table of the view to be
-  // selected.
-  $wizard_plugins = views_ui_get_wizards();
-  $options = array();
-  foreach ($wizard_plugins as $key => $wizard) {
-    $options[$key] = $wizard['title'];
-  }
-  $form['displays']['show']['wizard_key'] = array(
-    '#type' => 'select',
-    '#title' => t('Show'),
-    '#options' => $options,
-  );
-  $show_form = &$form['displays']['show'];
-  $default_value = module_exists('node') ? 'node' : 'users';
-  $show_form['wizard_key']['#default_value'] = views_ui_get_selected($form_state, array('show', 'wizard_key'), $default_value, $show_form['wizard_key']);
-  // Changing this dropdown updates the entire content of $form['displays'] via
-  // AJAX.
-  views_ui_add_ajax_trigger($show_form, 'wizard_key', array('displays'));
-
-  // Build the rest of the form based on the currently selected wizard plugin.
-  $wizard_key = $show_form['wizard_key']['#default_value'];
-
-  views_include_handlers();
-  $wizard_instance = views_get_plugin('wizard', $wizard_key);
-
-  $form = $wizard_instance->build_form($form, $form_state);
-
-  $form['save'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save & exit'),
-    '#validate' => array('views_ui_wizard_form_validate'),
-    '#submit' => array('views_ui_add_form_save_submit'),
-  );
-  $form['continue'] = array(
-    '#type' => 'submit',
-    '#value' => t('Continue & edit'),
-    '#validate' => array('views_ui_wizard_form_validate'),
-    '#submit' => array('views_ui_add_form_store_edit_submit'),
-    '#process' => array_merge(array('views_ui_default_button'), element_info_property('submit', '#process', array())),
-  );
-  $form['cancel'] = array(
-    '#type' => 'submit',
-    '#value' => t('Cancel'),
-    '#submit' => array('views_ui_add_form_cancel_submit'),
-    '#limit_validation_errors' => array(),
-  );
-
-  return $form;
+  $form_state['build_info']['args'] = array();
+  $form_state['build_info']['callback'] = array('Drupal\views\ViewUI', 'addForm');
+  return drupal_build_form('views_ui_add_form', $form_state);
 }
 
 /**
@@ -808,68 +465,28 @@ function views_ui_break_lock_confirm($form, &$form_state, ViewUI $view) {
     $cancel = 'admin/structure/views/view/' . $view->storage->name . '/edit';
   }
 
-  $account = user_load($view->locked->ownerId);
-  return confirm_form($form,
+  $account = user_load($view->locked->ownerID);
+  $form = confirm_form($form,
                   t('Are you sure you want to break the lock on view %name?',
                   array('%name' => $view->storage->name)),
                   $cancel,
                   t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', array('account' => $account)))),
                   t('Break lock'),
                   t('Cancel'));
-}
-
-/**
- * Submit handler to break_lock a view.
- */
-function views_ui_break_lock_confirm_submit(&$form, &$form_state) {
-  UserTempStore::clearAll('view', $form_state['view']->storage->name);
-  $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit';
-  drupal_set_message(t('The lock has been broken and you may now edit this view.'));
-}
-
-/**
- * Helper function to return the used display_id for the edit page
- *
- * This function handles access to the display.
- */
-function views_ui_edit_page_display(ViewUI $view, $display_id) {
-  // Determine the displays available for editing.
-  if ($tabs = views_ui_edit_page_display_tabs($view, $display_id)) {
-    // If a display isn't specified, use the first one.
-    if (empty($display_id)) {
-      foreach ($tabs as $id => $tab) {
-        if (!isset($tab['#access']) || $tab['#access']) {
-          $display_id = $id;
-          break;
-        }
-      }
-    }
-    // If a display is specified, but we don't have access to it, return
-    // an access denied page.
-    if ($display_id && (!isset($tabs[$display_id]) || (isset($tabs[$display_id]['#access']) && !$tabs[$display_id]['#access']))) {
-      return MENU_ACCESS_DENIED;
-    }
-
-    return $display_id;
-  }
-  elseif ($display_id) {
-    return MENU_ACCESS_DENIED;
-  }
-  else {
-    $display_id = NULL;
-  }
-
-  return $display_id;
+  $form['actions']['submit']['#submit'][] = array($view, 'submitBreakLock');
+  return $form;
 }
 
 /**
  * Page callback for the Edit View page.
  */
 function views_ui_edit_page(ViewUI $view, $display_id = NULL) {
-  $display_id = views_ui_edit_page_display($view, $display_id);
+  $display_id = $view->getDisplayEditPage($display_id);
   if (!in_array($display_id, array(MENU_ACCESS_DENIED, MENU_NOT_FOUND))) {
     $build = array();
-    $build['edit_form'] = drupal_get_form('views_ui_edit_form', $view, $display_id);
+    $form_state['build_info']['args'] = array($display_id);
+    $form_state['build_info']['callback'] = array($view, 'editForm');
+    $build['edit_form'] = drupal_build_form('views_ui_edit_form', $form_state);
     $build['preview'] = views_ui_build_preview($view, $display_id, FALSE);
   }
   else {
@@ -885,7 +502,8 @@ function views_ui_build_preview(ViewUI $view, $display_id, $render = TRUE) {
     '#attributes' => array('id' => 'views-preview-wrapper', 'class' => 'views-admin clearfix'),
   );
 
-  $form_state = array('build_info' => array('args' => array($view, $display_id)));
+  $form_state['build_info']['args'] = array($display_id);
+  $form_state['build_info']['callback'] = array($view, 'buildPreviewForm');
   $build['controls'] = drupal_build_form('views_ui_preview_form', $form_state);
 
   $args = array();
@@ -896,1621 +514,213 @@ function views_ui_build_preview(ViewUI $view, $display_id, $render = TRUE) {
   $build['preview'] = array(
     '#theme_wrappers' => array('container'),
     '#attributes' => array('id' => 'views-live-preview'),
-    '#markup' => $render ? views_ui_preview($view->cloneView(), $display_id, $args) : '',
+    '#markup' => $render ? views_ui_preview($view->cloneView(FALSE, TRUE), $display_id, $args) : '',
   );
 
   return $build;
 }
 
-/**
- * Form builder callback for editing a View.
- *
- * @todo Remove as many #prefix/#suffix lines as possible. Use #theme_wrappers
- *   instead.
- *
- * @todo Rename to views_ui_edit_view_form(). See that function for the "old"
- *   version.
- *
- * @see views_ui_ajax_get_form()
- */
-function views_ui_edit_form($form, &$form_state, ViewUI $view, $display_id = NULL) {
-  // Do not allow the form to be cached, because $form_state['view'] can become
-  // stale between page requests.
-  // See views_ui_ajax_get_form() for how this affects #ajax.
-  // @todo To remove this and allow the form to be cacheable:
-  //   - Change $form_state['view'] to $form_state['temporary']['view'].
-  //   - Add a #process function to initialize $form_state['temporary']['view']
-  //     on cached form submissions.
-  //   - Use form_load_include().
-  $form_state['no_cache'] = TRUE;
-
-  if ($display_id) {
-    if (!$view->setDisplay($display_id)) {
-      $form['#markup'] = t('Invalid display id @display', array('@display' => $display_id));
-      return $form;
-    }
-  }
-
-  $form['#tree'] = TRUE;
-  // @todo When more functionality is added to this form, cloning here may be
-  //   too soon. But some of what we do with $view later in this function
-  //   results in making it unserializable due to PDO limitations.
-  $form_state['view'] = clone($view);
-
-  $form['#attached']['library'][] = array('system', 'jquery.ui.tabs');
-  $form['#attached']['library'][] = array('system', 'jquery.ui.dialog');
-  $form['#attached']['library'][] = array('system', 'drupal.ajax');
-  $form['#attached']['library'][] = array('system', 'jquery.form');
-  $form['#attached']['library'][] = array('system', 'drupal.states');
-  // TODO: This should be getting added to the page when an ajax popup calls
-  // for it, instead of having to add it manually here.
-  // @TODO: Figure out why this is not a library.
-  $form['#attached']['js'][] = 'core/misc/tabledrag.js';
-
-  $form['#attached']['css'] = views_ui_get_admin_css();
-  $module_path = drupal_get_path('module', 'views_ui');
-
-  $form['#attached']['js'][] = $module_path . '/js/views-admin.js';
-  $form['#attached']['js'][] = array(
-    'data' => array('views' => array('ajax' => array(
-      'id' => '#views-ajax-body',
-      'title' => '#views-ajax-title',
-      'popup' => '#views-ajax-popup',
-      'defaultForm' => views_ui_get_default_ajax_message(),
-    ))),
-    'type' => 'setting',
-  );
-
-  $form += array(
-    '#prefix' => '',
-    '#suffix' => '',
-  );
-  $form['#prefix'] = $form['#prefix'] . '<div class="views-edit-view views-admin clearfix">';
-  $form['#suffix'] = '</div>' . $form['#suffix'];
+function template_preprocess_views_ui_display_tab_setting(&$variables) {
+  static $zebra = 0;
+  $variables['zebra'] = ($zebra % 2 === 0 ? 'odd' : 'even');
+  $zebra++;
 
-  $form['#attributes']['class'] = array('form-edit');
+  // Put the main link to the left side
+  array_unshift($variables['settings_links'], $variables['link']);
+  $variables['settings_links'] = implode('<span class="label">&nbsp;|&nbsp;</span>', $variables['settings_links']);
 
-  if (isset($view->locked) && is_object($view->locked)) {
-    $form['locked'] = array(
-      '#theme_wrappers' => array('container'),
-      '#attributes' => array('class' => array('view-locked', 'messages', 'warning')),
-      '#markup' => t('This view is being edited by user !user, and is therefore locked from editing by others. This lock is !age old. Click here to <a href="!break">break this lock</a>.', array('!user' => theme('username', array('account' => user_load($view->locked->ownerId))), '!age' => format_interval(REQUEST_TIME - $view->locked->updated), '!break' => url('admin/structure/views/view/' . $view->storage->name . '/break-lock'))),
-    );
-  }
-  if (isset($view->vid) && $view->vid == 'new') {
-    $message = t('* All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard the view.');
+  if (!empty($variables['defaulted'])) {
+    $variables['attributes']['class'][] = 'defaulted';
   }
-  else {
-    $message = t('* All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard your changes.');
+  if (!empty($variables['overridden'])) {
+    $variables['attributes']['class'][] = 'overridden';
+    $variables['attributes_array']['title'][] = t('Overridden');
   }
 
-  $form['changed'] = array(
-    '#theme_wrappers' => array('container'),
-    '#attributes' => array('class' => array('view-changed', 'messages', 'warning')),
-    '#markup' => $message,
-  );
-  if (empty($view->changed)) {
-    $form['changed']['#attributes']['class'][] = 'js-hide';
+  // Append a colon to the description, if requested.
+  if ($variables['description'] && $variables['description_separator']) {
+    $variables['description'] .= t(':');
   }
+}
 
-  $form['help_text'] = array(
-    '#prefix' => '<div>',
-    '#suffix' => '</div>',
-    '#markup' => t('Modify the display(s) of your view below or add new displays.'),
-  );
-
-  $form['actions'] = array(
-    '#type' => 'actions',
-    '#weight' => 0,
-  );
+function template_preprocess_views_ui_display_tab_bucket(&$variables) {
+  $element = $variables['element'];
 
-  if (empty($view->changed)) {
-    $form['actions']['#attributes'] = array(
-      'class' => array(
-        'js-hide',
-      ),
-    );
+  if (!empty($element['#name'])) {
+    $variables['attributes']['class'][] = drupal_html_class($element['#name']);
+  }
+  if (!empty($element['#overridden'])) {
+    $variables['attributes']['class'][] = 'overridden';
+    $variables['attributes_array']['title'][] = t('Overridden');
   }
 
-  $form['actions']['save'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    // Taken from the "old" UI. @TODO: Review and rename.
-    '#validate' => array('views_ui_edit_view_form_validate'),
-    '#submit' => array('views_ui_edit_view_form_submit'),
-  );
-  $form['actions']['cancel'] = array(
-    '#type' => 'submit',
-    '#value' => t('Cancel'),
-    '#submit' => array('views_ui_edit_view_form_cancel'),
-  );
-
-  $form['displays'] = array(
-    '#prefix' => '<h1 class="unit-title clearfix">' . t('Displays') . '</h1>' . "\n" . '<div class="views-displays">',
-    '#suffix' => '</div>',
-  );
-
-  $form['displays']['top'] = views_ui_render_display_top($view, $display_id);
-
-  // The rest requires a display to be selected.
-  if ($display_id) {
-    $form_state['display_id'] = $display_id;
-
-    // The part of the page where editing will take place.
-    $form['displays']['settings'] = array(
-      '#type' => 'container',
-      '#id' => 'edit-display-settings',
-    );
-    $display_title = views_ui_get_display_label($view, $display_id, FALSE);
+  $variables['content'] = $element['#children'];
+  $variables['title'] = $element['#title'];
+  $variables['actions'] = !empty($element['#actions']) ? $element['#actions'] : '';
+}
 
-    $form['displays']['settings']['#title'] = '<h2>' . t('@display_title details', array('@display_title' => ucwords($display_title))) . '</h2>';
+function template_preprocess_views_ui_display_tab_column(&$variables) {
+  $element = $variables['element'];
 
-    // Add a text that the display is disabled.
-    if (!empty($view->displayHandlers[$display_id])) {
-      $enabled = $view->displayHandlers[$display_id]->getOption('enabled');
-      if (empty($enabled)) {
-        $form['displays']['settings']['disabled']['#markup'] = t('This display is disabled.');
-      }
-    }
+  $variables['content'] = $element['#children'];
+  $variables['column'] = $element['#column'];
+}
 
-    $form['displays']['settings']['settings_content']= array(
-      '#theme_wrappers' => array('container'),
-    );
-    // Add the edit display content
-    $form['displays']['settings']['settings_content']['tab_content'] = views_ui_get_display_tab($view, $display_id);
-    $form['displays']['settings']['settings_content']['tab_content']['#theme_wrappers'] = array('container');
-    $form['displays']['settings']['settings_content']['tab_content']['#attributes'] = array('class' => array('views-display-tab'));
-    $form['displays']['settings']['settings_content']['tab_content']['#id'] = 'views-tab-' . $display_id;
-    // Mark deleted displays as such.
-    if (!empty($view->display[$display_id]['deleted'])) {
-      $form['displays']['settings']['settings_content']['tab_content']['#attributes']['class'][] = 'views-display-deleted';
-    }
-    // Mark disabled displays as such.
-    if (empty($enabled)) {
-      $form['displays']['settings']['settings_content']['tab_content']['#attributes']['class'][] = 'views-display-disabled';
+/**
+ * Move form elements into fieldsets for presentation purposes.
+ *
+ * Many views forms use #tree = TRUE to keep their values in a hierarchy for
+ * easier storage. Moving the form elements into fieldsets during form building
+ * would break up that hierarchy. Therefore, we wait until the pre_render stage,
+ * where any changes we make affect presentation only and aren't reflected in
+ * $form_state['values'].
+ */
+function views_ui_pre_render_add_fieldset_markup($form) {
+  foreach (element_children($form) as $key) {
+    $element = $form[$key];
+    // In our form builder functions, we added an arbitrary #fieldset property
+    // to any element that belongs in a fieldset. If this form element has that
+    // property, move it into its fieldset.
+    if (isset($element['#fieldset']) && isset($form[$element['#fieldset']])) {
+      $form[$element['#fieldset']][$key] = $element;
+      // Remove the original element this duplicates.
+      unset($form[$key]);
     }
-
-    // The content of the popup dialog.
-    $form['ajax-area'] = array(
-      '#theme_wrappers' => array('container'),
-      '#id' => 'views-ajax-popup',
-    );
-    $form['ajax-area']['ajax-title'] = array(
-      '#markup' => '<h2 id="views-ajax-title"></h2>',
-    );
-    $form['ajax-area']['ajax-body'] = array(
-      '#theme_wrappers' => array('container'),
-      '#id' => 'views-ajax-body',
-      '#markup' => views_ui_get_default_ajax_message(),
-    );
   }
 
-  // If relationships had to be fixed, we want to get that into the cache
-  // so that edits work properly, and to try to get the user to save it
-  // so that it's not using weird fixed up relationships.
-  if (!empty($view->relationships_changed) && drupal_container()->get('request')->request->count()) {
-    drupal_set_message(t('This view has been automatically updated to fix missing relationships. While this View should continue to work, you should verify that the automatic updates are correct and save this view.'));
-    views_ui_cache_set($view);
-  }
   return $form;
 }
 
 /**
- * Provide the preview formulas and the preview output, too.
+ * Flattens the structure of an element containing the #flatten property.
+ *
+ * If a form element has #flatten = TRUE, then all of it's children
+ * get moved to the same level as the element itself.
+ * So $form['to_be_flattened'][$key] becomes $form[$key], and
+ * $form['to_be_flattened'] gets unset.
  */
-function views_ui_preview_form($form, &$form_state, ViewUI $view, $display_id = 'default') {
-  $form_state['no_cache'] = TRUE;
-  $form_state['view'] = $view;
-
-  $form['#attributes'] = array('class' => array('clearfix'));
-
-  // Add a checkbox controlling whether or not this display auto-previews.
-  $form['live_preview'] = array(
-    '#type' => 'checkbox',
-    '#id' => 'edit-displays-live-preview',
-    '#title' => t('Auto preview'),
-    '#default_value' => config('views.settings')->get('ui.always_live_preview'),
-  );
-
-  // Add the arguments textfield
-  $form['view_args'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Preview with contextual filters:'),
-    '#description' => t('Separate contextual filter values with a "/". For example, %example.', array('%example' => '40/12/10')),
-    '#id' => 'preview-args',
-  );
-
-  // Add the preview button
-  $form['button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Update preview'),
-    '#attributes' => array('class' => array('arguments-preview', 'ctools-auto-submit-click')),
-    '#prefix' => '<div id="preview-submit-wrapper">',
-    '#suffix' => '</div>',
-    '#id' => 'preview-submit',
-    '#submit' => array('views_ui_edit_form_submit_preview'),
-    '#ajax' => array(
-      'path' => 'admin/structure/views/view/' . $view->storage->name . '/preview/' . $display_id . '/ajax',
-      'wrapper' => 'views-preview-wrapper',
-      'event' => 'click',
-      'progress' => array('type' => 'throbber'),
-      'method' => 'replace',
-    ),
-    // Make ENTER in arguments textfield (and other controls) submit the form
-    // as this button, not the Save button.
-    // @todo This only works for JS users. To make this work for nojs users,
-    //   we may need to split Preview into a separate form.
-    '#process' => array_merge(array('views_ui_default_button'), element_info_property('submit', '#process', array())),
-  );
-  $form['#action'] = url('admin/structure/views/view/' . $view->storage->name .'/preview/' . $display_id);
-
-  return $form;
-}
-
-/**
- * Render the top of the display so it can be updated during ajax operations.
- */
-function views_ui_render_display_top(ViewUI $view, $display_id) {
-  $element['#theme_wrappers'] = array('views_container');
-  $element['#attributes']['class'] = array('views-display-top', 'clearfix');
-  $element['#attributes']['id'] = array('views-display-top');
-
-  // Extra actions for the display
-  $element['extra_actions'] = array(
-    '#theme' => 'links__ctools_dropbutton',
-    '#attributes' => array(
-        'id' => 'views-display-extra-actions',
-        'class' => array(
-          'horizontal', 'right', 'links', 'actions',
-        ),
-      ),
-    '#links' => array(
-      'edit-details' => array(
-        'title' => t('edit view name/description'),
-        'href' => "admin/structure/views/nojs/edit-details/{$view->storage->name}",
-        'attributes' => array('class' => array('views-ajax-link')),
-      ),
-      'analyze' => array(
-        'title' => t('analyze view'),
-        'href' => "admin/structure/views/nojs/analyze/{$view->storage->name}/$display_id",
-        'attributes' => array('class' => array('views-ajax-link')),
-      ),
-      'clone' => array(
-        'title' => t('clone view'),
-        'href' => "admin/structure/views/view/{$view->storage->name}/clone",
-      ),
-      'reorder' => array(
-        'title' => t('reorder displays'),
-        'href' => "admin/structure/views/nojs/reorder-displays/{$view->storage->name}/$display_id",
-        'attributes' => array('class' => array('views-ajax-link')),
-      ),
-    ),
-  );
-
-  // Let other modules add additional links here.
-  drupal_alter('views_ui_display_top_links', $element['extra_actions']['#links'], $view, $display_id);
-
-  if (isset($view->type) && $view->type != t('Default')) {
-    if ($view->type == t('Overridden')) {
-      $element['extra_actions']['#links']['revert'] = array(
-        'title' => t('revert view'),
-        'href' => "admin/structure/views/view/{$view->storage->name}/revert",
-        'query' => array('destination' => "admin/structure/views/view/{$view->storage->name}"),
-      );
-    }
-    else {
-      $element['extra_actions']['#links']['delete'] = array(
-        'title' => t('delete view'),
-        'href' => "admin/structure/views/view/{$view->storage->name}/delete",
-      );
-    }
-  }
-
-  // Determine the displays available for editing.
-  if ($tabs = views_ui_edit_page_display_tabs($view, $display_id)) {
-    if ($display_id) {
-      $tabs[$display_id]['#active'] = TRUE;
-    }
-    $tabs['#prefix'] = '<h2 class="element-invisible">' . t('Secondary tabs') . '</h2><ul id = "views-display-menu-tabs" class="tabs secondary">';
-    $tabs['#suffix'] = '</ul>';
-    $element['tabs'] = $tabs;
-  }
-
-  // Buttons for adding a new display.
-  foreach (views_fetch_plugin_names('display', NULL, array($view->storage->base_table)) as $type => $label) {
-    $element['add_display'][$type] = array(
-      '#type' => 'submit',
-      '#value' => t('Add !display', array('!display' => $label)),
-      '#limit_validation_errors' => array(),
-      '#submit' => array('views_ui_edit_form_submit_add_display', 'views_ui_edit_form_submit_delay_destination'),
-      '#attributes' => array('class' => array('add-display')),
-      // Allow JavaScript to remove the 'Add ' prefix from the button label when
-      // placing the button in a "Add" dropdown menu.
-      '#process' => array_merge(array('views_ui_form_button_was_clicked'), element_info_property('submit', '#process', array())),
-      '#values' => array(t('Add !display', array('!display' => $label)), $label),
-    );
-  }
-
-  return $element;
-}
-
-function views_ui_get_default_ajax_message() {
-  return '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
-}
-
-/**
- * Submit handler to add a display to a view.
- */
-function views_ui_edit_form_submit_add_display($form, &$form_state) {
-  $view = $form_state['view'];
-
-  // Create the new display.
-  $parents = $form_state['triggering_element']['#parents'];
-  $display_type = array_pop($parents);
-  $display_id = $view->storage->addDisplay($display_type);
-  views_ui_cache_set($view);
-
-  // Redirect to the new display's edit page.
-  $form_state['redirect'] = 'admin/structure/views/view/' . $view->storage->name . '/edit/' . $display_id;
-}
-
-/**
- * Submit handler to duplicate a display for a view.
- */
-function views_ui_edit_form_submit_duplicate_display($form, &$form_state) {
-  $view = $form_state['view'];
-  $display_id = $form_state['display_id'];
-
-  // Create the new display.
-  $display = $view->storage->display[$display_id];
-  $new_display_id = $view->storage->addDisplay($display['display_plugin']);
-  $view->storage->display[$new_display_id] = $display;
-
-  // By setting the current display the changed marker will appear on the new
-  // display.
-  $view->current_display = $new_display_id;
-  views_ui_cache_set($view);
-
-  // Redirect to the new display's edit page.
-  $form_state['redirect'] = 'admin/structure/views/view/' . $view->storage->name . '/edit/' . $new_display_id;
-}
-
-/**
- * Submit handler to delete a display from a view.
- */
-function views_ui_edit_form_submit_delete_display($form, &$form_state) {
-  $view = $form_state['view'];
-  $display_id = $form_state['display_id'];
-
-  // Mark the display for deletion.
-  $view->storage->display[$display_id]['deleted'] = TRUE;
-  views_ui_cache_set($view);
-
-  // Redirect to the top-level edit page. The first remaining display will
-  // become the active display.
-  $form_state['redirect'] = 'admin/structure/views/view/' . $view->storage->name;
-}
-
-/**
- * Submit handler to add a restore a removed display to a view.
- */
-function views_ui_edit_form_submit_undo_delete_display($form, &$form_state) {
-  // Create the new display
-  $id = $form_state['display_id'];
-  $form_state['view']->storage->display[$id]['deleted'] = FALSE;
-
-  // Store in cache
-  views_ui_cache_set($form_state['view']);
-
-  // Redirect to the top-level edit page.
-  $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit/' . $id;
-}
-
-/**
- * Submit handler to enable a disabled display.
- */
-function views_ui_edit_form_submit_enable_display($form, &$form_state) {
-  $id = $form_state['display_id'];
-  // setOption doesn't work because this would might affect upper displays
-  $form_state['view']->displayHandlers[$id]->setOption('enabled', TRUE);
-
-  // Store in cache
-  views_ui_cache_set($form_state['view']);
-
-  // Redirect to the top-level edit page.
-  $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit/' . $id;
-}
-
-/**
- * Submit handler to disable display.
- */
-function views_ui_edit_form_submit_disable_display($form, &$form_state) {
-  $id = $form_state['display_id'];
-  $form_state['view']->displayHandlers[$id]->setOption('enabled', FALSE);
-
-  // Store in cache
-  views_ui_cache_set($form_state['view']);
-
-  // Redirect to the top-level edit page.
-  $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit/' . $id;
-}
-
-/**
- * Submit handler when Preview button is clicked.
- */
-function views_ui_edit_form_submit_preview($form, &$form_state) {
-  // Rebuild the form with a pristine $view object.
-  $form_state['build_info']['args'][0] = views_ui_cache_load($form_state['view']->storage->name);
-  $form_state['show_preview'] = TRUE;
-  $form_state['rebuild'] = TRUE;
-}
-
-/**
- * Submit handler for form buttons that do not complete a form workflow.
- *
- * The Edit View form is a multistep form workflow, but with state managed by
- * the CTools object cache rather than $form_state['rebuild']. Without this
- * submit handler, buttons that add or remove displays would redirect to the
- * destination parameter (e.g., when the Edit View form is linked to from a
- * contextual link). This handler can be added to buttons whose form submission
- * should not yet redirect to the destination.
- */
-function views_ui_edit_form_submit_delay_destination($form, &$form_state) {
-  $query = drupal_container()->get('request')->query;
-  // @todo: Revisit this when http://drupal.org/node/1668866 is in.
-  $destination = $query->get('destination');
-  if (isset($destination) && $form_state['redirect'] !== FALSE) {
-    if (!isset($form_state['redirect'])) {
-      $form_state['redirect'] = current_path();
-    }
-    if (is_string($form_state['redirect'])) {
-      $form_state['redirect'] = array($form_state['redirect']);
-    }
-    $options = isset($form_state['redirect'][1]) ? $form_state['redirect'][1] : array();
-    if (!isset($options['query']['destination'])) {
-      $options['query']['destination'] = $destination;
-    }
-    $form_state['redirect'][1] = $options;
-    $query->remove('destination');
-  }
-}
-
-/**
- * Adds tabs for navigating across Displays when editing a View.
- *
- * This function can be called from hook_menu_local_tasks_alter() to implement
- * these tabs as secondary local tasks, or it can be called from elsewhere if
- * having them as secondary local tasks isn't desired. The caller is responsible
- * for setting the active tab's #active property to TRUE.
- *
- * @param view $view
- *    The view which will be edited.
- * @param $display_id
- *    The display_id which is edited on the current request.
- */
-function views_ui_edit_page_display_tabs(ViewUI $view, $display_id = NULL) {
-  $tabs = array();
-
-  // Create a tab for each display.
-  uasort($view->storage->display, '_views_position_sort');
-  foreach ($view->storage->display as $id => $display) {
-    $tabs[$id] = array(
-      '#theme' => 'menu_local_task',
-      '#link' => array(
-        'title' => views_ui_get_display_label($view, $id),
-        'href' => 'admin/structure/views/view/' . $view->storage->name . '/edit/' . $id,
-        'localized_options' => array(),
-      ),
-    );
-    if (!empty($display['deleted'])) {
-      $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'views-display-deleted-link';
-    }
-    if (isset($display['display_options']['enabled']) && !$display['display_options']['enabled']) {
-      $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'views-display-disabled-link';
-    }
-  }
-
-  // If the default display isn't supposed to be shown, don't display its tab, unless it's the only display.
-  if ((!views_ui_show_default_display($view) && $display_id != 'default') && count($tabs) > 1) {
-    $tabs['default']['#access'] = FALSE;
-  }
-
-  // Mark the display tab as red to show validation errors.
-  $view->validate();
-  foreach ($view->storage->display as $id => $display) {
-    if (!empty($view->display_errors[$id])) {
-      // Always show the tab.
-      $tabs[$id]['#access'] = TRUE;
-      // Add a class to mark the error and a title to make a hover tip.
-      $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'error';
-      $tabs[$id]['#link']['localized_options']['attributes']['title'] = t('This display has one or more validation errors; please review it.');
-    }
-  }
-
-  return $tabs;
-}
-
-/**
- * Controls whether or not the default display should have its own tab on edit.
- */
-function views_ui_show_default_display(ViewUI $view) {
-  // Always show the default display for advanced users who prefer that mode.
-  $advanced_mode = config('views.settings')->get('ui.show.master_display');
-  // For other users, show the default display only if there are no others, and
-  // hide it if there's at least one "real" display.
-  $additional_displays = (count($view->displayHandlers) == 1);
-
-  return $advanced_mode || $additional_displays;
-}
-
-/**
- * Returns a renderable array representing the edit page for one display.
- */
-function views_ui_get_display_tab(ViewUI $view, $display_id) {
-  $build = array();
-  $display = $view->displayHandlers[$display_id];
-  // If the plugin doesn't exist, display an error message instead of an edit
-  // page.
-  if (empty($display)) {
-    $title = isset($display['display_title']) ? $display['display_title'] : t('Invalid');
-    // @TODO: Improved UX for the case where a plugin is missing.
-    $build['#markup'] = t("Error: Display @display refers to a plugin named '@plugin', but that plugin is not available.", array('@display' => $display['id'], '@plugin' => $display['display_plugin']));
-  }
-  // Build the content of the edit page.
-  else {
-    $build['details'] = views_ui_get_display_tab_details($view, $display->display);
-  }
-  // In AJAX context, views_ui_regenerate_tab() returns this outside of form
-  // context, so hook_form_views_ui_edit_form_alter() is insufficient.
-  drupal_alter('views_ui_display_tab', $build, $view, $display_id);
-  return $build;
-}
-
-/**
- * Helper function to get the display details section of the edit UI.
- *
- * @param $view
- * @param $display
- *
- * @return array
- *   A renderable page build array.
- */
-function views_ui_get_display_tab_details(ViewUI $view, $display) {
-  $display_title = views_ui_get_display_label($view, $display['id'], FALSE);
-  $build = array(
-    '#theme_wrappers' => array('container'),
-    '#attributes' => array('id' => 'edit-display-settings-details'),
-  );
-
-  // The following is for display purposes only. We need to determine if there is more than one button and wrap
-  // the buttons in a .ctools-dropbutton class if more than one is present.  Otherwise, we'll just wrap the
-  // actions in the .ctools-button class.
-  $is_display_deleted = !empty($display['deleted']);
-  // The master display cannot be cloned.
-  $is_default = $display['id'] == 'default';
-  // @todo: Figure out why getOption doesn't work here.
-  $is_enabled = $view->displayHandlers[$display['id']]->getOption('enabled');
-
-  if (!$is_display_deleted && !$is_default) {
-    $prefix = '<div class="ctools-no-js ctools-button ctools-dropbutton"><div class="ctools-link"><a href="#" class="ctools-twisty ctools-text">open</a></div><div class="ctools-content"><ul class="horizontal right actions">';
-    $suffix = '</ul></div></div>';
-    $item_element = 'li';
-  }
-  else {
-    $prefix = '<div class="ctools-button"><div class="ctools-content"><ul class="horizontal right actions">';
-    $suffix = '</ul></div></div>';
-    $item_element = 'li';
-  }
-
-  if ($display['id'] != 'default') {
-    $build['top']['#theme_wrappers'] = array('container');
-    $build['top']['#attributes']['id'] = 'edit-display-settings-top';
-    $build['top']['#attributes']['class'] = array('views-ui-display-tab-actions', 'views-ui-display-tab-bucket', 'clearfix');
-
-    // The Delete, Duplicate and Undo Delete buttons.
-    $build['top']['actions'] = array(
-      '#prefix' => $prefix,
-      '#suffix' => $suffix,
-    );
-
-    if (!$is_display_deleted) {
-      if (!$is_enabled) {
-        $build['top']['actions']['enable'] = array(
-          '#type' => 'submit',
-          '#value' => t('enable @display_title', array('@display_title' => $display_title)),
-          '#limit_validation_errors' => array(),
-          '#submit' => array('views_ui_edit_form_submit_enable_display', 'views_ui_edit_form_submit_delay_destination'),
-          '#prefix' => '<' . $item_element . ' class="enable">',
-          "#suffix" => '</' . $item_element . '>',
-        );
-      }
-      // Add a link to view the page.
-      elseif ($view->displayHandlers[$display['id']]->hasPath()) {
-        $path = $view->displayHandlers[$display['id']]->getPath();
-        if (strpos($path, '%') === FALSE) {
-          $build['top']['actions']['path'] = array(
-            '#type' => 'link',
-            '#title' => t('view @display', array('@display' => $display['display_title'])),
-            '#options' => array('alt' => array(t("Go to the real page for this display"))),
-            '#href' => $path,
-            '#prefix' => '<' . $item_element . ' class="view">',
-            "#suffix" => '</' . $item_element . '>',
-          );
-        }
-      }
-      if (!$is_default) {
-        $build['top']['actions']['duplicate'] = array(
-          '#type' => 'submit',
-          '#value' => t('clone @display_title', array('@display_title' => $display_title)),
-          '#limit_validation_errors' => array(),
-          '#submit' => array('views_ui_edit_form_submit_duplicate_display', 'views_ui_edit_form_submit_delay_destination'),
-          '#prefix' => '<' . $item_element . ' class="duplicate">',
-          "#suffix" => '</' . $item_element . '>',
-        );
-      }
-      // Always allow a display to be deleted.
-      $build['top']['actions']['delete'] = array(
-        '#type' => 'submit',
-        '#value' => t('delete @display_title', array('@display_title' => $display_title)),
-        '#limit_validation_errors' => array(),
-        '#submit' => array('views_ui_edit_form_submit_delete_display', 'views_ui_edit_form_submit_delay_destination'),
-        '#prefix' => '<' . $item_element . ' class="delete">',
-        "#suffix" => '</' . $item_element . '>',
-      );
-      if ($is_enabled) {
-        $build['top']['actions']['disable'] = array(
-          '#type' => 'submit',
-          '#value' => t('disable @display_title', array('@display_title' => $display_title)),
-          '#limit_validation_errors' => array(),
-          '#submit' => array('views_ui_edit_form_submit_disable_display', 'views_ui_edit_form_submit_delay_destination'),
-          '#prefix' => '<' . $item_element . ' class="disable">',
-          "#suffix" => '</' . $item_element . '>',
-        );
-      }
-    }
-    else {
-      $build['top']['actions']['undo_delete'] = array(
-        '#type' => 'submit',
-        '#value' => t('undo delete of @display_title', array('@display_title' => $display_title)),
-        '#limit_validation_errors' => array(),
-        '#submit' => array('views_ui_edit_form_submit_undo_delete_display', 'views_ui_edit_form_submit_delay_destination'),
-        '#prefix' => '<' . $item_element . ' class="undo-delete">',
-        "#suffix" => '</' . $item_element . '>',
-      );
-    }
-
-    // The area above the three columns.
-    $build['top']['display_title'] = array(
-      '#theme' => 'views_ui_display_tab_setting',
-      '#description' => t('Display name'),
-      '#link' => $view->displayHandlers[$display['id']]->optionLink(check_plain($display_title), 'display_title'),
-    );
-  }
-
-  $build['columns'] = array();
-  $build['columns']['#theme_wrappers'] = array('container');
-  $build['columns']['#attributes'] = array('id' => 'edit-display-settings-main', 'class' => array('clearfix', 'views-display-columns'));
-
-  $build['columns']['first']['#theme_wrappers'] = array('container');
-  $build['columns']['first']['#attributes'] = array('class' => array('views-display-column', 'first'));
-
-  $build['columns']['second']['#theme_wrappers'] = array('container');
-  $build['columns']['second']['#attributes'] = array('class' => array('views-display-column', 'second'));
-
-  $build['columns']['second']['settings'] = array();
-  $build['columns']['second']['header'] = array();
-  $build['columns']['second']['footer'] = array();
-  $build['columns']['second']['pager'] = array();
-
-  // The third column buckets are wrapped in a fieldset.
-  $build['columns']['third'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Advanced'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#theme_wrappers' => array('fieldset', 'container'),
-    '#attributes' => array(
-      'class' => array(
-        'views-display-column',
-        'third',
-      ),
-    ),
-  );
-
-  // Collapse the fieldset by default.
-  if (config('views.settings')->get('ui.show.advanced_column')) {
-    $build['columns']['third']['#collapsed'] = FALSE;
-  }
-
-  // Each option (e.g. title, access, display as grid/table/list) fits into one
-  // of several "buckets," or boxes (Format, Fields, Sort, and so on).
-  $buckets = array();
-
-  // Fetch options from the display plugin, with a list of buckets they go into.
-  $options = array();
-  $view->displayHandlers[$display['id']]->optionsSummary($buckets, $options);
-
-  // Place each option into its bucket.
-  foreach ($options as $id => $option) {
-    // Each option self-identifies as belonging in a particular bucket.
-    $buckets[$option['category']]['build'][$id] = views_ui_edit_form_get_build_from_option($id, $option, $view, $display);
-  }
-
-  // Place each bucket into the proper column.
-  foreach ($buckets as $id => $bucket) {
-    // Let buckets identify themselves as belonging in a column.
-    if (isset($bucket['column']) && isset($build['columns'][$bucket['column']])) {
-      $column = $bucket['column'];
-    }
-    // If a bucket doesn't pick one of our predefined columns to belong to, put
-    // it in the last one.
-    else {
-      $column = 'third';
-    }
-    if (isset($bucket['build']) && is_array($bucket['build'])) {
-      $build['columns'][$column][$id] = $bucket['build'];
-      $build['columns'][$column][$id]['#theme_wrappers'][] = 'views_ui_display_tab_bucket';
-      $build['columns'][$column][$id]['#title'] = !empty($bucket['title']) ? $bucket['title'] : '';
-      $build['columns'][$column][$id]['#name'] = !empty($bucket['title']) ? $bucket['title'] : $id;
-    }
-  }
-
-  $build['columns']['first']['fields'] = views_ui_edit_form_get_bucket('field', $view, $display);
-  $build['columns']['first']['filters'] = views_ui_edit_form_get_bucket('filter', $view, $display);
-  $build['columns']['first']['sorts'] = views_ui_edit_form_get_bucket('sort', $view, $display);
-  $build['columns']['second']['header'] = views_ui_edit_form_get_bucket('header', $view, $display);
-  $build['columns']['second']['footer'] = views_ui_edit_form_get_bucket('footer', $view, $display);
-  $build['columns']['third']['arguments'] = views_ui_edit_form_get_bucket('argument', $view, $display);
-  $build['columns']['third']['relationships'] = views_ui_edit_form_get_bucket('relationship', $view, $display);
-  $build['columns']['third']['empty'] = views_ui_edit_form_get_bucket('empty', $view, $display);
-
-  return $build;
-}
-
-/**
- * Build a renderable array representing one option on the edit form.
- *
- * This function might be more logical as a method on an object, if a suitable
- * object emerges out of refactoring.
- */
-function views_ui_edit_form_get_build_from_option($id, $option, ViewUI $view, $display) {
-  $option_build = array();
-  $option_build['#theme'] = 'views_ui_display_tab_setting';
-
-  $option_build['#description'] = $option['title'];
-
-  $option_build['#link'] = $view->displayHandlers[$display['id']]->optionLink($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
-
-  $option_build['#links'] = array();
-  if (!empty($option['links']) && is_array($option['links'])) {
-    foreach ($option['links'] as $link_id => $link_value) {
-      $option_build['#settings_links'][] = $view->displayHandlers[$display['id']]->optionLink($option['setting'], $link_id, 'views-button-configure', $link_value);
-    }
-  }
-
-  if (!empty($view->displayHandlers[$display['id']]->options['defaults'][$id])) {
-    $display_id = 'default';
-    $option_build['#defaulted'] = TRUE;
-  }
-  else {
-    $display_id = $display['id'];
-    if (!$view->displayHandlers[$display['id']]->isDefaultDisplay()) {
-      if ($view->displayHandlers[$display['id']]->defaultableSections($id)) {
-        $option_build['#overridden'] = TRUE;
-      }
-    }
-  }
-  $option_build['#attributes']['class'][] = drupal_clean_css_identifier($display_id . '-' . $id);
-  return $option_build;
-}
-
-function template_preprocess_views_ui_display_tab_setting(&$variables) {
-  static $zebra = 0;
-  $variables['zebra'] = ($zebra % 2 === 0 ? 'odd' : 'even');
-  $zebra++;
-
-  // Put the main link to the left side
-  array_unshift($variables['settings_links'], $variables['link']);
-  $variables['settings_links'] = implode('<span class="label">&nbsp;|&nbsp;</span>', $variables['settings_links']);
-
-  if (!empty($variables['defaulted'])) {
-    $variables['attributes']['class'][] = 'defaulted';
-  }
-  if (!empty($variables['overridden'])) {
-    $variables['attributes']['class'][] = 'overridden';
-    $variables['attributes_array']['title'][] = t('Overridden');
-  }
-
-  // Append a colon to the description, if requested.
-  if ($variables['description'] && $variables['description_separator']) {
-    $variables['description'] .= t(':');
-  }
-}
-
-function template_preprocess_views_ui_display_tab_bucket(&$variables) {
-  $element = $variables['element'];
-
-  if (!empty($element['#name'])) {
-    $variables['attributes']['class'][] = drupal_html_class($element['#name']);
-  }
-  if (!empty($element['#overridden'])) {
-    $variables['attributes']['class'][] = 'overridden';
-    $variables['attributes_array']['title'][] = t('Overridden');
-  }
-
-  $variables['content'] = $element['#children'];
-  $variables['title'] = $element['#title'];
-  $variables['actions'] = !empty($element['#actions']) ? $element['#actions'] : '';
-}
-
-function template_preprocess_views_ui_display_tab_column(&$variables) {
-  $element = $variables['element'];
-
-  $variables['content'] = $element['#children'];
-  $variables['column'] = $element['#column'];
-}
-
-/**
- * Move form elements into fieldsets for presentation purposes.
- *
- * Many views forms use #tree = TRUE to keep their values in a hierarchy for
- * easier storage. Moving the form elements into fieldsets during form building
- * would break up that hierarchy. Therefore, we wait until the pre_render stage,
- * where any changes we make affect presentation only and aren't reflected in
- * $form_state['values'].
- */
-function views_ui_pre_render_add_fieldset_markup($form) {
-  foreach (element_children($form) as $key) {
-    $element = $form[$key];
-    // In our form builder functions, we added an arbitrary #fieldset property
-    // to any element that belongs in a fieldset. If this form element has that
-    // property, move it into its fieldset.
-    if (isset($element['#fieldset']) && isset($form[$element['#fieldset']])) {
-      $form[$element['#fieldset']][$key] = $element;
-      // Remove the original element this duplicates.
-      unset($form[$key]);
-    }
-  }
-
-  return $form;
-}
-
-/**
- * Flattens the structure of an element containing the #flatten property.
- *
- * If a form element has #flatten = TRUE, then all of it's children
- * get moved to the same level as the element itself.
- * So $form['to_be_flattened'][$key] becomes $form[$key], and
- * $form['to_be_flattened'] gets unset.
- */
-function views_ui_pre_render_flatten_data($form) {
-  foreach (element_children($form) as $key) {
-    $element = $form[$key];
-    if (!empty($element['#flatten'])) {
-      foreach (element_children($element) as $child_key) {
-        $form[$child_key] = $form[$key][$child_key];
-      }
-      // All done, remove the now-empty parent.
-      unset($form[$key]);
-    }
-  }
-
-  return $form;
-}
-
-/**
- * Moves argument options into their place.
- *
- * When configuring the default argument behavior, almost each of the radio
- * buttons has its own fieldset shown bellow it when the radio button is
- * clicked. That fieldset is created through a custom form process callback.
- * Each element that has #argument_option defined and pointing to a default
- * behavior gets moved to the appropriate fieldset.
- * So if #argument_option is specified as 'default', the element is moved
- * to the 'default_options' fieldset.
- */
-function views_ui_pre_render_move_argument_options($form) {
+function views_ui_pre_render_flatten_data($form) {
   foreach (element_children($form) as $key) {
     $element = $form[$key];
-    if (!empty($element['#argument_option'])) {
-      $container_name = $element['#argument_option'] . '_options';
-      if (isset($form['no_argument']['default_action'][$container_name])) {
-        $form['no_argument']['default_action'][$container_name][$key] = $element;
-      }
-      // Remove the original element this duplicates.
-      unset($form[$key]);
-    }
-  }
-  return $form;
-}
-
-/**
- * Custom form radios process function.
- *
- * Roll out a single radios element to a list of radios,
- * using the options array as index.
- * While doing that, create a container element underneath each option, which
- * contains the settings related to that option.
- *
- * @see form_process_radios()
- */
-function views_ui_process_container_radios($element) {
-  if (count($element['#options']) > 0) {
-    foreach ($element['#options'] as $key => $choice) {
-      $element += array($key => array());
-      // Generate the parents as the autogenerator does, so we will have a
-      // unique id for each radio button.
-      $parents_for_id = array_merge($element['#parents'], array($key));
-
-      $element[$key] += array(
-        '#type' => 'radio',
-        '#title' => $choice,
-        // The key is sanitized in drupal_attributes() during output from the
-        // theme function.
-        '#return_value' => $key,
-        '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL,
-        '#attributes' => $element['#attributes'],
-        '#parents' => $element['#parents'],
-        '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
-        '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
-      );
-      $element[$key . '_options'] = array(
-        '#type' => 'container',
-        '#attributes' => array('class' => array('views-admin-dependent')),
-      );
-    }
-  }
-  return $element;
-}
-
-/**
- * Import a view from cut & paste.
- */
-function views_ui_import_page($form, &$form_state) {
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('View name'),
-    '#description' => t('Enter the name to use for this view if it is different from the source view. Leave blank to use the name of the view.'),
-  );
-
-  $form['name_override'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Replace an existing view if one exists with the same name'),
-  );
-
-  $form['bypass_validation'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Bypass view validation'),
-    '#description' => t('Bypass the validation of plugins and handlers when importing this view.'),
-  );
-
-  $form['view'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Paste view code here'),
-    '#required' => TRUE,
-  );
-
-  $form['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Import'),
-    '#submit' => array('views_ui_import_submit'),
-    '#validate' => array('views_ui_import_validate'),
-  );
-  return $form;
-}
-
-/**
- * Validate handler to import a view.
- */
-function views_ui_import_validate($form, &$form_state) {
-  $view = '';
-  // Be forgiving if someone pastes views code that starts with '<?php'.
-  if (substr($form_state['values']['view'], 0, 5) == '<?php') {
-    $form_state['values']['view'] = substr($form_state['values']['view'], 5);
-  }
-  ob_start();
-  eval($form_state['values']['view']);
-  ob_end_clean();
-
-  if (!is_object($view)) {
-    return form_error($form['view'], t('Unable to interpret view code.'));
-  }
-
-  if (empty($view->api_version) || $view->api_version < 2) {
-    form_error($form['view'], t('That view is not compatible with this version of Views.
-      If you have a view from views1 you have to go to a drupal6 installation and import it there.'));
-  }
-  elseif (version_compare($view->api_version, views_api_version(), '>')) {
-    form_error($form['view'], t('That view is created for the version @import_version of views, but you only have @api_version', array(
-      '@import_version' => $view->api_version,
-      '@api_version' => views_api_version())));
-  }
-
-  // View name must be alphanumeric or underscores, no other punctuation.
-  if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) {
-    form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
-  }
-
-  if ($form_state['values']['name']) {
-    $view->storage->name = $form_state['values']['name'];
-  }
-
-  $test = views_get_view($view->storage->name);
-  if (!$form_state['values']['name_override']) {
-    if ($test && $test->type != t('Default')) {
-      form_set_error('', t('A view by that name already exists; please choose a different name'));
-    }
-  }
-  else {
-    if ($test->vid) {
-      $view->vid = $test->vid;
-    }
-  }
-
-  // Make sure base table gets set properly if it got moved.
-  $view->update();
-
-  $view->initDisplay();
-
-  $broken = FALSE;
-
-  // Bypass the validation of view pluigns/handlers if option is checked.
-  if (!$form_state['values']['bypass_validation']) {
-    // Make sure that all plugins and handlers needed by this view actually exist.
-    foreach ($view->displayHandlers as $id => $display) {
-      if (empty($display) || !empty($display->broken)) {
-        drupal_set_message(t('Display plugin @plugin is not available.', array('@plugin' => $display->getPluginId())), 'error');
-        $broken = TRUE;
-        continue;
-      }
-
-      $style = $display->getOption('style');
-      $plugin = views_get_plugin('style', $style['type']);
-      if (!$plugin) {
-        drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $style['type'])), 'error');
-        $broken = TRUE;
-      }
-      elseif ($plugin->usesRowPlugin()) {
-        $row = $display->getOption('row');
-        $plugin = views_get_plugin('row', $row['type']);
-        if (!$plugin) {
-          drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $row['type'])), 'error');
-          $broken = TRUE;
-        }
-      }
-
-      foreach (ViewExecutable::viewsHandlerTypes() as $type => $info) {
-        $handlers = $display->getHandlers($type);
-        if ($handlers) {
-          foreach ($handlers as $id => $handler) {
-            if ($handler->broken()) {
-              drupal_set_message(t('@type handler @table.@field is not available.', array(
-                '@type' => $info['stitle'],
-                '@table' => $handler->table,
-                '@field' => $handler->field,
-              )), 'error');
-              $broken = TRUE;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  if ($broken) {
-    form_set_error('', t('Unable to import view.'));
-  }
-
-  $form_state['view'] = &$view;
-}
-
-/**
- * Submit handler for view import.
- */
-function views_ui_import_submit($form, &$form_state) {
-  // Store in cache and then go to edit.
-  views_ui_cache_set($form_state['view']);
-  $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit';
-}
-
-/**
- * Validate that a view is complete and whole.
- */
-function views_ui_edit_view_form_validate($form, &$form_state) {
-  // Do not validate cancel or delete or revert.
-  if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) {
-    return;
-  }
-
-  $errors = $form_state['view']->validate();
-  if ($errors !== TRUE) {
-    foreach ($errors as $error) {
-      form_set_error('', $error);
-    }
-  }
-}
-
-/**
- * Submit handler for the edit view form.
- */
-function views_ui_edit_view_form_submit($form, &$form_state) {
-  // Go through and remove displayed scheduled for removal.
-  foreach ($form_state['view']->storage->display as $id => $display) {
-    if (!empty($display['deleted'])) {
-      unset($form_state['view']->displayHandlers[$id]);
-      unset($form_state['view']->storage->display[$id]);
-    }
-  }
-  // Rename display ids if needed.
-  foreach ($form_state['view']->displayHandlers as $id => $display) {
-    if (!empty($display->display['new_id'])) {
-      $form_state['view']->displayHandlers[$id]['id'] = $display['new_id'];
-      // Redirect the user to the renamed display to be sure that the page itself exists and doesn't throw errors.
-      $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit/' . $display['new_id'];
-    }
-  }
-
-  // Direct the user to the right url, if the path of the display has changed.
-  $query = drupal_container()->get('request')->query;
-  // @todo: Revisit this when http://drupal.org/node/1668866 is in.
-  $destination = $query->get('destination');
-  if (!empty($destination)) {
-    // Find out the first display which has a changed path and redirect to this url.
-    $old_view = views_get_view($form_state['view']->storage->name);
-    foreach ($old_view->displayHandlers as $id => $display) {
-      // Only check for displays with a path.
-      if (!isset($display->display['display_options']['path'])) {
-        continue;
-      }
-      $old_path = $display->display['display_options']['path'];
-      if (($display->display['display_plugin'] == 'page') && ($old_path == $destination) && ($old_path != $form_state['view']->display[$id]->display['display_options']['path'])) {
-        $destination = $form_state['view']->displayHandlers[$id]->display['display_options']['path'];
-        $query->remove('destination');
-      }
-    }
-    $form_state['redirect'] = $destination;
-  }
-
-  $form_state['view']->save();
-  drupal_set_message(t('The view %name has been saved.', array('%name' => $form_state['view']->storage->getHumanName())));
-
-  // Remove this view from cache so we can edit it properly.
-  views_temp_store()->delete($form_state['view']->storage->name);
-}
-
-/**
- * Submit handler for the edit view form.
- */
-function views_ui_edit_view_form_cancel($form, &$form_state) {
-  // Remove this view from cache so edits will be lost.
-  views_temp_store()->delete($form_state['view']->storage->name);
-  if (empty($form['view']->vid)) {
-    // I seem to have to drupal_goto here because I can't get fapi to
-    // honor the redirect target. Not sure what I screwed up here.
-    drupal_goto('admin/structure/views');
-  }
-}
-
-function views_ui_edit_view_form_delete($form, &$form_state) {
-  $request = drupal_container()->get('request')->request;
-  // @todo: Revisit this when http://drupal.org/node/1668866 is in.
-  if ($request->get('destination') !== NULL) {
-    $request->remove('destination');
-  }
-  // Redirect to the delete confirm page
-  $form_state['redirect'] = array('admin/structure/views/view/' . $form_state['view']->storage->name . '/delete', array('query' => drupal_get_destination() + array('cancel' => 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit')));
-}
-
-/**
- * Add information about a section to a display.
- */
-function views_ui_edit_form_get_bucket($type, ViewUI $view, $display) {
-  $build = array(
-    '#theme_wrappers' => array('views_ui_display_tab_bucket'),
-  );
-  $types = ViewExecutable::viewsHandlerTypes();
-
-  $build['#overridden'] = FALSE;
-  $build['#defaulted'] = FALSE;
-
-  $build['#name'] = $build['#title'] = $types[$type]['title'];
-
-  // Different types now have different rearrange forms, so we use this switch
-  // to get the right one.
-  switch ($type) {
-    case 'filter':
-      $rearrange_url = "admin/structure/views/nojs/rearrange-$type/{$view->storage->name}/{$display['id']}/$type";
-      $rearrange_text = t('And/Or, Rearrange');
-      // TODO: Add another class to have another symbol for filter rearrange.
-      $class = 'icon compact rearrange';
-      break;
-    case 'field':
-      // Fetch the style plugin info so we know whether to list fields or not.
-      $style = $view->displayHandlers[$display['id']]->getOption('style');
-      $style_plugin = $view->displayHandlers[$display['id']]->getPlugin('style', $style['type']);
-      $uses_fields = $style_plugin && $style_plugin->usesFields();
-      if (!$uses_fields) {
-        $build['fields'][] = array(
-          '#markup' => t('The selected style or row format does not utilize fields.'),
-          '#theme_wrappers' => array('views_container'),
-          '#attributes' => array('class' => array('views-display-setting')),
-        );
-        return $build;
-      }
-
-    default:
-      $rearrange_url = "admin/structure/views/nojs/rearrange/{$view->storage->name}/{$display['id']}/$type";
-      $rearrange_text = t('Rearrange');
-      $class = 'icon compact rearrange';
-  }
-
-  // Create an array of actions to pass to theme_links
-  $actions = array();
-  $count_handlers = count($view->displayHandlers[$display['id']]->getHandlers($type));
-  $actions['add'] = array(
-    'title' => t('Add'),
-    'href' => "admin/structure/views/nojs/add-item/{$view->storage->name}/{$display['id']}/$type",
-    'attributes' => array('class' => array('icon compact add', 'views-ajax-link'), 'title' => t('Add'), 'id' => 'views-add-' . $type),
-    'html' => TRUE,
-  );
-  if ($count_handlers > 0) {
-    $actions['rearrange'] = array(
-      'title' => $rearrange_text,
-      'href' => $rearrange_url,
-      'attributes' => array('class' => array($class, 'views-ajax-link'), 'title' => t('Rearrange'), 'id' => 'views-rearrange-' . $type),
-      'html' => TRUE,
-    );
-  }
-
-  // Render the array of links
-  $build['#actions'] = theme('links__ctools_dropbutton',
-    array(
-      'links' => $actions,
-      'attributes' => array(
-        'class' => array('inline', 'links', 'actions', 'horizontal', 'right')
-      ),
-      'class' => array('views-ui-settings-bucket-operations'),
-    )
-  );
-
-  if (!$view->displayHandlers[$display['id']]->isDefaultDisplay()) {
-    if (!$view->displayHandlers[$display['id']]->isDefaulted($types[$type]['plural'])) {
-      $build['#overridden'] = TRUE;
-    }
-    else {
-      $build['#defaulted'] = TRUE;
-    }
-  }
-
-  // If there's an options form for the bucket, link to it.
-  if (!empty($types[$type]['options'])) {
-    $build['#title'] = l($build['#title'], "admin/structure/views/nojs/config-type/{$view->storage->name}/{$display['id']}/$type", array('attributes' => array('class' => array('views-ajax-link'), 'id' => 'views-title-' . $type)));
-  }
-
-  static $relationships = NULL;
-  if (!isset($relationships)) {
-    // Get relationship labels
-    $relationships = array();
-    foreach ($view->displayHandlers[$display['id']]->getHandlers('relationship') as $id => $handler) {
-      $relationships[$id] = $handler->label();
-    }
-  }
-
-  // Filters can now be grouped so we do a little bit extra:
-  $groups = array();
-  $grouping = FALSE;
-  if ($type == 'filter') {
-    $group_info = $view->display_handler->getOption('filter_groups');
-    // If there is only one group but it is using the "OR" filter, we still
-    // treat it as a group for display purposes, since we want to display the
-    // "OR" label next to items within the group.
-    if (!empty($group_info['groups']) && (count($group_info['groups']) > 1 || current($group_info['groups']) == 'OR')) {
-      $grouping = TRUE;
-      $groups = array(0 => array());
-    }
-  }
-
-  $build['fields'] = array();
-
-  foreach ($view->displayHandlers[$display['id']]->getOption($types[$type]['plural']) as $id => $field) {
-    // Build the option link for this handler ("Node: ID = article").
-    $build['fields'][$id] = array();
-    $build['fields'][$id]['#theme'] = 'views_ui_display_tab_setting';
-
-    $handler = $view->displayHandlers[$display['id']]->getHandler($type, $id);
-    if (empty($handler)) {
-      $build['fields'][$id]['#class'][] = 'broken';
-      $field_name = t('Broken/missing handler: @table > @field', array('@table' => $field['table'], '@field' => $field['field']));
-      $build['fields'][$id]['#link'] = l($field_name, "admin/structure/views/nojs/config-item/{$view->storage->name}/{$display['id']}/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
-      continue;
-    }
-
-    $field_name = check_plain($handler->adminLabel(TRUE));
-    if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
-      $field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name;
-    }
-
-    $description = filter_xss_admin($handler->adminSummary());
-    $link_text = $field_name . (empty($description) ? '' : " ($description)");
-    $link_attributes = array('class' => array('views-ajax-link'));
-    if (!empty($field['exclude'])) {
-      $link_attributes['class'][] = 'views-field-excluded';
-    }
-    $build['fields'][$id]['#link'] = l($link_text, "admin/structure/views/nojs/config-item/{$view->storage->name}/{$display['id']}/$type/$id", array('attributes' => $link_attributes, 'html' => TRUE));
-    $build['fields'][$id]['#class'][] = drupal_clean_css_identifier($display['id']. '-' . $type . '-' . $id);
-
-    if ($view->displayHandlers[$display['id']]->useGroupBy() && $handler->usesGroupBy()) {
-      $build['fields'][$id]['#settings_links'][] = l('<span class="label">' . t('Aggregation settings') . '</span>', "admin/structure/views/nojs/config-item-group/{$view->storage->name}/{$display['id']}/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Aggregation settings')), 'html' => TRUE));
-    }
-
-    if ($handler->hasExtraOptions()) {
-      $build['fields'][$id]['#settings_links'][] = l('<span class="label">' . t('Settings') . '</span>', "admin/structure/views/nojs/config-item-extra/{$view->storage->name}/{$display['id']}/$type/$id", array('attributes' => array('class' => array('views-button-configure', 'views-ajax-link'), 'title' => t('Settings')), 'html' => TRUE));
-    }
-
-    if ($grouping) {
-      $gid = $handler->options['group'];
-
-      // Show in default group if the group does not exist.
-      if (empty($group_info['groups'][$gid])) {
-        $gid = 0;
-      }
-      $groups[$gid][] = $id;
-    }
-  }
-
-  // If using grouping, re-order fields so that they show up properly in the list.
-  if ($type == 'filter' && $grouping) {
-    $store = $build['fields'];
-    $build['fields'] = array();
-    foreach ($groups as $gid => $contents) {
-      // Display an operator between each group.
-      if (!empty($build['fields'])) {
-        $build['fields'][] = array(
-          '#theme' => 'views_ui_display_tab_setting',
-          '#class' => array('views-group-text'),
-          '#link' => ($group_info['operator'] == 'OR' ? t('OR') : t('AND')),
-        );
-      }
-      // Display an operator between each pair of filters within the group.
-      $keys = array_keys($contents);
-      $last = end($keys);
-      foreach ($contents as $key => $pid) {
-        if ($key != $last) {
-          $store[$pid]['#link'] .= '&nbsp;&nbsp;' . ($group_info['groups'][$gid] == 'OR' ? t('OR') : t('AND'));
-        }
-        $build['fields'][$pid] = $store[$pid];
-      }
-    }
-  }
-
-  return $build;
-}
-
-/**
- * Regenerate the current tab for AJAX updates.
- */
-function views_ui_regenerate_tab(ViewUI $view, &$output, $display_id) {
-  if (!$view->setDisplay('default')) {
-    return;
+    if (!empty($element['#flatten'])) {
+      foreach (element_children($element) as $child_key) {
+        $form[$child_key] = $form[$key][$child_key];
+      }
+      // All done, remove the now-empty parent.
+      unset($form[$key]);
+    }
   }
 
-  // Regenerate the main display area.
-  $build = views_ui_get_display_tab($view, $display_id);
-  views_ui_add_microweights($build);
-  $output[] = ajax_command_html('#views-tab-' . $display_id, drupal_render($build));
-
-  // Regenerate the top area so changes to display names and order will appear.
-  $build = views_ui_render_display_top($view, $display_id);
-  views_ui_add_microweights($build);
-  $output[] = ajax_command_replace('#views-display-top', drupal_render($build));
+  return $form;
 }
 
 /**
- * Recursively adds microweights to a render array, similar to what form_builder() does for forms.
+ * Moves argument options into their place.
  *
- * @todo Submit a core patch to fix drupal_render() to do this, so that all
- *   render arrays automatically preserve array insertion order, as forms do.
+ * When configuring the default argument behavior, almost each of the radio
+ * buttons has its own fieldset shown bellow it when the radio button is
+ * clicked. That fieldset is created through a custom form process callback.
+ * Each element that has #argument_option defined and pointing to a default
+ * behavior gets moved to the appropriate fieldset.
+ * So if #argument_option is specified as 'default', the element is moved
+ * to the 'default_options' fieldset.
  */
-function views_ui_add_microweights(&$build) {
-  $count = 0;
-  foreach (element_children($build) as $key) {
-    if (!isset($build[$key]['#weight'])) {
-      $build[$key]['#weight'] = $count/1000;
+function views_ui_pre_render_move_argument_options($form) {
+  foreach (element_children($form) as $key) {
+    $element = $form[$key];
+    if (!empty($element['#argument_option'])) {
+      $container_name = $element['#argument_option'] . '_options';
+      if (isset($form['no_argument']['default_action'][$container_name])) {
+        $form['no_argument']['default_action'][$container_name][$key] = $element;
+      }
+      // Remove the original element this duplicates.
+      unset($form[$key]);
     }
-    views_ui_add_microweights($build[$key]);
-    $count++;
   }
+  return $form;
 }
 
 /**
- * Provide a standard set of Apply/Cancel/OK buttons for the forms. Also provide
- * a hidden op operator because the forms plugin doesn't seem to properly
- * provide which button was clicked.
- *
- * TODO: Is the hidden op operator still here somewhere, or is that part of the
- * docblock outdated?
+ * Validate that a view is complete and whole.
  */
-function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) {
-  $form['buttons'] = array(
-    '#prefix' => '<div class="clearfix"><div class="form-buttons">',
-    '#suffix' => '</div></div>',
-  );
-
-  if (empty($name)) {
-    $name = t('Apply');
-    $view = $form_state['view'];
-    if (!empty($view->stack) && count($view->stack) > 1) {
-      $name = t('Apply and continue');
-    }
-    $names = array(t('Apply'), t('Apply and continue'));
-  }
-
-  // Forms that are purely informational set an ok_button flag, so we know not
-  // to create an "Apply" button for them.
-  if (empty($form_state['ok_button'])) {
-    $form['buttons']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => $name,
-      // The regular submit handler ($form_id . '_submit') does not apply if
-      // we're updating the default display. It does apply if we're updating
-      // the current display. Since we have no way of knowing at this point
-      // which display the user wants to update, views_ui_standard_submit will
-      // take care of running the regular submit handler as appropriate.
-      '#submit' => array('views_ui_standard_submit'),
-    );
-    // Form API button click detection requires the button's #value to be the
-    // same between the form build of the initial page request, and the initial
-    // form build of the request processing the form submission. Ideally, the
-    // button's #value shouldn't change until the form rebuild step. However,
-    // views_ui_ajax_form() implements a different multistep form workflow than
-    // the Form API does, and adjusts $view->stack prior to form processing, so
-    // we compensate by extending button click detection code to support any of
-    // the possible button labels.
-    if (isset($names)) {
-      $form['buttons']['submit']['#values'] = $names;
-      $form['buttons']['submit']['#process'] = array_merge(array('views_ui_form_button_was_clicked'), element_info_property($form['buttons']['submit']['#type'], '#process', array()));
-    }
-    // If a validation handler exists for the form, assign it to this button.
-    if (function_exists($form_id . '_validate')) {
-      $form['buttons']['submit']['#validate'][] = $form_id . '_validate';
-    }
+function views_ui_edit_view_form_validate($form, &$form_state) {
+  // Do not validate cancel or delete or revert.
+  if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) {
+    return;
   }
 
-  // Create a "Cancel" button. For purely informational forms, label it "OK".
-  $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : 'views_ui_standard_cancel';
-  $form['buttons']['cancel'] = array(
-    '#type' => 'submit',
-    '#value' => empty($form_state['ok_button']) ? t('Cancel') : t('Ok'),
-    '#submit' => array($cancel_submit),
-    '#validate' => array(),
-  );
-
-  // Some forms specify a third button, with a name and submit handler.
-  if ($third) {
-    if (empty($submit)) {
-      $submit = 'third';
+  $errors = $form_state['view']->validate();
+  if ($errors !== TRUE) {
+    foreach ($errors as $error) {
+      form_set_error('', $error);
     }
-    $third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : 'views_ui_standard_cancel';
-
-    $form['buttons'][$submit] = array(
-      '#type' => 'submit',
-      '#value' => $third,
-      '#validate' => array(),
-      '#submit' => array($third_submit),
-    );
-  }
-
-  // Compatibility, to be removed later: // TODO: When is "later"?
-  // We used to set these items on the form, but now we want them on the $form_state:
-  if (isset($form['#title'])) {
-    $form_state['title'] = $form['#title'];
-  }
-  if (isset($form['#url'])) {
-    $form_state['url'] = $form['#url'];
-  }
-  if (isset($form['#section'])) {
-    $form_state['#section'] = $form['#section'];
-  }
-  // Finally, we never want these cached -- our object cache does that for us.
-  $form['#no_cache'] = TRUE;
-
-  // If this isn't an ajaxy form, then we want to set the title.
-  if (!empty($form['#title'])) {
-    drupal_set_title($form['#title']);
   }
 }
 
 /**
- * Basic submit handler applicable to all 'standard' forms.
- *
- * This submit handler determines whether the user wants the submitted changes
- * to apply to the default display or to the current display, and dispatches
- * control appropriately.
+ * Submit handler for the edit view form.
  */
-function views_ui_standard_submit($form, &$form_state) {
-  // Determine whether the values the user entered are intended to apply to
-  // the current display or the default display.
-
-  list($was_defaulted, $is_defaulted, $revert) = views_ui_standard_override_values($form, $form_state);
-
-  // Based on the user's choice in the display dropdown, determine which display
-  // these changes apply to.
-  if ($revert) {
-    // If it's revert just change the override and return.
-    $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
-    $display->optionsOverride($form, $form_state);
-
-    // Don't execute the normal submit handling but still store the changed view into cache.
-    views_ui_cache_set($form_state['view']);
-    return;
-  }
-  elseif ($was_defaulted === $is_defaulted) {
-    // We're not changing which display these form values apply to.
-    // Run the regular submit handler for this form.
-  }
-  elseif ($was_defaulted && !$is_defaulted) {
-    // We were using the default display's values, but we're now overriding
-    // the default display and saving values specific to this display.
-    $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
-    // optionsOverride toggles the override of this section.
-    $display->optionsOverride($form, $form_state);
-    $display->submitOptionsForm($form, $form_state);
-  }
-  elseif (!$was_defaulted && $is_defaulted) {
-    // We used to have an override for this display, but the user now wants
-    // to go back to the default display.
-    // Overwrite the default display with the current form values, and make
-    // the current display use the new default values.
-    $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
-    // optionsOverride toggles the override of this section.
-    $display->optionsOverride($form, $form_state);
-    $display->submitOptionsForm($form, $form_state);
+function views_ui_edit_view_form_submit($form, &$form_state) {
+  // Go through and remove displayed scheduled for removal.
+  foreach ($form_state['view']->storage->display as $id => $display) {
+    if (!empty($display['deleted'])) {
+      unset($form_state['view']->displayHandlers[$id]);
+      unset($form_state['view']->storage->display[$id]);
+    }
   }
+  // Rename display ids if needed.
+  foreach ($form_state['view']->displayHandlers as $id => $display) {
+    if (!empty($display->display['new_id'])) {
+      $new_id = $display->display['new_id'];
+      $form_state['view']->displayHandlers[$new_id] = $form_state['view']->displayHandlers[$id];
+      $form_state['view']->displayHandlers[$new_id]->display['id'] = $new_id;
 
-  $submit_handler = $form['#form_id'] . '_submit';
-  if (function_exists($submit_handler)) {
-    $submit_handler($form, $form_state);
+      $form_state['view']->storage->display[$new_id] = $form_state['view']->storage->display[$id];
+      unset($form_state['view']->storage->display[$id]);
+      // Redirect the user to the renamed display to be sure that the page itself exists and doesn't throw errors.
+      $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit/' . $new_id;
+    }
   }
-}
 
-/**
- * Return the was_defaulted, is_defaulted and revert state of a form.
- */
-function views_ui_standard_override_values($form, $form_state) {
-  // Make sure the dropdown exists in the first place.
-  if (isset($form_state['values']['override']['dropdown'])) {
-    // #default_value is used to determine whether it was the default value or not.
-    // So the available options are: $display, 'default' and 'default_revert', not 'defaults'.
-    $was_defaulted = ($form['override']['dropdown']['#default_value'] === 'defaults');
-    $is_defaulted = ($form_state['values']['override']['dropdown'] === 'default');
-    $revert = ($form_state['values']['override']['dropdown'] === 'default_revert');
-
-    if ($was_defaulted !== $is_defaulted && isset($form['#section'])) {
-      // We're changing which display these values apply to.
-      // Update the #section so it knows what to mark changed.
-      $form['#section'] = str_replace('default-', $form_state['display_id'] . '-', $form['#section']);
+  // Direct the user to the right url, if the path of the display has changed.
+  $query = drupal_container()->get('request')->query;
+  // @todo: Revisit this when http://drupal.org/node/1668866 is in.
+  $destination = $query->get('destination');
+  if (!empty($destination)) {
+    // Find out the first display which has a changed path and redirect to this url.
+    $old_view = views_get_view($form_state['view']->storage->name);
+    foreach ($old_view->displayHandlers as $id => $display) {
+      // Only check for displays with a path.
+      if (!isset($display->display['display_options']['path'])) {
+        continue;
+      }
+      $old_path = $display->display['display_options']['path'];
+      if (($display->display['display_plugin'] == 'page') && ($old_path == $destination) && ($old_path != $form_state['view']->display[$id]->display['display_options']['path'])) {
+        $destination = $form_state['view']->displayHandlers[$id]->display['display_options']['path'];
+        $query->remove('destination');
+      }
     }
+    $form_state['redirect'] = $destination;
   }
-  else {
-    // The user didn't get the dropdown for overriding the default display.
-    $was_defaulted = FALSE;
-    $is_defaulted = FALSE;
-    $revert = FALSE;
-  }
 
-  return array($was_defaulted, $is_defaulted, $revert);
+  $form_state['view']->save();
+  drupal_set_message(t('The view %name has been saved.', array('%name' => $form_state['view']->storage->getHumanName())));
+
+  // Remove this view from cache so we can edit it properly.
+  views_temp_store()->delete($form_state['view']->storage->name);
 }
 
 /**
- * Submit handler for cancel button
+ * Submit handler for the edit view form.
  */
-function views_ui_standard_cancel($form, &$form_state) {
-  if (!empty($form_state['view']->changed) && isset($form_state['view']->form_cache)) {
-    unset($form_state['view']->form_cache);
-    views_ui_cache_set($form_state['view']);
+function views_ui_edit_view_form_cancel($form, &$form_state) {
+  // Remove this view from cache so edits will be lost.
+  views_temp_store()->delete($form_state['view']->storage->name);
+  if (empty($form['view']->vid)) {
+    // I seem to have to drupal_goto here because I can't get fapi to
+    // honor the redirect target. Not sure what I screwed up here.
+    drupal_goto('admin/structure/views');
   }
-
-  $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit';
 }
 
 /**
@@ -2527,7 +737,7 @@ function views_ui_standard_display_dropdown(&$form, &$form_state, $section) {
   // Add the "2 of 3" progress indicator.
   // @TODO: Move this to a separate function if it's needed on any forms that
   // don't have the display dropdown.
-  if ($form_progress = views_ui_get_form_progress($view)) {
+  if ($form_progress = $view->getFormProgress()) {
     $form['progress']['#markup'] = '<div id="views-progress-indicator">' . t('@current of @total', array('@current' => $form_progress['current'], '@total' => $form_progress['total'])) . '</div>';
     $form['progress']['#weight'] = -1001;
   }
@@ -2575,38 +785,6 @@ function views_ui_standard_display_dropdown(&$form, &$form_state, $section) {
 
 }
 
-/**
- * Get the user's current progress through the form stack.
- *
- * @param $view
- *   The current view.
- *
- * @return
- *   FALSE if the user is not currently in a multiple-form stack. Otherwise,
- *   an associative array with the following keys:
- *   - current: The number of the current form on the stack.
- *   - total: The total number of forms originally on the stack.
- */
-function views_ui_get_form_progress(ViewUI $view) {
-  $progress = FALSE;
-  if (!empty($view->stack)) {
-    $stack = $view->stack;
-    // The forms on the stack have integer keys that don't change as the forms
-    // are completed, so we can see which ones are still left.
-    $keys = array_keys($view->stack);
-    // Add 1 to the array keys for the benefit of humans, who start counting
-    // from 1 and not 0.
-    $current = reset($keys) + 1;
-    $total = end($keys) + 1;
-    if ($total > 1) {
-      $progress = array();
-      $progress['current'] = $current;
-      $progress['total'] = $total;
-    }
-  }
-  return $progress;
-}
-
 // --------------------------------------------------------------------------
 // Various subforms for editing the pieces of a view.
 
@@ -2635,6 +813,7 @@ function views_ui_ajax_forms($key = NULL) {
     'reorder-displays' => array(
       'form_id' => 'views_ui_reorder_displays_form',
       'args' => array(),
+      'callback' => 'buildDisplaysReorderForm',
     ),
     'add-item' => array(
       'form_id' => 'views_ui_add_item_form',
@@ -2673,24 +852,6 @@ function views_ui_ajax_forms($key = NULL) {
   return $forms;
 }
 
-/**
- * Build a form identifier that we can use to see if one form
- * is the same as another. Since the arguments differ slightly
- * we do a lot of spiffy concatenation here.
- */
-function views_ui_build_identifier($key, ViewUI $view, $display_id, $args) {
-  $form = views_ui_ajax_forms($key);
-  // Automatically remove the single-form cache if it exists and
-  // does not match the key.
-  $identifier = implode('-', array($key, $view->storage->name, $display_id));
-
-  foreach ($form['args'] as $id) {
-    $arg = (!empty($args)) ? array_shift($args) : NULL;
-    $identifier .= '-' . $arg;
-  }
-  return $identifier;
-}
-
 /**
  * Build up a $form_state object suitable for use with drupal_build_form
  * based on known information about a form.
@@ -2706,6 +867,11 @@ function views_ui_build_form_state($js, $key, ViewUI $view, $display_id, $args)
     'display_id' => $display_id,
     'no_redirect' => TRUE,
   );
+  // If an method was specified, use that for the callback.
+  if (isset($form['callback'])) {
+    $form_state['build_info']['args'] = array();
+    $form_state['build_info']['callback'] = array($view, $form['callback']);
+  }
 
   foreach ($form['args'] as $id) {
     $form_state[$id] = (!empty($args)) ? array_shift($args) : NULL;
@@ -2729,48 +895,6 @@ function views_ui_build_form_url($form_state) {
   return $url;
 }
 
-/**
- * Add another form to the stack; clicking 'apply' will go to this form
- * rather than closing the ajax popup.
- */
-function views_ui_add_form_to_stack($key, ViewUI $view, $display_id, $args, $top = FALSE, $rebuild_keys = FALSE) {
-  if (empty($view->stack)) {
-    $view->stack = array();
-  }
-
-  $stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, &$view, $display_id, $args);
-  // If we're being asked to add this form to the bottom of the stack, no
-  // special logic is required. Our work is equally easy if we were asked to add
-  // to the top of the stack, but there's nothing in it yet.
-  if (!$top || empty($view->stack)) {
-    $view->stack[] = $stack;
-  }
-  // If we're adding to the top of an existing stack, we have to maintain the
-  // existing integer keys, so they can be used for the "2 of 3" progress
-  // indicator (which will now read "2 of 4").
-  else {
-    $keys = array_keys($view->stack);
-    $first = current($keys);
-    $last = end($keys);
-    for ($i = $last; $i >= $first; $i--) {
-      if (!isset($view->stack[$i])) {
-        continue;
-      }
-      // Move form number $i to the next position in the stack.
-      $view->stack[$i + 1] = $view->stack[$i];
-      unset($view->stack[$i]);
-    }
-    // Now that the previously $first slot is free, move the new form into it.
-    $view->stack[$first] = $stack;
-    ksort($view->stack);
-
-    // Start the keys from 0 again, if requested.
-    if ($rebuild_keys) {
-      $view->stack = array_values($view->stack);
-    }
-  }
-}
-
 /**
  * Generic entry point to handle forms.
  *
@@ -2793,7 +917,7 @@ function views_ui_ajax_form($js, $key, ViewUI $view, $display_id = '') {
   // it off; if it isn't, the user clicked somewhere else and the stack is
   // now irrelevant.
   if (!empty($view->stack)) {
-    $identifier = views_ui_build_identifier($key, $view, $display_id, $args);
+    $identifier = $view->buildIdentifier($key, $display_id, $args);
     // Retrieve the first form from the stack without changing the integer keys,
     // as they're being used for the "2 of 3" progress indicator.
     reset($view->stack);
@@ -2852,25 +976,13 @@ function views_ui_ajax_form($js, $key, ViewUI $view, $display_id = '') {
     // If this form was for view-wide changes, there's no need to regenerate
     // the display section of the form.
     if ($display_id !== '') {
-      views_ui_regenerate_tab($view, $output, $display_id);
+      $view->rebuildCurrentTab($output, $display_id);
     }
   }
 
   return $js ? array('#type' => 'ajax', '#commands' => $output) : $output;
 }
 
-/**
- * Submit handler to add a restore a removed display to a view.
- */
-function views_ui_remove_display_form_restore($form, &$form_state) {
-  // Create the new display
-  $id = $form_state['display_id'];
-  $form_state['view']->storage->display[$id]['deleted'] = FALSE;
-
-  // Store in cache
-  views_ui_cache_set($form_state['view']);
-}
-
 /**
  * Form constructor callback to display analysis information on a view
  */
@@ -2891,7 +1003,7 @@ function views_ui_analyze_view_form($form, &$form_state) {
 
   // Inform the standard button function that we want an OK button.
   $form_state['ok_button'] = TRUE;
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_analyze_view_form');
+  $view->getStandardButtons($form, $form_state, 'views_ui_analyze_view_form');
   return $form;
 }
 
@@ -2902,128 +1014,6 @@ function views_ui_analyze_view_form_submit($form, &$form_state) {
   $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->storage->name . '/edit';
 }
 
-/**
- * Form constructor callback to reorder displays on a view
- */
-function views_ui_reorder_displays_form($form, &$form_state) {
-  $view = &$form_state['view'];
-  $display_id = $form_state['display_id'];
-
-  $form['view'] = array('#type' => 'value', '#value' => $view);
-
-  $form['#tree'] = TRUE;
-
-  uasort($form_state['view']->storage->display, '_views_position_sort');
-  $count = count($view->storage->display);
-
-  foreach ($view->storage->display as $display) {
-    $form[$display['id']] = array(
-      'title'  => array('#markup' => $display['display_title']),
-      'weight' => array(
-        '#type' => 'weight',
-        '#value' => $display['position'],
-        '#delta' => $count,
-        '#title' => t('Weight for @display', array('@display' => $display['display_title'])),
-        '#title_display' => 'invisible',
-      ),
-      '#tree' => TRUE,
-      '#display' => $display,
-      'removed' => array(
-        '#type' => 'checkbox',
-        '#id' => 'display-removed-' . $display['id'],
-        '#attributes' => array('class' => array('views-remove-checkbox')),
-        '#default_value' => isset($display['deleted']),
-      ),
-    );
-
-    if (isset($display->deleted) && $display['deleted']) {
-      $form[$display['id']]['deleted'] = array('#type' => 'value', '#value' => TRUE);
-    }
-    if ($display['id'] === 'default') {
-      unset($form[$display['id']]['weight']);
-      unset($form[$display['id']]['removed']);
-    }
-
-  }
-
-  $form['#title'] = t('Displays Reorder');
-  $form['#section'] = 'reorder';
-
-  // Add javascript settings that will be added via $.extend for tabledragging
-  $form['#js']['tableDrag']['reorder-displays']['weight'][0] = array(
-    'target' => 'weight',
-    'source' => NULL,
-    'relationship' => 'sibling',
-    'action' => 'order',
-    'hidden' => TRUE,
-    'limit' => 0,
-  );
-
-  $form['#action'] = url('admin/structure/views/nojs/reorder-displays/' . $view->storage->name . '/' . $display_id);
-
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_reorder_displays_form');
-
-  return $form;
-}
-
-/**
- * Display position sorting function
- */
-function _views_position_sort($display1, $display2) {
-  if ($display1['position'] != $display2['position']) {
-    return $display1['position'] < $display2['position'] ? -1 : 1;
-  }
-
-  return 0;
-}
-
-/**
- * Submit handler for rearranging display form
- */
-function views_ui_reorder_displays_form_submit($form, &$form_state) {
-  foreach ($form_state['input'] as $display => $info) {
-    // add each value that is a field with a weight to our list, but only if
-    // it has had its 'removed' checkbox checked.
-    if (is_array($info) && isset($info['weight']) && empty($info['removed'])) {
-      $order[$display] = $info['weight'];
-    }
-  }
-  debug($form_state['input']);
-
-  // Sort the order array
-  asort($order);
-
-  // Fixing up positions
-  $position = 1;
-
-  foreach (array_keys($order) as $display) {
-    $order[$display] = $position++;
-  }
-
-  // Setting up position and removing deleted displays
-  $displays = $form_state['view']->storage->display;
-  foreach ($displays as $display_id => $display) {
-    // Don't touch the default !!!
-    if ($display_id === 'default') {
-      $form_state['view']->storage->display[$display_id]['position'] = 0;
-      continue;
-    }
-    if (isset($order[$display_id])) {
-      $form_state['view']->storage->display[$display_id]['position'] = $order[$display_id];
-    }
-    else {
-      $form_state['view']->storage->display[$display_id]['deleted'] = TRUE;
-    }
-  }
-
-  // Sorting back the display array as the position is not enough
-  uasort($form_state['view']->storage->display, '_views_position_sort');
-
-  // Store in cache
-  views_ui_cache_set($form_state['view']);
-  $form_state['redirect'] = array('admin/structure/views/view/' . $form_state['view']->storage->name . '/edit', array('fragment' => 'views-tab-default'));
-}
-
 /**
  * Turn the reorder form into a proper table
  */
@@ -3115,7 +1105,7 @@ function views_ui_edit_details_form($form, &$form_state) {
     '#default_value' => $view->storage->description,
   );
 
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form');
+  $view->getStandardButtons($form, $form_state, 'views_ui_edit_details_form');
   return $form;
 }
 
@@ -3171,7 +1161,7 @@ function views_ui_edit_display_form($form, &$form_state) {
     $name = $form_state['update_name'];
   }
 
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_display_form', $name);
+  $view->getStandardButtons($form, $form_state, 'views_ui_edit_display_form', $name);
   return $form;
 }
 
@@ -3216,7 +1206,7 @@ function views_ui_config_type_form($form, &$form_state) {
   $display_id = $form_state['display_id'];
   $type = $form_state['type'];
 
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   if (!$view->setDisplay($display_id)) {
     views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
   }
@@ -3240,7 +1230,7 @@ function views_ui_config_type_form($form, &$form_state) {
     $name = $form_state['update_name'];
   }
 
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_type_form', $name);
+  $view->getStandardButtons($form, $form_state, 'views_ui_config_type_form', $name);
   return $form;
 }
 
@@ -3248,7 +1238,7 @@ function views_ui_config_type_form($form, &$form_state) {
  * Submit handler for type configuration form
  */
 function views_ui_config_type_form_submit($form, &$form_state) {
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   $display = &$form_state['view']->display[$form_state['display_id']];
 
   // Store in cache
@@ -3263,7 +1253,7 @@ function views_ui_rearrange_form($form, &$form_state) {
   $display_id = $form_state['display_id'];
   $type = $form_state['type'];
 
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   if (!$view->setDisplay($display_id)) {
     views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
   }
@@ -3338,7 +1328,7 @@ function views_ui_rearrange_form($form, &$form_state) {
     $name = $form_state['update_name'];
   }
 
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_form');
+  $view->getStandardButtons($form, $form_state, 'views_ui_rearrange_form');
   return $form;
 }
 
@@ -3488,7 +1478,7 @@ function theme_views_ui_build_group_filter_form($variables) {
  * Submit handler for rearranging form.
  */
 function views_ui_rearrange_form_submit($form, &$form_state) {
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
 
   $old_fields = $display->getOption($types[$form_state['type']]['plural']);
@@ -3524,7 +1514,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
   $display_id = $form_state['display_id'];
   $type = $form_state['type'];
 
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   if (!$view->setDisplay($display_id)) {
     views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
   }
@@ -3682,7 +1672,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
     $name = $form_state['update_name'];
   }
 
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_filter_form');
+  $view->getStandardButtons($form, $form_state, 'views_ui_rearrange_filter_form');
   $form['buttons']['add_group'] = array(
     '#type' => 'submit',
     '#value' => t('Create new filter group'),
@@ -3790,7 +1780,7 @@ function theme_views_ui_rearrange_filter_form(&$vars) {
  * Submit handler for rearranging form
  */
 function views_ui_rearrange_filter_form_submit($form, &$form_state) {
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
   $remember_groups = array();
 
@@ -3866,7 +1856,7 @@ function views_ui_rearrange_filter_form_submit($form, &$form_state) {
     );
 
     // Return to this form except on actual Update.
-    views_ui_add_form_to_stack('rearrange-filter', $form_state['view'], $form_state['display_id'], array($form_state['type']));
+    $form_state['view']->addFormToStack('rearrange-filter', $form_state['display_id'], array($form_state['type']));
   }
   else {
     // The actual update button was clicked. Remove the empty groups, and
@@ -3913,7 +1903,7 @@ function views_ui_add_item_form($form, &$form_state) {
   }
   $display = &$view->displayHandlers[$display_id];
 
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
   $ltitle = $types[$type]['ltitle'];
   $section = $types[$type]['plural'];
 
@@ -4021,80 +2011,15 @@ function views_ui_add_item_form($form, &$form_state) {
     '#theme_wrappers' => array('form_element', 'views_container'),
     '#attributes' => array('class' => array('container-inline', 'views-add-form-selected')),
   );
-  views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add and configure @types', array('@types' => $ltitle)));
+  $view->getStandardButtons($form, $form_state, 'views_ui_add_item_form', t('Add and configure @types', array('@types' => $ltitle)));
 
   // Remove the default submit function.
-  $form['buttons']['submit']['#submit'] = array_diff($form['buttons']['submit']['#submit'], array('views_ui_standard_submit'));
-  $form['buttons']['submit']['#submit'][] = 'views_ui_add_item_form_submit';
+  $form['buttons']['submit']['#submit'] = array_diff($form['buttons']['submit']['#submit'], array(array($view, 'standardSubmit')));
+  $form['buttons']['submit']['#submit'][] = array($view, 'submitItemAdd');
 
   return $form;
 }
 
-/**
- * Submit handler for adding new item(s) to a view.
- */
-function views_ui_add_item_form_submit($form, &$form_state) {
-  $type = $form_state['type'];
-  $types = ViewExecutable::viewsHandlerTypes();
-  $section = $types[$type]['plural'];
-
-  // Handle the override select.
-  list($was_defaulted, $is_defaulted) = views_ui_standard_override_values($form, $form_state);
-  if ($was_defaulted && !$is_defaulted) {
-    // We were using the default display's values, but we're now overriding
-    // the default display and saving values specific to this display.
-    $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
-    // setOverride toggles the override of this section.
-    $display->setOverride($section);
-  }
-  elseif (!$was_defaulted && $is_defaulted) {
-    // We used to have an override for this display, but the user now wants
-    // to go back to the default display.
-    // Overwrite the default display with the current form values, and make
-    // the current display use the new default values.
-    $display = &$form_state['view']->displayHandlers[$form_state['display_id']];
-    // optionsOverride toggles the override of this section.
-    $display->setOverride($section);
-  }
-
-  if (!empty($form_state['values']['name']) && is_array($form_state['values']['name'])) {
-    // Loop through each of the items that were checked and add them to the view.
-    foreach (array_keys(array_filter($form_state['values']['name'])) as $field) {
-      list($table, $field) = explode('.', $field, 2);
-
-      if ($cut = strpos($field, '$')) {
-        $field = substr($field, 0, $cut);
-      }
-      $id = $form_state['view']->addItem($form_state['display_id'], $type, $table, $field);
-
-      // check to see if we have group by settings
-      $key = $type;
-      // Footer,header and empty text have a different internal handler type(area).
-      if (isset($types[$type]['type'])) {
-        $key = $types[$type]['type'];
-      }
-      $handler = views_get_handler($table, $field, $key);
-      if ($form_state['view']->display_handler->useGroupBy() && $handler->usesGroupBy()) {
-        views_ui_add_form_to_stack('config-item-group', $form_state['view'], $form_state['display_id'], array($type, $id));
-      }
-
-      // check to see if this type has settings, if so add the settings form first
-      if ($handler && $handler->hasExtraOptions()) {
-        views_ui_add_form_to_stack('config-item-extra', $form_state['view'], $form_state['display_id'], array($type, $id));
-      }
-      // Then add the form to the stack
-      views_ui_add_form_to_stack('config-item', $form_state['view'], $form_state['display_id'], array($type, $id));
-    }
-  }
-
-  if (isset($form_state['view']->form_cache)) {
-    unset($form_state['view']->form_cache);
-  }
-
-  // Store in cache
-  views_ui_cache_set($form_state['view']);
-}
-
 /**
  * Override handler for views_ui_edit_display_form
  */
@@ -4110,7 +2035,7 @@ function views_ui_config_item_form_build_group($form, &$form_state) {
 
   $form_state['view']->setItem($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
-  views_ui_add_form_to_stack($form_state['form_key'], $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE, TRUE);
+  $form_state['view']->addFormToStack($form_state['form_key'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE, TRUE);
 
   views_ui_cache_set($form_state['view']);
   $form_state['rerender'] = TRUE;
@@ -4162,7 +2087,7 @@ function views_ui_config_item_form($form, &$form_state) {
       $form['markup'] = array('#markup' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
     }
     else {
-      $types = ViewExecutable::viewsHandlerTypes();
+      $types = ViewUI::viewsHandlerTypes();
 
       // If this item can come from the default display, show a dropdown
       // that lets the user choose which display the changes should apply to.
@@ -4254,7 +2179,7 @@ function views_ui_config_item_form($form, &$form_state) {
       $name = $form_state['update_name'];
     }
 
-    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove');
+    $view->getStandardButtons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove');
     // Only validate the override values, because this values are required for
     // the override selection.
     $form['buttons']['remove']['#limit_validation_errors'] = array(array('override'));
@@ -4282,7 +2207,7 @@ function views_ui_config_item_form_submit_temporary($form, &$form_state) {
   // Run it through the handler's submit function.
   $form_state['handler']->submitOptionsForm($form['options'], $form_state);
   $item = $form_state['handler']->options;
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
 
   // For footer/header $handler_type is area but $type is footer/header.
   // For all other handle types it's the same.
@@ -4321,7 +2246,7 @@ function views_ui_config_item_form_submit_temporary($form, &$form_state) {
   // @todo: Figure out whether views_ui_ajax_form is perhaps the better place to fix the issue.
   // views_ui_ajax_form() drops the current form from the stack, even if it's an #ajax.
   // So add the item back to the top of the stack.
-  views_ui_add_form_to_stack($form_state['form_key'], $form_state['view'], $form_state['display_id'], array($type, $item['id']), TRUE);
+  $form_state['view']->addFormToStack($form_state['form_key'], $form_state['display_id'], array($type, $item['id']), TRUE);
 
   $form_state['rerender'] = TRUE;
   $form_state['rebuild'] = TRUE;
@@ -4336,7 +2261,7 @@ function views_ui_config_item_form_submit($form, &$form_state) {
   // Run it through the handler's submit function.
   $form_state['handler']->submitOptionsForm($form['options'], $form_state);
   $item = $form_state['handler']->options;
-  $types = ViewExecutable::viewsHandlerTypes();
+  $types = ViewUI::viewsHandlerTypes();
 
   // For footer/header $handler_type is area but $type is footer/header.
   // For all other handle types it's the same.
@@ -4412,7 +2337,7 @@ function views_ui_config_item_group_form($type, &$form_state) {
     }
     else {
       $handler->init($view, $item);
-      $types = ViewExecutable::viewsHandlerTypes();
+      $types = ViewUI::viewsHandlerTypes();
 
       $form['#title'] = t('Configure group settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->adminLabel()));
 
@@ -4420,7 +2345,7 @@ function views_ui_config_item_group_form($type, &$form_state) {
       $form_state['handler'] = &$handler;
     }
 
-    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_group_form');
+    $view->getStandardButtons($form, $form_state, 'views_ui_config_item_group_form');
   }
   return $form;
 }
@@ -4450,7 +2375,7 @@ function views_ui_config_item_group_form_submit($form, &$form_state) {
  */
 function views_ui_config_item_form_remove($form, &$form_state) {
   // Store the item back on the view
-  list($was_defaulted, $is_defaulted) = views_ui_standard_override_values($form, $form_state);
+  list($was_defaulted, $is_defaulted) = $form_state['view']->getOverrideValues($form, $form_state);
   // If the display selection was changed toggle the override value.
   if ($was_defaulted != $is_defaulted) {
     $display =& $form_state['view']->displayHandlers[$form_state['display_id']];
@@ -4477,7 +2402,7 @@ function views_ui_config_item_form_expose($form, &$form_state) {
 
   $form_state['view']->setItem($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
-  views_ui_add_form_to_stack($form_state['form_key'], $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE, TRUE);
+  $form_state['view']->addFormToStack($form_state['form_key'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE, TRUE);
 
   views_ui_cache_set($form_state['view']);
   $form_state['rerender'] = TRUE;
@@ -4513,7 +2438,7 @@ function views_ui_config_item_extra_form($form, &$form_state) {
     }
     else {
       $handler->init($view, $item);
-      $types = ViewExecutable::viewsHandlerTypes();
+      $types = ViewUI::viewsHandlerTypes();
 
       $form['#title'] = t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->adminLabel()));
 
@@ -4524,7 +2449,7 @@ function views_ui_config_item_extra_form($form, &$form_state) {
       $form_state['handler'] = &$handler;
     }
 
-    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_extra_form');
+    $view->getStandardButtons($form, $form_state, 'views_ui_config_item_extra_form');
   }
   return $form;
 }
@@ -4584,7 +2509,7 @@ function views_ui_config_style_form($form, &$form_state) {
     }
     else {
       $handler->init($view, $item);
-      $types = ViewExecutable::viewsHandlerTypes();
+      $types = ViewUI::viewsHandlerTypes();
 
       $form['#title'] = t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->adminLabel()));
 
@@ -4603,7 +2528,7 @@ function views_ui_config_style_form($form, &$form_state) {
       $form_state['handler'] = &$handler;
     }
 
-    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_style_form');
+    $view->getStandardButtons($form, $form_state, 'views_ui_config_style_form');
   }
   return $form;
 }
@@ -4626,30 +2551,12 @@ function views_ui_config_style_form_submit($form, &$form_state) {
   views_ui_cache_set($form_state['view']);
 }
 
-/**
- * Get a list of roles in the system.
- */
-function views_ui_get_roles() {
-  static $roles = NULL;
-  if (!isset($roles)) {
-    $roles = array();
-    // Uses db_query() rather than db_select() because the query is static and
-    // does not include any variables.
-    $result = $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
-    foreach ($result as $obj) {
-      $roles[$obj->rid] = $obj->name;
-    }
-  }
-
-  return $roles;
-}
-
 /**
  * Form builder for the admin display defaults page.
  */
 function views_ui_admin_settings_basic($form, &$form_state) {
   $form = array();
-  $form['#attached']['css'] = views_ui_get_admin_css();
+  $form['#attached']['css'] = ViewUI::getAdminCSS();
 
   $config = config('views.settings');
 
@@ -4789,7 +2696,7 @@ function views_ui_admin_settings_basic_submit(&$form, &$form_state) {
  */
 function views_ui_admin_settings_advanced() {
   $form = array();
-  $form['#attached']['css'] = views_ui_get_admin_css();
+  $form['#attached']['css'] = ViewUI::getAdminCSS();
 
   $config = config('views.settings');
 
@@ -5203,23 +3110,6 @@ function theme_views_ui_style_plugin_table($variables) {
   return $output;
 }
 
-/**
- * Placeholder function for overriding $display['display_title'].
- *
- * @todo Remove this function once editing the display title is possible.
- */
-function views_ui_get_display_label(ViewUI $view, $display_id, $check_changed = TRUE) {
-  $title = $display_id == 'default' ? t('Master') : $view->storage->display[$display_id]['display_title'];
-  $title = views_ui_truncate($title, 25);
-
-  if ($check_changed && !empty($view->changed_display[$display_id])) {
-    $changed = '*';
-    $title = $title . $changed;
-  }
-
-  return $title;
-}
-
 function views_ui_add_template_page() {
   $templates = views_get_all_templates();
 
@@ -5293,12 +3183,13 @@ function views_ui_field_list() {
   // Fetch all fieldapi fields which are used in views
   // Therefore search in all views, displays and handler-types.
   $fields = array();
+  $handler_types = ViewUI::viewsHandlerTypes();
   foreach ($views as $view) {
     $view = $view->getExecutable();
     $view->initDisplay();
     foreach ($view->displayHandlers as $display_id => $display) {
       if ($view->setDisplay($display_id)) {
-        foreach (ViewExecutable::viewsHandlerTypes() as $type => $info) {
+        foreach ($handler_types as $type => $info) {
           foreach ($view->getItems($type, $display_id) as $item) {
             $data = views_fetch_data($item['table']);
             if (isset($data[$item['field']]) && isset($data[$item['field']][$type])
diff --git a/lib/Drupal/views/Plugin/views/access/Role.php b/lib/Drupal/views/Plugin/views/access/Role.php
index 4fafbc3d2579..647d4bfb1f57 100644
--- a/lib/Drupal/views/Plugin/views/access/Role.php
+++ b/lib/Drupal/views/Plugin/views/access/Role.php
@@ -45,7 +45,7 @@ public function summaryTitle() {
       return t('Multiple roles');
     }
     else {
-      $rids = views_ui_get_roles();
+      $rids = user_roles();
       $rid = reset($this->options['role']);
       return check_plain($rids[$rid]);
     }
@@ -65,7 +65,7 @@ public function buildOptionsForm(&$form, &$form_state) {
       '#type' => 'checkboxes',
       '#title' => t('Role'),
       '#default_value' => $this->options['role'],
-      '#options' => array_map('check_plain', views_ui_get_roles()),
+      '#options' => array_map('check_plain', $this->getRoles()),
       '#description' => t('Only the checked roles will be able to access this display. Note that users with "access all views" can see any view, regardless of role.'),
     );
   }
diff --git a/lib/Drupal/views/Plugin/views/argument/ArgumentPluginBase.php b/lib/Drupal/views/Plugin/views/argument/ArgumentPluginBase.php
index 7a60550b9f04..2d569251715b 100644
--- a/lib/Drupal/views/Plugin/views/argument/ArgumentPluginBase.php
+++ b/lib/Drupal/views/Plugin/views/argument/ArgumentPluginBase.php
@@ -183,7 +183,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
     $form['default_action'] = array(
       '#type' => 'radios',
-      '#process' => array('views_ui_process_container_radios'),
+      '#process' => array(array($this, 'processContainerRadios')),
       '#default_value' => $this->options['default_action'],
       '#fieldset' => 'no_argument',
     );
@@ -1076,6 +1076,44 @@ function get_sort_name() {
     return t('Default sort', array(), array('context' => 'Sort order'));
   }
 
+  /**
+   * Custom form radios process function.
+   *
+   * Roll out a single radios element to a list of radios, using the options
+   * array as index. While doing that, create a container element underneath
+   * each option, which contains the settings related to that option.
+   *
+   * @see form_process_radios()
+   */
+  public static function processContainerRadios($element) {
+    if (count($element['#options']) > 0) {
+      foreach ($element['#options'] as $key => $choice) {
+        $element += array($key => array());
+        // Generate the parents as the autogenerator does, so we will have a
+        // unique id for each radio button.
+        $parents_for_id = array_merge($element['#parents'], array($key));
+
+        $element[$key] += array(
+          '#type' => 'radio',
+          '#title' => $choice,
+          // The key is sanitized in drupal_attributes() during output from the
+          // theme function.
+          '#return_value' => $key,
+          '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL,
+          '#attributes' => $element['#attributes'],
+          '#parents' => $element['#parents'],
+          '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
+          '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
+        );
+        $element[$key . '_options'] = array(
+          '#type' => 'container',
+          '#attributes' => array('class' => array('views-admin-dependent')),
+        );
+      }
+    }
+    return $element;
+  }
+
 }
 
 /**
diff --git a/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index 1026ae4a1803..a92c58315f10 100644
--- a/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -1570,6 +1570,7 @@ public function buildOptionsForm(&$form, &$form_state) {
         break;
       case 'style':
         $form['#title'] .= t('How should this view be styled');
+        $style = $this->getOption('style');
         $form['style_plugin'] =  array(
           '#type' => 'radios',
           '#options' => views_fetch_plugin_names('style', $this->getStyleType(), array($this->view->storage->base_table)),
@@ -1612,6 +1613,7 @@ public function buildOptionsForm(&$form, &$form_state) {
         break;
       case 'row':
         $form['#title'] .= t('How should each row in this view be styled');
+        $row = $this->getOption('row');
         $form['row_plugin'] =  array(
           '#type' => 'radios',
           '#options' => views_fetch_plugin_names('row', $this->getStyleType(), array($this->view->storage->base_table)),
@@ -1630,7 +1632,7 @@ public function buildOptionsForm(&$form, &$form_state) {
         break;
       case 'link_display':
         $form['#title'] .= t('Which display to use for path');
-        foreach ($this->view->display as $display_id => $display) {
+        foreach ($this->view->storage->display as $display_id => $display) {
           if ($this->view->displayHandlers[$display_id]->hasPath()) {
             $options[$display_id] = $display['display_title'];
           }
@@ -2170,7 +2172,7 @@ public function submitOptionsForm(&$form, &$form_state) {
             $access = array('type' => $form_state['values']['access']['type']);
             $this->setOption('access', $access);
             if ($plugin->usesOptions()) {
-              views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('access_options'));
+              $this->view->addFormToStack('display', $this->display['id'], array('access_options'));
             }
           }
         }
@@ -2193,7 +2195,7 @@ public function submitOptionsForm(&$form, &$form_state) {
             $cache = array('type' => $form_state['values']['cache']['type']);
             $this->setOption('cache', $cache);
             if ($plugin->usesOptions()) {
-              views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('cache_options'));
+              $this->view->addFormToStack('display', $this->display['id'], array('cache_options'));
             }
           }
         }
@@ -2254,7 +2256,7 @@ public function submitOptionsForm(&$form, &$form_state) {
 
             // send ajax form to options page if we use it.
             if ($plugin->usesOptions()) {
-              views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('row_options'));
+              $this->view->addFormToStack('display', $this->display['id'], array('row_options'));
             }
           }
         }
@@ -2270,7 +2272,7 @@ public function submitOptionsForm(&$form, &$form_state) {
             $this->setOption($section, $row);
             // send ajax form to options page if we use it.
             if ($plugin->usesOptions()) {
-              views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('style_options'));
+              $this->view->addFormToStack('display', $this->display['id'], array('style_options'));
             }
           }
         }
@@ -2304,7 +2306,7 @@ public function submitOptionsForm(&$form, &$form_state) {
             $exposed_form = array('type' => $form_state['values']['exposed_form']['type'], 'options' => array());
             $this->setOption('exposed_form', $exposed_form);
             if ($plugin->usesOptions()) {
-              views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('exposed_form_options'));
+              $this->view->addFormToStack('display', $this->display['id'], array('exposed_form_options'));
             }
           }
         }
@@ -2331,7 +2333,7 @@ public function submitOptionsForm(&$form, &$form_state) {
             $pager = array('type' => $form_state['values']['pager']['type'], 'options' => $plugin->options);
             $this->setOption('pager', $pager);
             if ($plugin->usesOptions()) {
-              views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('pager_options'));
+              $this->view->addFormToStack('display', $this->display['id'], array('pager_options'));
             }
           }
         }
diff --git a/lib/Drupal/views/Plugin/views/display/Page.php b/lib/Drupal/views/Plugin/views/display/Page.php
index d348872334ca..9bc4346d7da6 100644
--- a/lib/Drupal/views/Plugin/views/display/Page.php
+++ b/lib/Drupal/views/Plugin/views/display/Page.php
@@ -609,7 +609,7 @@ public function submitOptionsForm(&$form, &$form_state) {
         $this->setOption('menu', $form_state['values']['menu']);
         // send ajax form to options page if we use it.
         if ($form_state['values']['menu']['type'] == 'default tab') {
-          views_ui_add_form_to_stack('display', $this->view, $this->display['id'], array('tab_options'));
+          $this->view->addFormToStack('display', $this->display['id'], array('tab_options'));
         }
         break;
       case 'tab_options':
diff --git a/lib/Drupal/views/ViewExecutable.php b/lib/Drupal/views/ViewExecutable.php
index 794b8bfa9a69..66b067f0be1e 100644
--- a/lib/Drupal/views/ViewExecutable.php
+++ b/lib/Drupal/views/ViewExecutable.php
@@ -165,12 +165,6 @@ class ViewExecutable {
    */
   public $is_attachment = NULL;
 
-  // Stores the next steps of form items to handle.
-  // It's an array of stack items, which contain the form id, the type of form,
-  // the view, the display and some additional arguments.
-  // @see views_ui_add_form_to_stack()
-  // var $stack;
-
   /**
    * Identifier of the current display.
    *
@@ -1821,13 +1815,11 @@ public function createDuplicate() {
    * This will completely wipe a view clean so it can be considered fresh.
    *
    * @return Drupal\views\ViewExecutable
-   *    The cloned view.
+   *   The cloned view.
    */
   public function cloneView() {
-    $clone = clone $this->storage;
-    $clone = $clone->getExecutable(TRUE);
-
-    return $clone;
+    $storage = clone $this->storage;
+    return $storage->getExecutable(TRUE);
   }
 
   /**
diff --git a/lib/Drupal/views/ViewListController.php b/lib/Drupal/views/ViewListController.php
index a6976ef7a347..38267c7e4919 100644
--- a/lib/Drupal/views/ViewListController.php
+++ b/lib/Drupal/views/ViewListController.php
@@ -131,7 +131,7 @@ public function getOperations(EntityInterface $view) {
    */
   public function render() {
     $list = parent::render();
-    $list['#attached']['css'] = views_ui_get_admin_css();
+    $list['#attached']['css'] = ViewUI::getAdminCSS();
     return $list;
   }
 
diff --git a/lib/Drupal/views/ViewStorage.php b/lib/Drupal/views/ViewStorage.php
index eb90d61c8835..439880c2aec5 100644
--- a/lib/Drupal/views/ViewStorage.php
+++ b/lib/Drupal/views/ViewStorage.php
@@ -129,13 +129,22 @@ public function setExecutable(ViewExecutable $executable) {
    *
    * @param bool $reset
    *   Get a new Drupal\views\ViewExecutable instance.
+   * @param bool $ui
+   *   If this should return Drupal\views\ViewUI instead.
    *
    * @return Drupal\views\ViewExecutable
    *   The executable version of this view.
    */
-  public function getExecutable($reset = FALSE) {
+  public function getExecutable($reset = FALSE, $ui = FALSE) {
     if (!isset($this->executable) || $reset) {
-      $this->setExecutable(new ViewExecutable($this));
+     // @todo Remove this approach and use proper dependency injection.
+      if ($ui) {
+        $executable = new ViewUI($this);
+      }
+      else {
+        $executable = new ViewExecutable($this);
+      }
+      $this->setExecutable($executable);
     }
     return $this->executable;
   }
diff --git a/lib/Drupal/views/ViewUI.php b/lib/Drupal/views/ViewUI.php
index 9d3bdc6fb966..5c7e34470958 100644
--- a/lib/Drupal/views/ViewUI.php
+++ b/lib/Drupal/views/ViewUI.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views;
 
+use Drupal\views\TempStore\UserTempStore;
+
 /**
  * Stores UI related temporary settings.
  */
@@ -88,4 +90,1875 @@ class ViewUI extends ViewExecutable {
    * @var bool
    */
   public $live_preview;
+
+  /**
+   * Overrides Drupal\views\ViewExecutable::cloneView().
+   */
+  public function cloneView() {
+    $storage = clone $this->storage;
+    return $storage->getExecutable(TRUE, TRUE);
+  }
+
+  /**
+   * Placeholder function for overriding $display['display_title'].
+   *
+   * @todo Remove this function once editing the display title is possible.
+   */
+  public function getDisplayLabel($display_id, $check_changed = TRUE) {
+    $title = $display_id == 'default' ? t('Master') : $this->storage->display[$display_id]['display_title'];
+    $title = views_ui_truncate($title, 25);
+
+    if ($check_changed && !empty($this->changed_display[$display_id])) {
+      $changed = '*';
+      $title = $title . $changed;
+    }
+
+    return $title;
+  }
+
+  /**
+   * Helper function to return the used display_id for the edit page
+   *
+   * This function handles access to the display.
+   */
+  public function getDisplayEditPage($display_id) {
+    // Determine the displays available for editing.
+    if ($tabs = $this->getDisplayTabs($display_id)) {
+      // If a display isn't specified, use the first one.
+      if (empty($display_id)) {
+        foreach ($tabs as $id => $tab) {
+          if (!isset($tab['#access']) || $tab['#access']) {
+            $display_id = $id;
+            break;
+          }
+        }
+      }
+      // If a display is specified, but we don't have access to it, return
+      // an access denied page.
+      if ($display_id && (!isset($tabs[$display_id]) || (isset($tabs[$display_id]['#access']) && !$tabs[$display_id]['#access']))) {
+        return MENU_ACCESS_DENIED;
+      }
+
+      return $display_id;
+    }
+    elseif ($display_id) {
+      return MENU_ACCESS_DENIED;
+    }
+    else {
+      $display_id = NULL;
+    }
+
+    return $display_id;
+  }
+
+  /**
+   * Helper function to get the display details section of the edit UI.
+   *
+   * @param $display
+   *
+   * @return array
+   *   A renderable page build array.
+   */
+  public function getDisplayDetails($display) {
+    $display_title = $this->getDisplayLabel($display['id'], FALSE);
+    $build = array(
+      '#theme_wrappers' => array('container'),
+      '#attributes' => array('id' => 'edit-display-settings-details'),
+    );
+
+    // The following is for display purposes only. We need to determine if there is more than one button and wrap
+    // the buttons in a .ctools-dropbutton class if more than one is present.  Otherwise, we'll just wrap the
+    // actions in the .ctools-button class.
+    $is_display_deleted = !empty($display['deleted']);
+    // The master display cannot be cloned.
+    $is_default = $display['id'] == 'default';
+    // @todo: Figure out why getOption doesn't work here.
+    $is_enabled = $this->displayHandlers[$display['id']]->getOption('enabled');
+
+    if (!$is_display_deleted && !$is_default) {
+      $prefix = '<div class="ctools-no-js ctools-button ctools-dropbutton"><div class="ctools-link"><a href="#" class="ctools-twisty ctools-text">open</a></div><div class="ctools-content"><ul class="horizontal right actions">';
+      $suffix = '</ul></div></div>';
+      $item_element = 'li';
+    }
+    else {
+      $prefix = '<div class="ctools-button"><div class="ctools-content"><ul class="horizontal right actions">';
+      $suffix = '</ul></div></div>';
+      $item_element = 'li';
+    }
+
+    if ($display['id'] != 'default') {
+      $build['top']['#theme_wrappers'] = array('container');
+      $build['top']['#attributes']['id'] = 'edit-display-settings-top';
+      $build['top']['#attributes']['class'] = array('views-ui-display-tab-actions', 'views-ui-display-tab-bucket', 'clearfix');
+
+      // The Delete, Duplicate and Undo Delete buttons.
+      $build['top']['actions'] = array(
+        '#prefix' => $prefix,
+        '#suffix' => $suffix,
+      );
+
+      if (!$is_display_deleted) {
+        if (!$is_enabled) {
+          $build['top']['actions']['enable'] = array(
+            '#type' => 'submit',
+            '#value' => t('enable @display_title', array('@display_title' => $display_title)),
+            '#limit_validation_errors' => array(),
+            '#submit' => array(array($this, 'submitDisplayEnable'), array($this, 'submitDelayDestination')),
+            '#prefix' => '<' . $item_element . ' class="enable">',
+            "#suffix" => '</' . $item_element . '>',
+          );
+        }
+        // Add a link to view the page.
+        elseif ($this->displayHandlers[$display['id']]->hasPath()) {
+          $path = $this->displayHandlers[$display['id']]->getPath();
+          if (strpos($path, '%') === FALSE) {
+            $build['top']['actions']['path'] = array(
+              '#type' => 'link',
+              '#title' => t('view @display', array('@display' => $display['display_title'])),
+              '#options' => array('alt' => array(t("Go to the real page for this display"))),
+              '#href' => $path,
+              '#prefix' => '<' . $item_element . ' class="view">',
+              "#suffix" => '</' . $item_element . '>',
+            );
+          }
+        }
+        if (!$is_default) {
+          $build['top']['actions']['duplicate'] = array(
+            '#type' => 'submit',
+            '#value' => t('clone @display_title', array('@display_title' => $display_title)),
+            '#limit_validation_errors' => array(),
+            '#submit' => array(array($this, 'submitDisplayDuplicate'), array($this, 'submitDelayDestination')),
+            '#prefix' => '<' . $item_element . ' class="duplicate">',
+            "#suffix" => '</' . $item_element . '>',
+          );
+        }
+        // Always allow a display to be deleted.
+        $build['top']['actions']['delete'] = array(
+          '#type' => 'submit',
+          '#value' => t('delete @display_title', array('@display_title' => $display_title)),
+          '#limit_validation_errors' => array(),
+          '#submit' => array(array($this, 'submitDisplayDelete'), array($this, 'submitDelayDestination')),
+          '#prefix' => '<' . $item_element . ' class="delete">',
+          "#suffix" => '</' . $item_element . '>',
+        );
+        if ($is_enabled) {
+          $build['top']['actions']['disable'] = array(
+            '#type' => 'submit',
+            '#value' => t('disable @display_title', array('@display_title' => $display_title)),
+            '#limit_validation_errors' => array(),
+            '#submit' => array(array($this, 'submitDisplayDisable'), array($this, 'submitDelayDestination')),
+            '#prefix' => '<' . $item_element . ' class="disable">',
+            "#suffix" => '</' . $item_element . '>',
+          );
+        }
+      }
+      else {
+        $build['top']['actions']['undo_delete'] = array(
+          '#type' => 'submit',
+          '#value' => t('undo delete of @display_title', array('@display_title' => $display_title)),
+          '#limit_validation_errors' => array(),
+          '#submit' => array(array($this, 'submitDisplayUndoDelete'), array($this, 'submitDelayDestination')),
+          '#prefix' => '<' . $item_element . ' class="undo-delete">',
+          "#suffix" => '</' . $item_element . '>',
+        );
+      }
+
+      // The area above the three columns.
+      $build['top']['display_title'] = array(
+        '#theme' => 'views_ui_display_tab_setting',
+        '#description' => t('Display name'),
+        '#link' => $this->displayHandlers[$display['id']]->optionLink(check_plain($display_title), 'display_title'),
+      );
+    }
+
+    $build['columns'] = array();
+    $build['columns']['#theme_wrappers'] = array('container');
+    $build['columns']['#attributes'] = array('id' => 'edit-display-settings-main', 'class' => array('clearfix', 'views-display-columns'));
+
+    $build['columns']['first']['#theme_wrappers'] = array('container');
+    $build['columns']['first']['#attributes'] = array('class' => array('views-display-column', 'first'));
+
+    $build['columns']['second']['#theme_wrappers'] = array('container');
+    $build['columns']['second']['#attributes'] = array('class' => array('views-display-column', 'second'));
+
+    $build['columns']['second']['settings'] = array();
+    $build['columns']['second']['header'] = array();
+    $build['columns']['second']['footer'] = array();
+    $build['columns']['second']['pager'] = array();
+
+    // The third column buckets are wrapped in a fieldset.
+    $build['columns']['third'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Advanced'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#theme_wrappers' => array('fieldset', 'container'),
+      '#attributes' => array(
+        'class' => array(
+          'views-display-column',
+          'third',
+        ),
+      ),
+    );
+
+    // Collapse the fieldset by default.
+    if (config('views.settings')->get('ui.show.advanced_column')) {
+      $build['columns']['third']['#collapsed'] = FALSE;
+    }
+
+    // Each option (e.g. title, access, display as grid/table/list) fits into one
+    // of several "buckets," or boxes (Format, Fields, Sort, and so on).
+    $buckets = array();
+
+    // Fetch options from the display plugin, with a list of buckets they go into.
+    $options = array();
+    $this->displayHandlers[$display['id']]->optionsSummary($buckets, $options);
+
+    // Place each option into its bucket.
+    foreach ($options as $id => $option) {
+      // Each option self-identifies as belonging in a particular bucket.
+      $buckets[$option['category']]['build'][$id] = $this->buildOptionForm($id, $option, $display);
+    }
+
+    // Place each bucket into the proper column.
+    foreach ($buckets as $id => $bucket) {
+      // Let buckets identify themselves as belonging in a column.
+      if (isset($bucket['column']) && isset($build['columns'][$bucket['column']])) {
+        $column = $bucket['column'];
+      }
+      // If a bucket doesn't pick one of our predefined columns to belong to, put
+      // it in the last one.
+      else {
+        $column = 'third';
+      }
+      if (isset($bucket['build']) && is_array($bucket['build'])) {
+        $build['columns'][$column][$id] = $bucket['build'];
+        $build['columns'][$column][$id]['#theme_wrappers'][] = 'views_ui_display_tab_bucket';
+        $build['columns'][$column][$id]['#title'] = !empty($bucket['title']) ? $bucket['title'] : '';
+        $build['columns'][$column][$id]['#name'] = !empty($bucket['title']) ? $bucket['title'] : $id;
+      }
+    }
+
+    $build['columns']['first']['fields'] = $this->getFormBucket('field', $display);
+    $build['columns']['first']['filters'] = $this->getFormBucket('filter', $display);
+    $build['columns']['first']['sorts'] = $this->getFormBucket('sort', $display);
+    $build['columns']['second']['header'] = $this->getFormBucket('header', $display);
+    $build['columns']['second']['footer'] = $this->getFormBucket('footer', $display);
+    $build['columns']['third']['arguments'] = $this->getFormBucket('argument', $display);
+    $build['columns']['third']['relationships'] = $this->getFormBucket('relationship', $display);
+    $build['columns']['third']['empty'] = $this->getFormBucket('empty', $display);
+
+    return $build;
+  }
+
+  /**
+   * Build a renderable array representing one option on the edit form.
+   *
+   * This function might be more logical as a method on an object, if a suitable
+   * object emerges out of refactoring.
+   */
+  public function buildOptionForm($id, $option, $display) {
+    $option_build = array();
+    $option_build['#theme'] = 'views_ui_display_tab_setting';
+
+    $option_build['#description'] = $option['title'];
+
+    $option_build['#link'] = $this->displayHandlers[$display['id']]->optionLink($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
+
+    $option_build['#links'] = array();
+    if (!empty($option['links']) && is_array($option['links'])) {
+      foreach ($option['links'] as $link_id => $link_value) {
+        $option_build['#settings_links'][] = $this->displayHandlers[$display['id']]->optionLink($option['setting'], $link_id, 'views-button-configure', $link_value);
+      }
+    }
+
+    if (!empty($this->displayHandlers[$display['id']]->options['defaults'][$id])) {
+      $display_id = 'default';
+      $option_build['#defaulted'] = TRUE;
+    }
+    else {
+      $display_id = $display['id'];
+      if (!$this->displayHandlers[$display['id']]->isDefaultDisplay()) {
+        if ($this->displayHandlers[$display['id']]->defaultableSections($id)) {
+          $option_build['#overridden'] = TRUE;
+        }
+      }
+    }
+    $option_build['#attributes']['class'][] = drupal_clean_css_identifier($display_id . '-' . $id);
+    return $option_build;
+  }
+
+  /**
+   * Render the top of the display so it can be updated during ajax operations.
+   */
+  public function renderDisplayTop($display_id) {
+    $element['#theme_wrappers'] = array('views_container');
+    $element['#attributes']['class'] = array('views-display-top', 'clearfix');
+    $element['#attributes']['id'] = array('views-display-top');
+
+    // Extra actions for the display
+    $element['extra_actions'] = array(
+      '#theme' => 'links__ctools_dropbutton',
+      '#attributes' => array(
+          'id' => 'views-display-extra-actions',
+          'class' => array(
+            'horizontal', 'right', 'links', 'actions',
+          ),
+        ),
+      '#links' => array(
+        'edit-details' => array(
+          'title' => t('edit view name/description'),
+          'href' => "admin/structure/views/nojs/edit-details/{$this->storage->name}",
+          'attributes' => array('class' => array('views-ajax-link')),
+        ),
+        'analyze' => array(
+          'title' => t('analyze view'),
+          'href' => "admin/structure/views/nojs/analyze/{$this->storage->name}/$display_id",
+          'attributes' => array('class' => array('views-ajax-link')),
+        ),
+        'clone' => array(
+          'title' => t('clone view'),
+          'href' => "admin/structure/views/view/{$this->storage->name}/clone",
+        ),
+        'reorder' => array(
+          'title' => t('reorder displays'),
+          'href' => "admin/structure/views/nojs/reorder-displays/{$this->storage->name}/$display_id",
+          'attributes' => array('class' => array('views-ajax-link')),
+        ),
+      ),
+    );
+
+    // Let other modules add additional links here.
+    drupal_alter('views_ui_display_top_links', $element['extra_actions']['#links'], $this, $display_id);
+
+    if (isset($this->type) && $this->type != t('Default')) {
+      if ($this->type == t('Overridden')) {
+        $element['extra_actions']['#links']['revert'] = array(
+          'title' => t('revert view'),
+          'href' => "admin/structure/views/view/{$this->storage->name}/revert",
+          'query' => array('destination' => "admin/structure/views/view/{$this->storage->name}"),
+        );
+      }
+      else {
+        $element['extra_actions']['#links']['delete'] = array(
+          'title' => t('delete view'),
+          'href' => "admin/structure/views/view/{$this->storage->name}/delete",
+        );
+      }
+    }
+
+    // Determine the displays available for editing.
+    if ($tabs = $this->getDisplayTabs($display_id)) {
+      if ($display_id) {
+        $tabs[$display_id]['#active'] = TRUE;
+      }
+      $tabs['#prefix'] = '<h2 class="element-invisible">' . t('Secondary tabs') . '</h2><ul id = "views-display-menu-tabs" class="tabs secondary">';
+      $tabs['#suffix'] = '</ul>';
+      $element['tabs'] = $tabs;
+    }
+
+    // Buttons for adding a new display.
+    foreach (views_fetch_plugin_names('display', NULL, array($this->storage->base_table)) as $type => $label) {
+      $element['add_display'][$type] = array(
+        '#type' => 'submit',
+        '#value' => t('Add !display', array('!display' => $label)),
+        '#limit_validation_errors' => array(),
+        '#submit' => array(array($this, 'submitDisplayAdd'), array($this, 'submitDelayDestination')),
+        '#attributes' => array('class' => array('add-display')),
+        // Allow JavaScript to remove the 'Add ' prefix from the button label when
+        // placing the button in a "Add" dropdown menu.
+        '#process' => array_merge(array('views_ui_form_button_was_clicked'), element_info_property('submit', '#process', array())),
+        '#values' => array(t('Add !display', array('!display' => $label)), $label),
+      );
+    }
+
+    return $element;
+  }
+
+  public static function getDefaultAJAXMessage() {
+    return '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
+  }
+
+  /**
+   * Adds tabs for navigating across Displays when editing a View.
+   *
+   * This function can be called from hook_menu_local_tasks_alter() to implement
+   * these tabs as secondary local tasks, or it can be called from elsewhere if
+   * having them as secondary local tasks isn't desired. The caller is responsible
+   * for setting the active tab's #active property to TRUE.
+   *
+   * @param $display_id
+   *   The display_id which is edited on the current request.
+   */
+  public function getDisplayTabs($display_id = NULL) {
+    $tabs = array();
+
+    // Create a tab for each display.
+    uasort($this->storage->display, array('static', 'sortPosition'));
+    foreach ($this->storage->display as $id => $display) {
+      $tabs[$id] = array(
+        '#theme' => 'menu_local_task',
+        '#link' => array(
+          'title' => $this->getDisplayLabel($id),
+          'href' => 'admin/structure/views/view/' . $this->storage->name . '/edit/' . $id,
+          'localized_options' => array(),
+        ),
+      );
+      if (!empty($display['deleted'])) {
+        $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'views-display-deleted-link';
+      }
+      if (isset($display['display_options']['enabled']) && !$display['display_options']['enabled']) {
+        $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'views-display-disabled-link';
+      }
+    }
+
+    // If the default display isn't supposed to be shown, don't display its tab, unless it's the only display.
+    if ((!$this->isDefaultDisplayShown() && $display_id != 'default') && count($tabs) > 1) {
+      $tabs['default']['#access'] = FALSE;
+    }
+
+    // Mark the display tab as red to show validation errors.
+    $this->validate();
+    foreach ($this->storage->display as $id => $display) {
+      if (!empty($this->display_errors[$id])) {
+        // Always show the tab.
+        $tabs[$id]['#access'] = TRUE;
+        // Add a class to mark the error and a title to make a hover tip.
+        $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'error';
+        $tabs[$id]['#link']['localized_options']['attributes']['title'] = t('This display has one or more validation errors; please review it.');
+      }
+    }
+
+    return $tabs;
+  }
+
+  /**
+   * Returns a renderable array representing the edit page for one display.
+   */
+  public function getDisplayTab($display_id) {
+    $build = array();
+    $display = $this->displayHandlers[$display_id];
+    // If the plugin doesn't exist, display an error message instead of an edit
+    // page.
+    if (empty($display)) {
+      $title = isset($display['display_title']) ? $display['display_title'] : t('Invalid');
+      // @TODO: Improved UX for the case where a plugin is missing.
+      $build['#markup'] = t("Error: Display @display refers to a plugin named '@plugin', but that plugin is not available.", array('@display' => $display['id'], '@plugin' => $display['display_plugin']));
+    }
+    // Build the content of the edit page.
+    else {
+      $build['details'] = $this->getDisplayDetails($display->display);
+    }
+    // In AJAX context, ViewUI::rebuildCurrentTab() returns this outside of form
+    // context, so hook_form_views_ui_edit_form_alter() is insufficient.
+    drupal_alter('views_ui_display_tab', $build, $this, $display_id);
+    return $build;
+  }
+
+  /**
+   * Controls whether or not the default display should have its own tab on edit.
+   */
+  public function isDefaultDisplayShown() {
+    // Always show the default display for advanced users who prefer that mode.
+    $advanced_mode = config('views.settings')->get('ui.show.master_display');
+    // For other users, show the default display only if there are no others, and
+    // hide it if there's at least one "real" display.
+    $additional_displays = (count($this->displayHandlers) == 1);
+
+    return $advanced_mode || $additional_displays;
+  }
+
+  /**
+   * Basic submit handler applicable to all 'standard' forms.
+   *
+   * This submit handler determines whether the user wants the submitted changes
+   * to apply to the default display or to the current display, and dispatches
+   * control appropriately.
+   */
+  public function standardSubmit($form, &$form_state) {
+    // Determine whether the values the user entered are intended to apply to
+    // the current display or the default display.
+
+    list($was_defaulted, $is_defaulted, $revert) = $this->getOverrideValues($form, $form_state);
+
+    // Based on the user's choice in the display dropdown, determine which display
+    // these changes apply to.
+    if ($revert) {
+      // If it's revert just change the override and return.
+      $display = &$this->displayHandlers[$form_state['display_id']];
+      $display->optionsOverride($form, $form_state);
+
+      // Don't execute the normal submit handling but still store the changed view into cache.
+      views_ui_cache_set($this);
+      return;
+    }
+    elseif ($was_defaulted === $is_defaulted) {
+      // We're not changing which display these form values apply to.
+      // Run the regular submit handler for this form.
+    }
+    elseif ($was_defaulted && !$is_defaulted) {
+      // We were using the default display's values, but we're now overriding
+      // the default display and saving values specific to this display.
+      $display = &$this->displayHandlers[$form_state['display_id']];
+      // optionsOverride toggles the override of this section.
+      $display->optionsOverride($form, $form_state);
+      $display->submitOptionsForm($form, $form_state);
+    }
+    elseif (!$was_defaulted && $is_defaulted) {
+      // We used to have an override for this display, but the user now wants
+      // to go back to the default display.
+      // Overwrite the default display with the current form values, and make
+      // the current display use the new default values.
+      $display = &$this->displayHandlers[$form_state['display_id']];
+      // optionsOverride toggles the override of this section.
+      $display->optionsOverride($form, $form_state);
+      $display->submitOptionsForm($form, $form_state);
+    }
+
+    $submit_handler = $form['#form_id'] . '_submit';
+    if (function_exists($submit_handler)) {
+      $submit_handler($form, $form_state);
+    }
+  }
+
+  /**
+   * Submit handler for cancel button
+   */
+  public function standardCancel($form, &$form_state) {
+    if (!empty($this->changed) && isset($this->form_cache)) {
+      unset($this->form_cache);
+      views_ui_cache_set($this);
+    }
+
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit';
+  }
+
+  /**
+   * Provide a standard set of Apply/Cancel/OK buttons for the forms. Also provide
+   * a hidden op operator because the forms plugin doesn't seem to properly
+   * provide which button was clicked.
+   *
+   * TODO: Is the hidden op operator still here somewhere, or is that part of the
+   * docblock outdated?
+   */
+  public function getStandardButtons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) {
+    $form['buttons'] = array(
+      '#prefix' => '<div class="clearfix"><div class="form-buttons">',
+      '#suffix' => '</div></div>',
+    );
+
+    if (empty($name)) {
+      $name = t('Apply');
+      if (!empty($this->stack) && count($this->stack) > 1) {
+        $name = t('Apply and continue');
+      }
+      $names = array(t('Apply'), t('Apply and continue'));
+    }
+
+    // Forms that are purely informational set an ok_button flag, so we know not
+    // to create an "Apply" button for them.
+    if (empty($form_state['ok_button'])) {
+      $form['buttons']['submit'] = array(
+        '#type' => 'submit',
+        '#value' => $name,
+        // The regular submit handler ($form_id . '_submit') does not apply if
+        // we're updating the default display. It does apply if we're updating
+        // the current display. Since we have no way of knowing at this point
+        // which display the user wants to update, views_ui_standard_submit will
+        // take care of running the regular submit handler as appropriate.
+        '#submit' => array(array($this, 'standardSubmit')),
+      );
+      // Form API button click detection requires the button's #value to be the
+      // same between the form build of the initial page request, and the initial
+      // form build of the request processing the form submission. Ideally, the
+      // button's #value shouldn't change until the form rebuild step. However,
+      // views_ui_ajax_form() implements a different multistep form workflow than
+      // the Form API does, and adjusts $view->stack prior to form processing, so
+      // we compensate by extending button click detection code to support any of
+      // the possible button labels.
+      if (isset($names)) {
+        $form['buttons']['submit']['#values'] = $names;
+        $form['buttons']['submit']['#process'] = array_merge(array('views_ui_form_button_was_clicked'), element_info_property($form['buttons']['submit']['#type'], '#process', array()));
+      }
+      // If a validation handler exists for the form, assign it to this button.
+      if (function_exists($form_id . '_validate')) {
+        $form['buttons']['submit']['#validate'][] = $form_id . '_validate';
+      }
+    }
+
+    // Create a "Cancel" button. For purely informational forms, label it "OK".
+    $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : array($this, 'standardCancel');
+    $form['buttons']['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => empty($form_state['ok_button']) ? t('Cancel') : t('Ok'),
+      '#submit' => array($cancel_submit),
+      '#validate' => array(),
+    );
+
+    // Some forms specify a third button, with a name and submit handler.
+    if ($third) {
+      if (empty($submit)) {
+        $submit = 'third';
+      }
+      $third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : array($this, 'standardCancel');
+
+      $form['buttons'][$submit] = array(
+        '#type' => 'submit',
+        '#value' => $third,
+        '#validate' => array(),
+        '#submit' => array($third_submit),
+      );
+    }
+
+    // Compatibility, to be removed later: // TODO: When is "later"?
+    // We used to set these items on the form, but now we want them on the $form_state:
+    if (isset($form['#title'])) {
+      $form_state['title'] = $form['#title'];
+    }
+    if (isset($form['#url'])) {
+      $form_state['url'] = $form['#url'];
+    }
+    if (isset($form['#section'])) {
+      $form_state['#section'] = $form['#section'];
+    }
+    // Finally, we never want these cached -- our object cache does that for us.
+    $form['#no_cache'] = TRUE;
+
+    // If this isn't an ajaxy form, then we want to set the title.
+    if (!empty($form['#title'])) {
+      drupal_set_title($form['#title']);
+    }
+  }
+
+  /**
+   * Creates an array of Views admin CSS for adding or attaching.
+   *
+   * This returns an array of arrays. Each array represents a single
+   * file. The array format is:
+   * - file: The fully qualified name of the file to send to drupal_add_css
+   * - options: An array of options to pass to drupal_add_css.
+   */
+  public static function getAdminCSS() {
+    $module_path = drupal_get_path('module', 'views_ui');
+    $list = array();
+    $list[$module_path . '/css/views-admin.css'] = array();
+    $list[$module_path . '/css/views-admin.theme.css'] = array();
+
+    // Add in any theme specific CSS files we have
+    $themes = list_themes();
+    $theme_key = $GLOBALS['theme'];
+    while ($theme_key) {
+      // Try to find the admin css file for non-core themes.
+      if (!in_array($theme_key, array('seven', 'bartik'))) {
+        $theme_path = drupal_get_path('theme', $theme_key);
+        // First search in the css directory, then in the root folder of the theme.
+        if (file_exists($theme_path . "/css/views-admin.$theme_key.css")) {
+          $list[$theme_path . "/css/views-admin.$theme_key.css"] = array(
+            'group' => CSS_THEME,
+          );
+        }
+        elseif (file_exists($theme_path . "/views-admin.$theme_key.css")) {
+          $list[$theme_path . "/views-admin.$theme_key.css"] = array(
+            'group' => CSS_THEME,
+          );
+        }
+      }
+      else {
+        $list[$module_path . "/css/views-admin.$theme_key.css"] = array(
+          'group' => CSS_THEME,
+        );
+      }
+      $theme_key = isset($themes[$theme_key]->base_theme) ? $themes[$theme_key]->base_theme : '';
+    }
+    // Views contains style overrides for the following modules
+    $module_list = array('contextual', 'ctools');
+    foreach ($module_list as $module) {
+      if (module_exists($module)) {
+        $list[$module_path . '/css/views-admin.' . $module . '.css'] = array();
+      }
+    }
+
+    return $list;
+  }
+
+  /**
+   * Submit handler to add a display to a view.
+   */
+  public function submitDisplayAdd($form, &$form_state) {
+    // Create the new display.
+    $parents = $form_state['triggering_element']['#parents'];
+    $display_type = array_pop($parents);
+    $display_id = $this->storage->addDisplay($display_type);
+    views_ui_cache_set($this);
+
+    // Redirect to the new display's edit page.
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit/' . $display_id;
+  }
+
+  /**
+   * Submit handler to duplicate a display for a view.
+   */
+  public function submitDisplayDuplicate($form, &$form_state) {
+    $display_id = $form_state['display_id'];
+
+    // Create the new display.
+    $display = $this->storage->display[$display_id];
+    $new_display_id = $this->storage->addDisplay($display['display_plugin']);
+    $this->storage->display[$new_display_id] = $display;
+    $this->storage->display[$new_display_id]['id'] = $new_display_id;
+
+    // By setting the current display the changed marker will appear on the new
+    // display.
+    $this->current_display = $new_display_id;
+    views_ui_cache_set($this);
+
+    // Redirect to the new display's edit page.
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit/' . $new_display_id;
+  }
+
+  /**
+   * Submit handler to delete a display from a view.
+   */
+  public function submitDisplayDelete($form, &$form_state) {
+    $display_id = $form_state['display_id'];
+
+    // Mark the display for deletion.
+    $this->storage->display[$display_id]['deleted'] = TRUE;
+    views_ui_cache_set($this);
+
+    // Redirect to the top-level edit page. The first remaining display will
+    // become the active display.
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name;
+  }
+
+  /**
+   * Submit handler for form buttons that do not complete a form workflow.
+   *
+   * The Edit View form is a multistep form workflow, but with state managed by
+   * the CTools object cache rather than $form_state['rebuild']. Without this
+   * submit handler, buttons that add or remove displays would redirect to the
+   * destination parameter (e.g., when the Edit View form is linked to from a
+   * contextual link). This handler can be added to buttons whose form submission
+   * should not yet redirect to the destination.
+   */
+  public function submitDelayDestination($form, &$form_state) {
+    $query = drupal_container()->get('request')->query;
+    // @todo: Revisit this when http://drupal.org/node/1668866 is in.
+    $destination = $query->get('destination');
+    if (isset($destination) && $form_state['redirect'] !== FALSE) {
+      if (!isset($form_state['redirect'])) {
+        $form_state['redirect'] = current_path();
+      }
+      if (is_string($form_state['redirect'])) {
+        $form_state['redirect'] = array($form_state['redirect']);
+      }
+      $options = isset($form_state['redirect'][1]) ? $form_state['redirect'][1] : array();
+      if (!isset($options['query']['destination'])) {
+        $options['query']['destination'] = $destination;
+      }
+      $form_state['redirect'][1] = $options;
+      $query->remove('destination');
+    }
+  }
+
+  /**
+   * Submit handler to enable a disabled display.
+   */
+  public function submitDisplayEnable($form, &$form_state) {
+    $id = $form_state['display_id'];
+    // setOption doesn't work because this would might affect upper displays
+    $this->displayHandlers[$id]->setOption('enabled', TRUE);
+
+    // Store in cache
+    views_ui_cache_set($this);
+
+    // Redirect to the top-level edit page.
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit/' . $id;
+  }
+
+  /**
+   * Submit handler to disable display.
+   */
+  public function submitDisplayDisable($form, &$form_state) {
+    $id = $form_state['display_id'];
+    $this->displayHandlers[$id]->setOption('enabled', FALSE);
+
+    // Store in cache
+    views_ui_cache_set($this);
+
+    // Redirect to the top-level edit page.
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit/' . $id;
+  }
+
+  /**
+   * Submit handler to add a restore a removed display to a view.
+   */
+  public function submitDisplayUndoDelete($form, &$form_state) {
+    // Create the new display
+    $id = $form_state['display_id'];
+    $this->storage->display[$id]['deleted'] = FALSE;
+
+    // Store in cache
+    views_ui_cache_set($this);
+
+    // Redirect to the top-level edit page.
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit/' . $id;
+  }
+
+  /**
+   * Add information about a section to a display.
+   */
+  public function getFormBucket($type, $display) {
+    $build = array(
+      '#theme_wrappers' => array('views_ui_display_tab_bucket'),
+    );
+    $types = static::viewsHandlerTypes();
+
+    $build['#overridden'] = FALSE;
+    $build['#defaulted'] = FALSE;
+
+    $build['#name'] = $build['#title'] = $types[$type]['title'];
+
+    // Different types now have different rearrange forms, so we use this switch
+    // to get the right one.
+    switch ($type) {
+      case 'filter':
+        $rearrange_url = "admin/structure/views/nojs/rearrange-$type/{$this->storage->name}/{$display['id']}/$type";
+        $rearrange_text = t('And/Or, Rearrange');
+        // TODO: Add another class to have another symbol for filter rearrange.
+        $class = 'icon compact rearrange';
+        break;
+      case 'field':
+        // Fetch the style plugin info so we know whether to list fields or not.
+        $style = $this->displayHandlers[$display['id']]->getOption('style');
+        $style_plugin = $this->displayHandlers[$display['id']]->getPlugin('style', $style['type']);
+        $uses_fields = $style_plugin && $style_plugin->usesFields();
+        if (!$uses_fields) {
+          $build['fields'][] = array(
+            '#markup' => t('The selected style or row format does not utilize fields.'),
+            '#theme_wrappers' => array('views_container'),
+            '#attributes' => array('class' => array('views-display-setting')),
+          );
+          return $build;
+        }
+
+      default:
+        $rearrange_url = "admin/structure/views/nojs/rearrange/{$this->storage->name}/{$display['id']}/$type";
+        $rearrange_text = t('Rearrange');
+        $class = 'icon compact rearrange';
+    }
+
+    // Create an array of actions to pass to theme_links
+    $actions = array();
+    $count_handlers = count($this->displayHandlers[$display['id']]->getHandlers($type));
+    $actions['add'] = array(
+      'title' => t('Add'),
+      'href' => "admin/structure/views/nojs/add-item/{$this->storage->name}/{$display['id']}/$type",
+      'attributes' => array('class' => array('icon compact add', 'views-ajax-link'), 'title' => t('Add'), 'id' => 'views-add-' . $type),
+      'html' => TRUE,
+    );
+    if ($count_handlers > 0) {
+      $actions['rearrange'] = array(
+        'title' => $rearrange_text,
+        'href' => $rearrange_url,
+        'attributes' => array('class' => array($class, 'views-ajax-link'), 'title' => t('Rearrange'), 'id' => 'views-rearrange-' . $type),
+        'html' => TRUE,
+      );
+    }
+
+    // Render the array of links
+    $build['#actions'] = theme('links__ctools_dropbutton',
+      array(
+        'links' => $actions,
+        'attributes' => array(
+          'class' => array('inline', 'links', 'actions', 'horizontal', 'right')
+        ),
+        'class' => array('views-ui-settings-bucket-operations'),
+      )
+    );
+
+    if (!$this->displayHandlers[$display['id']]->isDefaultDisplay()) {
+      if (!$this->displayHandlers[$display['id']]->isDefaulted($types[$type]['plural'])) {
+        $build['#overridden'] = TRUE;
+      }
+      else {
+        $build['#defaulted'] = TRUE;
+      }
+    }
+
+    // If there's an options form for the bucket, link to it.
+    if (!empty($types[$type]['options'])) {
+      $build['#title'] = l($build['#title'], "admin/structure/views/nojs/config-type/{$this->storage->name}/{$display['id']}/$type", array('attributes' => array('class' => array('views-ajax-link'), 'id' => 'views-title-' . $type)));
+    }
+
+    static $relationships = NULL;
+    if (!isset($relationships)) {
+      // Get relationship labels
+      $relationships = array();
+      foreach ($this->displayHandlers[$display['id']]->getHandlers('relationship') as $id => $handler) {
+        $relationships[$id] = $handler->label();
+      }
+    }
+
+    // Filters can now be grouped so we do a little bit extra:
+    $groups = array();
+    $grouping = FALSE;
+    if ($type == 'filter') {
+      $group_info = $this->display_handler->getOption('filter_groups');
+      // If there is only one group but it is using the "OR" filter, we still
+      // treat it as a group for display purposes, since we want to display the
+      // "OR" label next to items within the group.
+      if (!empty($group_info['groups']) && (count($group_info['groups']) > 1 || current($group_info['groups']) == 'OR')) {
+        $grouping = TRUE;
+        $groups = array(0 => array());
+      }
+    }
+
+    $build['fields'] = array();
+
+    foreach ($this->displayHandlers[$display['id']]->getOption($types[$type]['plural']) as $id => $field) {
+      // Build the option link for this handler ("Node: ID = article").
+      $build['fields'][$id] = array();
+      $build['fields'][$id]['#theme'] = 'views_ui_display_tab_setting';
+
+      $handler = $this->displayHandlers[$display['id']]->getHandler($type, $id);
+      if (empty($handler)) {
+        $build['fields'][$id]['#class'][] = 'broken';
+        $field_name = t('Broken/missing handler: @table > @field', array('@table' => $field['table'], '@field' => $field['field']));
+        $build['fields'][$id]['#link'] = l($field_name, "admin/structure/views/nojs/config-item/{$this->storage->name}/{$display['id']}/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
+        continue;
+      }
+
+      $field_name = check_plain($handler->adminLabel(TRUE));
+      if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
+        $field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name;
+      }
+
+      $description = filter_xss_admin($handler->adminSummary());
+      $link_text = $field_name . (empty($description) ? '' : " ($description)");
+      $link_attributes = array('class' => array('views-ajax-link'));
+      if (!empty($field['exclude'])) {
+        $link_attributes['class'][] = 'views-field-excluded';
+      }
+      $build['fields'][$id]['#link'] = l($link_text, "admin/structure/views/nojs/config-item/{$this->storage->name}/{$display['id']}/$type/$id", array('attributes' => $link_attributes, 'html' => TRUE));
+      $build['fields'][$id]['#class'][] = drupal_clean_css_identifier($display['id']. '-' . $type . '-' . $id);
+
+      if ($this->displayHandlers[$display['id']]->useGroupBy() && $handler->usesGroupBy()) {
+        $build['fields'][$id]['#settings_links'][] = l('<span class="label">' . t('Aggregation settings') . '</span>', "admin/structure/views/nojs/config-item-group/{$this->storage->name}/{$display['id']}/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Aggregation settings')), 'html' => TRUE));
+      }
+
+      if ($handler->hasExtraOptions()) {
+        $build['fields'][$id]['#settings_links'][] = l('<span class="label">' . t('Settings') . '</span>', "admin/structure/views/nojs/config-item-extra/{$this->storage->name}/{$display['id']}/$type/$id", array('attributes' => array('class' => array('views-button-configure', 'views-ajax-link'), 'title' => t('Settings')), 'html' => TRUE));
+      }
+
+      if ($grouping) {
+        $gid = $handler->options['group'];
+
+        // Show in default group if the group does not exist.
+        if (empty($group_info['groups'][$gid])) {
+          $gid = 0;
+        }
+        $groups[$gid][] = $id;
+      }
+    }
+
+    // If using grouping, re-order fields so that they show up properly in the list.
+    if ($type == 'filter' && $grouping) {
+      $store = $build['fields'];
+      $build['fields'] = array();
+      foreach ($groups as $gid => $contents) {
+        // Display an operator between each group.
+        if (!empty($build['fields'])) {
+          $build['fields'][] = array(
+            '#theme' => 'views_ui_display_tab_setting',
+            '#class' => array('views-group-text'),
+            '#link' => ($group_info['operator'] == 'OR' ? t('OR') : t('AND')),
+          );
+        }
+        // Display an operator between each pair of filters within the group.
+        $keys = array_keys($contents);
+        $last = end($keys);
+        foreach ($contents as $key => $pid) {
+          if ($key != $last) {
+            $store[$pid]['#link'] .= '&nbsp;&nbsp;' . ($group_info['groups'][$gid] == 'OR' ? t('OR') : t('AND'));
+          }
+          $build['fields'][$pid] = $store[$pid];
+        }
+      }
+    }
+
+    return $build;
+  }
+
+  /**
+   * Return the was_defaulted, is_defaulted and revert state of a form.
+   */
+  public function getOverrideValues($form, $form_state) {
+    // Make sure the dropdown exists in the first place.
+    if (isset($form_state['values']['override']['dropdown'])) {
+      // #default_value is used to determine whether it was the default value or not.
+      // So the available options are: $display, 'default' and 'default_revert', not 'defaults'.
+      $was_defaulted = ($form['override']['dropdown']['#default_value'] === 'defaults');
+      $is_defaulted = ($form_state['values']['override']['dropdown'] === 'default');
+      $revert = ($form_state['values']['override']['dropdown'] === 'default_revert');
+
+      if ($was_defaulted !== $is_defaulted && isset($form['#section'])) {
+        // We're changing which display these values apply to.
+        // Update the #section so it knows what to mark changed.
+        $form['#section'] = str_replace('default-', $form_state['display_id'] . '-', $form['#section']);
+      }
+    }
+    else {
+      // The user didn't get the dropdown for overriding the default display.
+      $was_defaulted = FALSE;
+      $is_defaulted = FALSE;
+      $revert = FALSE;
+    }
+
+    return array($was_defaulted, $is_defaulted, $revert);
+  }
+
+  /**
+   * Regenerate the current tab for AJAX updates.
+   */
+  public function rebuildCurrentTab(&$output, $display_id) {
+    if (!$this->setDisplay('default')) {
+      return;
+    }
+
+    // Regenerate the main display area.
+    $build = $this->getDisplayTab($display_id);
+    static::addMicroweights($build);
+    $output[] = ajax_command_html('#views-tab-' . $display_id, drupal_render($build));
+
+    // Regenerate the top area so changes to display names and order will appear.
+    $build = $this->renderDisplayTop($display_id);
+    static::addMicroweights($build);
+    $output[] = ajax_command_replace('#views-display-top', drupal_render($build));
+  }
+
+  /**
+   * Submit handler to break_lock a view.
+   */
+  public function submitBreakLock(&$form, &$form_state) {
+    UserTempStore::clearAll('view', $this->storage->name);
+    $form_state['redirect'] = 'admin/structure/views/view/' . $this->storage->name . '/edit';
+    drupal_set_message(t('The lock has been broken and you may now edit this view.'));
+  }
+
+  public static function addForm($form, &$form_state) {
+    $form['#attached']['css'] = static::getAdminCSS();
+    $form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
+    $form['#attributes']['class'] = array('views-admin');
+
+    $form['human_name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('View name'),
+      '#required' => TRUE,
+      '#size' => 32,
+      '#default_value' => '',
+      '#maxlength' => 255,
+    );
+    $form['name'] = array(
+      '#type' => 'machine_name',
+      '#maxlength' => 128,
+      '#machine_name' => array(
+        'exists' => 'views_get_view',
+        'source' => array('human_name'),
+      ),
+      '#description' => t('A unique machine-readable name for this View. It must only contain lowercase letters, numbers, and underscores.'),
+    );
+
+    $form['description_enable'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Description'),
+    );
+    $form['description'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Provide description'),
+      '#title_display' => 'invisible',
+      '#size' => 64,
+      '#default_value' => '',
+      '#states' => array(
+        'visible' => array(
+          ':input[name="description_enable"]' => array('checked' => TRUE),
+        ),
+      ),
+    );
+
+    // Create a wrapper for the entire dynamic portion of the form. Everything
+    // that can be updated by AJAX goes somewhere inside here. For example, this
+    // is needed by "Show" dropdown (below); it changes the base table of the
+    // view and therefore potentially requires all options on the form to be
+    // dynamically updated.
+    $form['displays'] = array();
+
+    // Create the part of the form that allows the user to select the basic
+    // properties of what the view will display.
+    $form['displays']['show'] = array(
+      '#type' => 'fieldset',
+      '#tree' => TRUE,
+      '#attributes' => array('class' => array('container-inline')),
+    );
+
+    // Create the "Show" dropdown, which allows the base table of the view to be
+    // selected.
+    $wizard_plugins = views_ui_get_wizards();
+    $options = array();
+    foreach ($wizard_plugins as $key => $wizard) {
+      $options[$key] = $wizard['title'];
+    }
+    $form['displays']['show']['wizard_key'] = array(
+      '#type' => 'select',
+      '#title' => t('Show'),
+      '#options' => $options,
+    );
+    $show_form = &$form['displays']['show'];
+    $default_value = module_exists('node') ? 'node' : 'users';
+    $show_form['wizard_key']['#default_value'] = views_ui_get_selected($form_state, array('show', 'wizard_key'), $default_value, $show_form['wizard_key']);
+    // Changing this dropdown updates the entire content of $form['displays'] via
+    // AJAX.
+    views_ui_add_ajax_trigger($show_form, 'wizard_key', array('displays'));
+
+    // Build the rest of the form based on the currently selected wizard plugin.
+    $wizard_key = $show_form['wizard_key']['#default_value'];
+
+    views_include_handlers();
+    $wizard_instance = views_get_plugin('wizard', $wizard_key);
+
+    $form = $wizard_instance->build_form($form, $form_state);
+
+    $form['save'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save & exit'),
+      '#validate' => array('views_ui_wizard_form_validate'),
+      '#submit' => array('views_ui_add_form_save_submit'),
+    );
+    $form['continue'] = array(
+      '#type' => 'submit',
+      '#value' => t('Continue & edit'),
+      '#validate' => array('views_ui_wizard_form_validate'),
+      '#submit' => array('views_ui_add_form_store_edit_submit'),
+      '#process' => array_merge(array('views_ui_default_button'), element_info_property('submit', '#process', array())),
+    );
+    $form['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel'),
+      '#submit' => array('views_ui_add_form_cancel_submit'),
+      '#limit_validation_errors' => array(),
+    );
+
+    return $form;
+  }
+
+  /**
+   * Form builder callback for editing a View.
+   *
+   * @todo Remove as many #prefix/#suffix lines as possible. Use #theme_wrappers
+   *   instead.
+   *
+   * @todo Rename to views_ui_edit_view_form(). See that function for the "old"
+   *   version.
+   *
+   * @see views_ui_ajax_get_form()
+   */
+  public function editForm($form, &$form_state, $display_id = NULL) {
+    // Do not allow the form to be cached, because $form_state['view'] can become
+    // stale between page requests.
+    // See views_ui_ajax_get_form() for how this affects #ajax.
+    // @todo To remove this and allow the form to be cacheable:
+    //   - Change $form_state['view'] to $form_state['temporary']['view'].
+    //   - Add a #process function to initialize $form_state['temporary']['view']
+    //     on cached form submissions.
+    //   - Use form_load_include().
+    $form_state['no_cache'] = TRUE;
+
+    if ($display_id) {
+      if (!$this->setDisplay($display_id)) {
+        $form['#markup'] = t('Invalid display id @display', array('@display' => $display_id));
+        return $form;
+      }
+    }
+
+    $form['#tree'] = TRUE;
+    // @todo When more functionality is added to this form, cloning here may be
+    //   too soon. But some of what we do with $view later in this function
+    //   results in making it unserializable due to PDO limitations.
+    $form_state['view'] = clone($this);
+
+    $form['#attached']['library'][] = array('system', 'jquery.ui.tabs');
+    $form['#attached']['library'][] = array('system', 'jquery.ui.dialog');
+    $form['#attached']['library'][] = array('system', 'drupal.ajax');
+    $form['#attached']['library'][] = array('system', 'jquery.form');
+    $form['#attached']['library'][] = array('system', 'drupal.states');
+    $form['#attached']['library'][] = array('system', 'drupal.tabledrag');
+
+    $form['#attached']['css'] = static::getAdminCSS();
+
+    $form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
+    $form['#attached']['js'][] = array(
+      'data' => array('views' => array('ajax' => array(
+        'id' => '#views-ajax-body',
+        'title' => '#views-ajax-title',
+        'popup' => '#views-ajax-popup',
+        'defaultForm' => static::getDefaultAJAXMessage(),
+      ))),
+      'type' => 'setting',
+    );
+
+    $form += array(
+      '#prefix' => '',
+      '#suffix' => '',
+    );
+    $form['#prefix'] .= '<div class="views-edit-view views-admin clearfix">';
+    $form['#suffix'] = '</div>' . $form['#suffix'];
+
+    $form['#attributes']['class'] = array('form-edit');
+
+    if (isset($this->locked) && is_object($this->locked)) {
+      $form['locked'] = array(
+        '#theme_wrappers' => array('container'),
+        '#attributes' => array('class' => array('view-locked', 'messages', 'warning')),
+        '#markup' => t('This view is being edited by user !user, and is therefore locked from editing by others. This lock is !age old. Click here to <a href="!break">break this lock</a>.', array('!user' => theme('username', array('account' => user_load($this->locked->ownerID))), '!age' => format_interval(REQUEST_TIME - $this->locked->updated), '!break' => url('admin/structure/views/view/' . $this->storage->name . '/break-lock'))),
+      );
+    }
+    if (isset($this->vid) && $this->vid == 'new') {
+      $message = t('* All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard the view.');
+    }
+    else {
+      $message = t('* All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard your changes.');
+    }
+
+    $form['changed'] = array(
+      '#theme_wrappers' => array('container'),
+      '#attributes' => array('class' => array('view-changed', 'messages', 'warning')),
+      '#markup' => $message,
+    );
+    if (empty($this->changed)) {
+      $form['changed']['#attributes']['class'][] = 'js-hide';
+    }
+
+    $form['help_text'] = array(
+      '#prefix' => '<div>',
+      '#suffix' => '</div>',
+      '#markup' => t('Modify the display(s) of your view below or add new displays.'),
+    );
+
+    $form['actions'] = array(
+      '#type' => 'actions',
+      '#weight' => 0,
+    );
+
+    if (empty($this->changed)) {
+      $form['actions']['#attributes'] = array(
+        'class' => array(
+          'js-hide',
+        ),
+      );
+    }
+
+    $form['actions']['save'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+      // Taken from the "old" UI. @TODO: Review and rename.
+      '#validate' => array('views_ui_edit_view_form_validate'),
+      '#submit' => array('views_ui_edit_view_form_submit'),
+    );
+    $form['actions']['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel'),
+      '#submit' => array('views_ui_edit_view_form_cancel'),
+    );
+
+    $form['displays'] = array(
+      '#prefix' => '<h1 class="unit-title clearfix">' . t('Displays') . '</h1>' . "\n" . '<div class="views-displays">',
+      '#suffix' => '</div>',
+    );
+
+    $form['displays']['top'] = $this->renderDisplayTop($display_id);
+
+    // The rest requires a display to be selected.
+    if ($display_id) {
+      $form_state['display_id'] = $display_id;
+
+      // The part of the page where editing will take place.
+      $form['displays']['settings'] = array(
+        '#type' => 'container',
+        '#id' => 'edit-display-settings',
+      );
+      $display_title = $this->getDisplayLabel($display_id, FALSE);
+
+      $form['displays']['settings']['#title'] = '<h2>' . t('@display_title details', array('@display_title' => ucwords($display_title))) . '</h2>';
+
+      // Add a text that the display is disabled.
+      if (!empty($this->displayHandlers[$display_id])) {
+        $enabled = $this->displayHandlers[$display_id]->getOption('enabled');
+        if (empty($enabled)) {
+          $form['displays']['settings']['disabled']['#markup'] = t('This display is disabled.');
+        }
+      }
+
+      $form['displays']['settings']['settings_content']= array(
+        '#theme_wrappers' => array('container'),
+      );
+      // Add the edit display content
+      $form['displays']['settings']['settings_content']['tab_content'] = $this->getDisplayTab($display_id);
+      $form['displays']['settings']['settings_content']['tab_content']['#theme_wrappers'] = array('container');
+      $form['displays']['settings']['settings_content']['tab_content']['#attributes'] = array('class' => array('views-display-tab'));
+      $form['displays']['settings']['settings_content']['tab_content']['#id'] = 'views-tab-' . $display_id;
+      // Mark deleted displays as such.
+      if (!empty($this->storage->display[$display_id]['deleted'])) {
+        $form['displays']['settings']['settings_content']['tab_content']['#attributes']['class'][] = 'views-display-deleted';
+      }
+      // Mark disabled displays as such.
+      if (empty($enabled)) {
+        $form['displays']['settings']['settings_content']['tab_content']['#attributes']['class'][] = 'views-display-disabled';
+      }
+
+      // The content of the popup dialog.
+      $form['ajax-area'] = array(
+        '#theme_wrappers' => array('container'),
+        '#id' => 'views-ajax-popup',
+      );
+      $form['ajax-area']['ajax-title'] = array(
+        '#markup' => '<h2 id="views-ajax-title"></h2>',
+      );
+      $form['ajax-area']['ajax-body'] = array(
+        '#theme_wrappers' => array('container'),
+        '#id' => 'views-ajax-body',
+        '#markup' => static::getDefaultAJAXMessage(),
+      );
+    }
+
+    // If relationships had to be fixed, we want to get that into the cache
+    // so that edits work properly, and to try to get the user to save it
+    // so that it's not using weird fixed up relationships.
+    if (!empty($this->relationships_changed) && drupal_container()->get('request')->request->count()) {
+      drupal_set_message(t('This view has been automatically updated to fix missing relationships. While this View should continue to work, you should verify that the automatic updates are correct and save this view.'));
+      views_ui_cache_set($this);
+    }
+    return $form;
+  }
+
+  /**
+   * Provide the preview formulas and the preview output, too.
+   */
+  public function buildPreviewForm($form, &$form_state, $display_id = 'default') {
+    $form_state['no_cache'] = TRUE;
+    $form_state['view'] = $this;
+
+    $form['#attributes'] = array('class' => array('clearfix'));
+
+    // Add a checkbox controlling whether or not this display auto-previews.
+    $form['live_preview'] = array(
+      '#type' => 'checkbox',
+      '#id' => 'edit-displays-live-preview',
+      '#title' => t('Auto preview'),
+      '#default_value' => config('views.settings')->get('ui.always_live_preview'),
+    );
+
+    // Add the arguments textfield
+    $form['view_args'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Preview with contextual filters:'),
+      '#description' => t('Separate contextual filter values with a "/". For example, %example.', array('%example' => '40/12/10')),
+      '#id' => 'preview-args',
+    );
+
+    // Add the preview button
+    $form['button'] = array(
+      '#type' => 'submit',
+      '#value' => t('Update preview'),
+      '#attributes' => array('class' => array('arguments-preview', 'ctools-auto-submit-click')),
+      '#prefix' => '<div id="preview-submit-wrapper">',
+      '#suffix' => '</div>',
+      '#id' => 'preview-submit',
+      '#ajax' => array(
+        'path' => 'admin/structure/views/view/' . $this->storage->name . '/preview/' . $display_id . '/ajax',
+        'wrapper' => 'views-preview-wrapper',
+        'event' => 'click',
+        'progress' => array('type' => 'throbber'),
+        'method' => 'replace',
+      ),
+      // Make ENTER in arguments textfield (and other controls) submit the form
+      // as this button, not the Save button.
+      // @todo This only works for JS users. To make this work for nojs users,
+      //   we may need to split Preview into a separate form.
+      '#process' => array_merge(array('views_ui_default_button'), element_info_property('submit', '#process', array())),
+    );
+    $form['#action'] = url('admin/structure/views/view/' . $this->storage->name .'/preview/' . $display_id);
+
+    return $form;
+  }
+
+  /**
+   * Form constructor callback to reorder displays on a view
+   */
+  public function buildDisplaysReorderForm($form, &$form_state) {
+    $display_id = $form_state['display_id'];
+
+    $form['view'] = array('#type' => 'value', '#value' => $this);
+
+    $form['#tree'] = TRUE;
+
+    $count = count($this->storage->display);
+
+    uasort($this->storage->display, array('static', 'sortPosition'));
+    foreach ($this->storage->display as $display) {
+      $form[$display['id']] = array(
+        'title'  => array('#markup' => $display['display_title']),
+        'weight' => array(
+          '#type' => 'weight',
+          '#value' => $display['position'],
+          '#delta' => $count,
+          '#title' => t('Weight for @display', array('@display' => $display['display_title'])),
+          '#title_display' => 'invisible',
+        ),
+        '#tree' => TRUE,
+        '#display' => $display,
+        'removed' => array(
+          '#type' => 'checkbox',
+          '#id' => 'display-removed-' . $display['id'],
+          '#attributes' => array('class' => array('views-remove-checkbox')),
+          '#default_value' => isset($display['deleted']),
+        ),
+      );
+
+      if (isset($display['deleted']) && $display['deleted']) {
+        $form[$display['id']]['deleted'] = array('#type' => 'value', '#value' => TRUE);
+      }
+      if ($display['id'] === 'default') {
+        unset($form[$display['id']]['weight']);
+        unset($form[$display['id']]['removed']);
+      }
+
+    }
+
+    $form['#title'] = t('Displays Reorder');
+    $form['#section'] = 'reorder';
+
+    // Add javascript settings that will be added via $.extend for tabledragging
+    $form['#js']['tableDrag']['reorder-displays']['weight'][0] = array(
+      'target' => 'weight',
+      'source' => NULL,
+      'relationship' => 'sibling',
+      'action' => 'order',
+      'hidden' => TRUE,
+      'limit' => 0,
+    );
+
+    $form['#action'] = url('admin/structure/views/nojs/reorder-displays/' . $this->storage->name . '/' . $display_id);
+
+    $this->getStandardButtons($form, $form_state, 'views_ui_reorder_displays_form');
+    $form['buttons']['submit']['#submit'] = array(array($this, 'submitDisplaysReorderForm'));
+
+    return $form;
+  }
+
+  /**
+   * Submit handler for rearranging display form
+   */
+  public function submitDisplaysReorderForm($form, &$form_state) {
+    foreach ($form_state['input'] as $display => $info) {
+      // add each value that is a field with a weight to our list, but only if
+      // it has had its 'removed' checkbox checked.
+      if (is_array($info) && isset($info['weight']) && empty($info['removed'])) {
+        $order[$display] = $info['weight'];
+      }
+    }
+
+    // Sort the order array
+    asort($order);
+
+    // Fixing up positions
+    $position = 1;
+
+    foreach (array_keys($order) as $display) {
+      $order[$display] = $position++;
+    }
+
+    // Setting up position and removing deleted displays
+    $displays = $this->storage->display;
+    foreach ($displays as $display_id => $display) {
+      // Don't touch the default !!!
+      if ($display_id === 'default') {
+        $this->storage->display[$display_id]['position'] = 0;
+        continue;
+      }
+      if (isset($order[$display_id])) {
+        $this->storage->display[$display_id]['position'] = $order[$display_id];
+      }
+      else {
+        $this->storage->display[$display_id]['deleted'] = TRUE;
+      }
+    }
+
+    // Sorting back the display array as the position is not enough
+    uasort($this->storage->display, array('static', 'sortPosition'));
+
+    // Store in cache
+    views_ui_cache_set($this);
+    $form_state['redirect'] = array('admin/structure/views/view/' . $this->storage->name . '/edit', array('fragment' => 'views-tab-default'));
+  }
+
+  /**
+   * Add another form to the stack; clicking 'apply' will go to this form
+   * rather than closing the ajax popup.
+   */
+  public function addFormToStack($key, $display_id, $args, $top = FALSE, $rebuild_keys = FALSE) {
+    if (empty($this->stack)) {
+      $this->stack = array();
+    }
+
+    $stack = array($this->buildIdentifier($key, $display_id, $args), $key, &$this, $display_id, $args);
+    // If we're being asked to add this form to the bottom of the stack, no
+    // special logic is required. Our work is equally easy if we were asked to add
+    // to the top of the stack, but there's nothing in it yet.
+    if (!$top || empty($this->stack)) {
+      $this->stack[] = $stack;
+    }
+    // If we're adding to the top of an existing stack, we have to maintain the
+    // existing integer keys, so they can be used for the "2 of 3" progress
+    // indicator (which will now read "2 of 4").
+    else {
+      $keys = array_keys($this->stack);
+      $first = current($keys);
+      $last = end($keys);
+      for ($i = $last; $i >= $first; $i--) {
+        if (!isset($this->stack[$i])) {
+          continue;
+        }
+        // Move form number $i to the next position in the stack.
+        $this->stack[$i + 1] = $this->stack[$i];
+        unset($this->stack[$i]);
+      }
+      // Now that the previously $first slot is free, move the new form into it.
+      $this->stack[$first] = $stack;
+      ksort($this->stack);
+
+      // Start the keys from 0 again, if requested.
+      if ($rebuild_keys) {
+        $this->stack = array_values($this->stack);
+      }
+    }
+  }
+
+  /**
+   * Submit handler for adding new item(s) to a view.
+   */
+  public function submitItemAdd($form, &$form_state) {
+    $type = $form_state['type'];
+    $types = static::viewsHandlerTypes();
+    $section = $types[$type]['plural'];
+
+    // Handle the override select.
+    list($was_defaulted, $is_defaulted) = $this->getOverrideValues($form, $form_state);
+    if ($was_defaulted && !$is_defaulted) {
+      // We were using the default display's values, but we're now overriding
+      // the default display and saving values specific to this display.
+      $display = &$this->displayHandlers[$form_state['display_id']];
+      // setOverride toggles the override of this section.
+      $display->setOverride($section);
+    }
+    elseif (!$was_defaulted && $is_defaulted) {
+      // We used to have an override for this display, but the user now wants
+      // to go back to the default display.
+      // Overwrite the default display with the current form values, and make
+      // the current display use the new default values.
+      $display = &$this->displayHandlers[$form_state['display_id']];
+      // optionsOverride toggles the override of this section.
+      $display->setOverride($section);
+    }
+
+    if (!empty($form_state['values']['name']) && is_array($form_state['values']['name'])) {
+      // Loop through each of the items that were checked and add them to the view.
+      foreach (array_keys(array_filter($form_state['values']['name'])) as $field) {
+        list($table, $field) = explode('.', $field, 2);
+
+        if ($cut = strpos($field, '$')) {
+          $field = substr($field, 0, $cut);
+        }
+        $id = $this->addItem($form_state['display_id'], $type, $table, $field);
+
+        // check to see if we have group by settings
+        $key = $type;
+        // Footer,header and empty text have a different internal handler type(area).
+        if (isset($types[$type]['type'])) {
+          $key = $types[$type]['type'];
+        }
+        $handler = views_get_handler($table, $field, $key);
+        if ($this->display_handler->useGroupBy() && $handler->usesGroupBy()) {
+          $this->addFormToStack('config-item-group', $form_state['display_id'], array($type, $id));
+        }
+
+        // check to see if this type has settings, if so add the settings form first
+        if ($handler && $handler->hasExtraOptions()) {
+          $this->addFormToStack('config-item-extra', $form_state['display_id'], array($type, $id));
+        }
+        // Then add the form to the stack
+        $this->addFormToStack('config-item', $form_state['display_id'], array($type, $id));
+      }
+    }
+
+    if (isset($this->form_cache)) {
+      unset($this->form_cache);
+    }
+
+    // Store in cache
+    views_ui_cache_set($this);
+  }
+
+  public function renderPreview($display_id, $args = array()) {
+    // Save the current path so it can be restored before returning from this function.
+    $old_q = current_path();
+
+    // Determine where the query and performance statistics should be output.
+    $config = config('views.settings');
+    $show_query = $config->get('ui.show.sql_query.enabled');
+    $show_info = $config->get('ui.show.preview_information');
+    $show_location = $config->get('ui.show.sql_query.where');
+
+    $show_stats = $config->get('ui.show.performance_statistics');
+    if ($show_stats) {
+      $show_stats = $config->get('ui.show.sql_query.where');
+    }
+
+    $combined = $show_query && $show_stats;
+
+    $rows = array('query' => array(), 'statistics' => array());
+    $output = '';
+
+    $errors = $this->validate();
+    if ($errors === TRUE) {
+      $this->ajax = TRUE;
+      $this->live_preview = TRUE;
+      $this->views_ui_context = TRUE;
+
+      // AJAX happens via $_POST but everything expects exposed data to
+      // be in GET. Copy stuff but remove ajax-framework specific keys.
+      // If we're clicking on links in a preview, though, we could actually
+      // still have some in $_GET, so we use $_REQUEST to ensure we get it all.
+      $exposed_input = drupal_container()->get('request')->request->all();
+      foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', 'ajax_html_ids', 'ajax_page_state', 'form_id', 'form_build_id', 'form_token') as $key) {
+        if (isset($exposed_input[$key])) {
+          unset($exposed_input[$key]);
+        }
+      }
+
+      $this->setExposedInput($exposed_input);
+
+      if (!$this->setDisplay($display_id)) {
+        return t('Invalid display id @display', array('@display' => $display_id));
+      }
+
+      $this->setArguments($args);
+
+      // Store the current view URL for later use:
+      if ($this->display_handler->getOption('path')) {
+        $path = $this->getUrl();
+      }
+
+      // Make view links come back to preview.
+      $this->override_path = 'admin/structure/views/nojs/preview/' . $this->storage->name . '/' . $display_id;
+
+      // Also override the current path so we get the pager.
+      $original_path = current_path();
+      $q = _current_path($this->override_path);
+      if ($args) {
+        $q .= '/' . implode('/', $args);
+        _current_path($q);
+      }
+
+      // Suppress contextual links of entities within the result set during a
+      // Preview.
+      // @todo We'll want to add contextual links specific to editing the View, so
+      //   the suppression may need to be moved deeper into the Preview pipeline.
+      views_ui_contextual_links_suppress_push();
+      $preview = $this->preview($display_id, $args);
+      views_ui_contextual_links_suppress_pop();
+
+      // Reset variables.
+      unset($this->override_path);
+      _current_path($original_path);
+
+      // Prepare the query information and statistics to show either above or
+      // below the view preview.
+      if ($show_info || $show_query || $show_stats) {
+        // Get information from the preview for display.
+        if (!empty($this->build_info['query'])) {
+          if ($show_query) {
+            $query = $this->build_info['query'];
+            // Only the sql default class has a method getArguments.
+            $quoted = array();
+
+            if (get_class($this->query) == 'views_plugin_query_default') {
+              $quoted = $query->getArguments();
+              $connection = Database::getConnection();
+              foreach ($quoted as $key => $val) {
+                if (is_array($val)) {
+                  $quoted[$key] = implode(', ', array_map(array($connection, 'quote'), $val));
+                }
+                else {
+                  $quoted[$key] = $connection->quote($val);
+                }
+              }
+            }
+            $rows['query'][] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain(strtr($query, $quoted)) . '</pre>');
+            if (!empty($this->additional_queries)) {
+              $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
+              foreach ($this->additional_queries as $query) {
+                if ($queries) {
+                  $queries .= "\n";
+                }
+                $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . $query[0];
+              }
+
+              $rows['query'][] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
+            }
+          }
+          if ($show_info) {
+            $rows['query'][] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($this->getTitle()));
+            if (isset($path)) {
+              $path = l($path, $path);
+            }
+            else {
+              $path = t('This display has no path.');
+            }
+            $rows['query'][] = array('<strong>' . t('Path') . '</strong>', $path);
+          }
+
+          if ($show_stats) {
+            $rows['statistics'][] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($this->build_time * 100000) / 100)));
+            $rows['statistics'][] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($this->execute_time * 100000) / 100)));
+            $rows['statistics'][] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($this->render_time * 100000) / 100)));
+
+          }
+          drupal_alter('views_preview_info', $rows, $this);
+        }
+        else {
+          // No query was run. Display that information in place of either the
+          // query or the performance statistics, whichever comes first.
+          if ($combined || ($show_location === 'above')) {
+            $rows['query'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
+          }
+          else {
+            $rows['statistics'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
+          }
+        }
+      }
+    }
+    else {
+      foreach ($errors as $error) {
+        drupal_set_message($error, 'error');
+      }
+      $preview = t('Unable to preview due to validation errors.');
+    }
+
+    // Assemble the preview, the query info, and the query statistics in the
+    // requested order.
+    if ($show_location === 'above') {
+      if ($combined) {
+        $output .= '<div class="views-query-info">' . theme('table', array('rows' => array_merge($rows['query'], $rows['statistics']))) . '</div>';
+      }
+      else {
+        $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['query'])) . '</div>';
+      }
+    }
+    elseif ($show_stats === 'above') {
+      $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['statistics'])) . '</div>';
+    }
+
+    $output .= $preview;
+
+    if ($show_location === 'below') {
+      if ($combined) {
+        $output .= '<div class="views-query-info">' . theme('table', array('rows' => array_merge($rows['query'], $rows['statistics']))) . '</div>';
+      }
+      else {
+        $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['query'])) . '</div>';
+      }
+    }
+    elseif ($show_stats === 'below') {
+      $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['statistics'])) . '</div>';
+    }
+
+    _current_path($old_q);
+    return $output;
+  }
+
+  /**
+   * Recursively adds microweights to a render array, similar to what form_builder() does for forms.
+   *
+   * @todo Submit a core patch to fix drupal_render() to do this, so that all
+   *   render arrays automatically preserve array insertion order, as forms do.
+   */
+  public static function addMicroweights(&$build) {
+    $count = 0;
+    foreach (element_children($build) as $key) {
+      if (!isset($build[$key]['#weight'])) {
+        $build[$key]['#weight'] = $count/1000;
+      }
+      static::addMicroweights($build[$key]);
+      $count++;
+    }
+  }
+
+  /**
+   * Get the user's current progress through the form stack.
+   *
+   * @return
+   *   FALSE if the user is not currently in a multiple-form stack. Otherwise,
+   *   an associative array with the following keys:
+   *   - current: The number of the current form on the stack.
+   *   - total: The total number of forms originally on the stack.
+   */
+  public function getFormProgress() {
+    $progress = FALSE;
+    if (!empty($this->stack)) {
+      $stack = $this->stack;
+      // The forms on the stack have integer keys that don't change as the forms
+      // are completed, so we can see which ones are still left.
+      $keys = array_keys($this->stack);
+      // Add 1 to the array keys for the benefit of humans, who start counting
+      // from 1 and not 0.
+      $current = reset($keys) + 1;
+      $total = end($keys) + 1;
+      if ($total > 1) {
+        $progress = array();
+        $progress['current'] = $current;
+        $progress['total'] = $total;
+      }
+    }
+    return $progress;
+  }
+
+  /**
+   * Build a form identifier that we can use to see if one form
+   * is the same as another. Since the arguments differ slightly
+   * we do a lot of spiffy concatenation here.
+   */
+  public function buildIdentifier($key, $display_id, $args) {
+    $form = views_ui_ajax_forms($key);
+    // Automatically remove the single-form cache if it exists and
+    // does not match the key.
+    $identifier = implode('-', array($key, $this->storage->name, $display_id));
+
+    foreach ($form['args'] as $id) {
+      $arg = (!empty($args)) ? array_shift($args) : NULL;
+      $identifier .= '-' . $arg;
+    }
+    return $identifier;
+  }
+
+  /**
+   * Display position sorting function
+   */
+  public static function sortPosition($display1, $display2) {
+    if ($display1['position'] != $display2['position']) {
+      return $display1['position'] < $display2['position'] ? -1 : 1;
+    }
+
+    return 0;
+  }
+
 }
diff --git a/views_ui.module b/views_ui.module
index 603f781d29fb..d35e5381ab10 100644
--- a/views_ui.module
+++ b/views_ui.module
@@ -66,14 +66,6 @@ function views_ui_menu() {
   ) + $base;
   */
 
-  $items['admin/structure/views/import'] = array(
-    'title' => 'Import',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('views_ui_import_page'),
-    'access callback' => 'views_import_access',
-    'type' => MENU_LOCAL_ACTION,
-  ) + $base;
-
   $items['admin/structure/views/settings'] = array(
     'title' => 'Settings',
     'page callback' => 'drupal_get_form',
@@ -150,21 +142,15 @@ function views_ui_menu() {
     'type' => MENU_CALLBACK,
   ) + $base;
 
-  // NoJS/AJAX callbacks that require custom page callbacks.
-  $ajax_callbacks = array(
-    'preview' => 'views_ui_preview',
-  );
-  foreach ($ajax_callbacks as $menu => $menu_callback) {
-    $items['admin/structure/views/nojs/' . $menu . '/%views_ui_cache/%'] = array(
-      'page callback' => $menu_callback,
-      'page arguments' => array(5, 6),
-    ) + $base;
-    $items['admin/structure/views/ajax/' . $menu . '/%views_ui_cache/%'] = array(
-      'page callback' => $menu_callback,
-      'page arguments' => array(5, 6),
-      'delivery callback' => 'ajax_deliver',
-    ) + $base;
-  }
+  $items['admin/structure/views/nojs/preview/%views_ui_cache/%'] = array(
+    'page callback' => 'views_ui_preview',
+    'page arguments' => array(5, 6),
+  ) + $base;
+  $items['admin/structure/views/ajax/preview/%views_ui_cache/%'] = array(
+    'page callback' => 'views_ui_preview',
+    'page arguments' => array(5, 6),
+    'delivery callback' => 'ajax_deliver',
+  ) + $base;
 
   // Autocomplete callback for tagging a View.
   // Views module uses admin/views/... instead of admin/structure/views/... for
-- 
GitLab