[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/views/includes/ -> admin.inc (source)

   1  <?php
   2  // $Id: admin.inc,v 1.161.2.12 2010/06/17 02:45:36 merlinofchaos Exp $
   3  /**
   4   * @file admin.inc
   5   * Provides the Views' administrative interface.
   6   */
   7  
   8  /**
   9   * Page callback to list views in the system.
  10   */
  11  function views_ui_list_views($arg = NULL) {
  12    if ($arg != NULL) {
  13      return drupal_not_found();
  14    }
  15  
  16    $output = theme('views_ui_list_views');
  17    views_ui_check_advanced_help();
  18    return $output;
  19  }
  20  
  21  /**
  22   * Check to see if the advanced help module is installed, and if not put up
  23   * a message.
  24   *
  25   * Only call this function if the user is already in a position for this to
  26   * be useful.
  27   */
  28  function views_ui_check_advanced_help() {
  29    if (variable_get('views_hide_help_message', FALSE)) {
  30      return;
  31    }
  32  
  33    if (!module_exists('advanced_help')) {
  34      $filename = db_result(db_query("SELECT filename FROM {system} WHERE type = 'module' AND name = 'advanced_help'"));
  35      if ($filename && file_exists($filename)) {
  36        drupal_set_message(t('If you <a href="@modules">enable the advanced help module</a>, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('@modules' => url('admin/build/modules'),'@hide' => url('admin/build/views/tools'))));
  37      }
  38      else {
  39        drupal_set_message(t('If you install the advanced help module from !href, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('!href' => l('http://drupal.org/project/advanced_help', 'http://drupal.org/project/advanced_help'), '@hide' => url('admin/build/views/tools'))));
  40      }
  41    }
  42  }
  43  
  44  /**
  45   * Preprocess the list views theme
  46   */
  47  function template_preprocess_views_ui_list_views(&$vars) {
  48    $items = array();
  49    $sorts = array();
  50  
  51    $views = views_get_all_views();
  52  
  53    $token_enable = drupal_get_token('views-enable');
  54    $token_disable = drupal_get_token('views-disable');
  55  
  56    // Respond to a reset command by clearing session and doing a drupal goto
  57    // back to the base URL.
  58    if (isset($_GET['op']) && $_GET['op'] == t('Reset')) {
  59      unset($_SESSION['views']['#admin']);
  60      drupal_goto('admin/build/views');
  61    }
  62    if (count($_GET) <= 1) {
  63      if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) {
  64        $_GET += $_SESSION['views']['#admin'];
  65      }
  66    }
  67    else {
  68      $_SESSION['views']['#admin'] = $_GET;
  69      unset($_SESSION['views']['#admin']['q']);
  70    }
  71  
  72    $form_state = array(
  73      'views' => $views,
  74      'input' => $_GET,
  75      'method' => 'get',
  76      'rerender' => TRUE,
  77      'no_redirect' => TRUE,
  78    );
  79  
  80    $vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state);
  81  
  82    $vars['help_type_icon'] = theme('advanced_help_topic', 'views', 'view-type');
  83  
  84    $base_tables = views_fetch_base_tables();
  85  
  86    foreach ($views as $view) {
  87      if ($form_state['values']['tag'] != 'all') {
  88        if ($form_state['values']['tag'] == 'none') {
  89          if (!empty($view->tag)) {
  90            continue;
  91          }
  92        }
  93        else if ($form_state['values']['tag'] != $view->tag) {
  94          continue;
  95        }
  96      }
  97      if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) {
  98        continue;
  99      }
 100  
 101      if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) {
 102        continue;
 103      }
 104  
 105      if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) {
 106        continue;
 107      }
 108  
 109      $item = new stdClass();
 110      $item->ops = array();
 111      if (empty($view->disabled)) {
 112        $item->ops[] = l(t('Edit'), "admin/build/views/edit/$view->name");
 113        $item->ops[] = l(t('Export'), "admin/build/views/export/$view->name");
 114        $item->ops[] = l(t('Clone'), "admin/build/views/clone/$view->name");
 115      }
 116      if ($view->type != t('Default')) {
 117        $text = $view->type == t('Overridden') ? t('Revert') : t('Delete');
 118        $item->ops[] = l($text, "admin/build/views/delete/$view->name");
 119      }
 120      else {
 121        if (empty($view->disabled)) {
 122          $item->ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination() . '&token=' . $token_disable));
 123        }
 124        else {
 125          $item->ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination() . '&token=' . $token_enable));
 126        }
 127      }
 128  
 129      $item->ops = implode(' | ', $item->ops);
 130      if (empty($view->display)) {
 131        $item->path = t('Warning! Broken view!');
 132      }
 133      else {
 134        $item->path = $raw_path = $view->get_path();
 135        $item->path = $item->path && empty($view->disabled) && strpos($item->path, '%') === FALSE ? l($item->path, $item->path) : check_plain($item->path);
 136      }
 137  
 138      $item->type = $view->type;
 139      $item->name = $view->name;
 140  
 141      if (!empty($view->tag)) {
 142        $item->tag = $view->tag;
 143      }
 144  
 145      $item->title = $view->get_title();
 146      $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken');
 147  
 148      $item->displays = array();
 149      foreach ($view->display as $display) {
 150        if (!empty($display->handler->definition['admin'])) {
 151          $item->displays[$display->handler->definition['admin']] = TRUE;
 152        }
 153      }
 154  
 155      if ($item->displays) {
 156        ksort($item->displays);
 157        $item->displays = implode(', ', array_keys($item->displays));
 158      }
 159  
 160      $item->description = check_plain($view->description);
 161      $item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled';
 162      $items[] = $item;
 163  
 164      $sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc');
 165  
 166      switch ($form_state['values']['order']) {
 167        case 'name':
 168        default:
 169          $sort .= strtolower($view->name);
 170          break;
 171        case 'title':
 172          $sort .= strtolower($item->title);
 173          break;
 174        case 'path':
 175          $sort .= strtolower($raw_path); // $path;
 176          break;
 177        case 'type':
 178          $sort .= $view->type . $view->name;
 179          break;
 180        case 'tag':
 181          $sort .= strtolower($view->tag);
 182          break;
 183        case 'desc':
 184          $sort .= strtolower($view->description);
 185          break;
 186      }
 187  
 188      $sorts[] = $sort;
 189    }
 190  
 191    if ($form_state['values']['sort'] == 'desc') {
 192      arsort($sorts);
 193    }
 194    else {
 195      asort($sorts);
 196    }
 197  
 198    $i = array();
 199    foreach ($sorts as $id => $title) {
 200      $i[] = $items[$id];
 201    }
 202  
 203    views_add_css('views-list');
 204    $vars['views'] = $i;
 205  
 206    $getting_started = theme('advanced_help_topic', 'views', 'getting-started', 'title');
 207    if (!$getting_started) {
 208      $getting_started = t('Install the advanced help module for the getting started');
 209    }
 210  
 211    $vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started));
 212  }
 213  
 214  /**
 215   * Provide a form for sorting and filtering the list of views.
 216   */
 217  function views_ui_list_views_form(&$form_state) {
 218    if (!variable_get('clean_url', FALSE)) {
 219      $form['q'] = array(
 220        '#type' => 'hidden',
 221        '#value' => $_GET['q'],
 222      );
 223    }
 224  
 225    $all = array('all' => t('<All>'));
 226    $none = array('none' => t('<None>'));
 227  
 228    $form['type'] = array(
 229      '#type' => 'select',
 230      '#title' => t('Storage'),
 231      '#options' => array(
 232        'all' => t('<All>'),
 233        t('Normal') => t('Normal'),
 234        t('Default') => t('Default'),
 235        t('Overridden') => t('Overridden'),
 236      ),
 237      '#default_value' => 'all',
 238    );
 239  
 240    $bases = array();
 241    foreach (views_fetch_base_tables() as $table => $info) {
 242      $bases[$table] = $info['title'];
 243    }
 244  
 245    $form['base'] = array(
 246      '#type' => 'select',
 247      '#title' => t('Type'),
 248      '#options' => array_merge($all, $bases),
 249      '#default_value' => 'all',
 250    );
 251  
 252    $tags = array();
 253  
 254    $extras = array();
 255    foreach ($form_state['views'] as $name => $view) {
 256      if (!empty($view->tag)) {
 257        $tags[$view->tag] = $view->tag;
 258      }
 259    }
 260  
 261    asort($tags);
 262  
 263    $form['tag'] = array(
 264      '#type' => 'select',
 265      '#title' => t('Tag'),
 266      '#options' => array_merge($all, $none, $tags),
 267      '#default_value' => 'all',
 268    );
 269  
 270    $displays = array();
 271    foreach (views_fetch_plugin_data('display') as $id => $info) {
 272      if (!empty($info['admin'])) {
 273        $displays[$id] = $info['admin'];
 274      }
 275    }
 276  
 277    asort($displays);
 278  
 279    $form['display'] = array(
 280      '#type' => 'select',
 281      '#title' => t('Displays'),
 282      '#options' => array_merge($all, $displays),
 283      '#default_value' => 'all',
 284    );
 285  
 286    $form['order'] = array(
 287      '#type' => 'select',
 288      '#title' => t('Sort by'),
 289      '#options' => array(
 290        'name' => t('Name'),
 291        'title' => t('Title'),
 292        'tag' => t('Tag'),
 293        'path' => t('Path'),
 294        'type' => t('Type'),
 295        'desc' => t('Description'),
 296      ),
 297      '#default_value' => 'name',
 298    );
 299  
 300    $form['sort'] = array(
 301      '#type' => 'select',
 302      '#title' => t('Order'),
 303      '#options' => array(
 304        'asc' => t('Up'),
 305        'desc' => t('Down'),
 306      ),
 307      '#default_value' => 'asc',
 308    );
 309  
 310    $form['submit'] = array(
 311      '#name' => '', // so it won't in the $_GET args
 312      '#type' => 'submit',
 313      '#id' => 'edit-views-apply',
 314      '#value' => t('Apply'),
 315    );
 316  
 317    if (!empty($_SESSION['views']['#admin'])) {
 318      $form['reset'] = array(
 319        '#type' => 'submit',
 320        '#id' => 'edit-views-reset',
 321        '#value' => t('Reset'),
 322      );
 323    }
 324  
 325    $form['#theme'] = array('views_ui_list_views_form');
 326    return $form;
 327  }
 328  
 329  function theme_views_ui_list_views_form($form) {
 330    // Don't render these:
 331    unset($form['form_id']);
 332    unset($form['form_build_id']);
 333    unset($form['form_token']);
 334    return drupal_render($form);
 335  }
 336  
 337  /**
 338   * Page callback for the live preview.
 339   *
 340   * @todo make this use a template
 341   */
 342  function views_ui_preview($js, $view) {
 343    // Take off the items we know so that we can have just the args passed
 344    // in for later use.
 345    $func_args = func_get_args();
 346    array_shift($func_args); // $js
 347    array_shift($func_args); // $view
 348    $display_id = (count($func_args)) ? array_shift($func_args) : 'default';
 349  
 350    $form_state = array(
 351      'display_id' => $display_id,
 352      'view_args' => $func_args ? implode('/', $func_args) : '',
 353      'rerender' => TRUE,
 354      'no_redirect' => TRUE,
 355      'view' => &$view,
 356      'ajax' => $js
 357    );
 358  
 359    $output = drupal_build_form('views_ui_preview_form', $form_state);
 360    $args = array();
 361    if (isset($form_state['view_args']) && $form_state['view_args'] !== '') {
 362      $args = explode('/', $form_state['view_args']);
 363    }
 364  
 365    $errors = $view->validate();
 366    if ($errors === TRUE) {
 367      $view->ajax = $js;
 368      $view->live_preview = TRUE;
 369  
 370      // Store the current view URL for later use:
 371      $view->set_display($form_state['display_id']);
 372      $view->set_arguments($args);
 373  
 374      if ($view->display_handler->get_option('path')) {
 375        $path = $view->get_url();
 376      }
 377  
 378      // Make view links come back to preview.
 379      $view->override_path = 'admin/build/views/nojs/preview/' . $view->name . '/' . $form_state['display_id'];
 380  
 381      // also override $_GET['q'] so we get the pager
 382      $_GET['q'] = $view->override_path;
 383      if ($form_state['view_args']) {
 384        $_GET['q'] .= '/' . $form_state['view_args'];
 385      }
 386  
 387      $preview = $view->preview($form_state['display_id'], $args);
 388  
 389      // Get information from the preview for display.
 390      if (!empty($view->build_info['query'])) {
 391        $rows = array();
 392        $query = db_prefix_tables($view->build_info['query']);
 393        if ($view->build_info['query_args']) {
 394          _db_query_callback($view->build_info['query_args'], TRUE);
 395          $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
 396        }
 397        $rows[] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain($query) . '</pre>');
 398        if (!empty($view->additional_queries)) {
 399          $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
 400          foreach ($view->additional_queries as $query) {
 401            if ($queries) {
 402              $queries .= "\n";
 403            }
 404            $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . check_plain($query[0]);
 405          }
 406  
 407          $rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
 408        }
 409  
 410        $rows[] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title()));
 411        if (isset($path)) {
 412          $path = l($path, $path);
 413        }
 414        else {
 415          $path = t('This display has no path.');
 416        }
 417  
 418        $rows[] = array('<strong>' . t('Path') . '</strong>', $path);
 419  
 420        $rows[] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100)));
 421        $rows[] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100)));
 422        $rows[] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($view->render_time * 100000) / 100)));
 423        drupal_alter('views_preview_info', $rows, $view);
 424  
 425        $info = theme('table', array(), $rows);
 426      }
 427      else {
 428        $info = theme('table', array(), array(array('<strong>' . t('Query') . '</strong>', t('No query was run'))));
 429      }
 430    }
 431    else {
 432      foreach ($errors as $error) {
 433        drupal_set_message($error, 'error');
 434      }
 435      $preview = t('Unable to preview due to validation errors.');
 436      $info = '';
 437    }
 438  
 439    $info = '<div class="views-query-info">' . $info . '</div>';
 440  
 441    if (variable_get('views_ui_query_on_top', FALSE)) {
 442      $output .= $info . $preview;
 443    }
 444    else {
 445      $output .= $preview . $info;
 446    }
 447  
 448    if (!$js) {
 449      views_add_css('views-admin');
 450      drupal_set_title($view->get_title());
 451      return $output;
 452    }
 453    else {
 454      views_include('ajax');
 455      $object = new stdClass();
 456      if (!empty($view->js_settings)) {
 457        $object->js = $view->js_settings;
 458      }
 459      $object->display = '';
 460      if ($messages = theme('status_messages')) {
 461        $object->display = '<div class="views-messages">' . $messages . '</div>';
 462      }
 463      $object->display .= $output;
 464      $object->title = $view->get_title();
 465      views_ajax_render($object);
 466    }
 467  }
 468  
 469  /**
 470   * Form for generating argument information for the live preview.
 471   */
 472  function views_ui_preview_form(&$form_state) {
 473    $view = &$form_state['view'];
 474    $view->init_display();
 475    $options = array();
 476    foreach ($view->display as $id => $display) {
 477      $options[$id] = $display->display_title;
 478    }
 479  
 480    $form['#attributes'] = array(
 481      'class' => 'clear-block',
 482    );
 483  
 484    $form['display_id'] = array(
 485      '#type' => 'select',
 486      '#title' => t('Display'),
 487      '#options' => $options,
 488      '#default_value' => $form_state['display_id'],
 489      '#id' => 'preview-display-id',
 490    );
 491  
 492    $form['args'] = array(
 493      '#type' => 'textfield',
 494      '#title' => t('Arguments'),
 495      '#default_value' => $form_state['view_args'],
 496      '#description' => t('Separate arguments with a / as though they were a URL path.'),
 497      '#id' => 'preview-args',
 498    );
 499  
 500    $form['preview'] = array(
 501      '#type' => 'submit',
 502      '#value' => t('Preview'),
 503      '#id' => 'preview-submit',
 504    );
 505  
 506  
 507    $form['live_preview'] = array(
 508      '#type' => 'checkbox',
 509      '#title' => t('Automatic live preview'),
 510      '#default_value' => !variable_get('views_ui_disable_live_preview', 0),
 511    );
 512  
 513    $form['#action'] = url("admin/build/views/nojs/preview/$view->name");
 514    return $form;
 515  }
 516  
 517  /**
 518   * Submit the preview form.
 519   *
 520   * This just takes the data and stores it on the form state in a
 521   * known location. The caller will be responsible for using it.
 522   */
 523  function views_ui_preview_form_submit(&$form, &$form_state) {
 524    $form_state['display_id'] = $form_state['values']['display_id'];
 525    $form_state['view_args'] = $form_state['values']['args'];
 526  }
 527  
 528  /**
 529   * Page callback to add a new view.
 530   */
 531  function views_ui_add_page() {
 532    $form_state = array(
 533      'view' => NULL
 534    );
 535  
 536    return drupal_build_form('views_ui_add_form', $form_state);
 537  }
 538  
 539  /**
 540   * Page callback to add a new view.
 541   */
 542  function views_ui_clone_page($view) {
 543    $form_state = array(
 544      'view' => $view->copy(),
 545    );
 546  
 547    drupal_set_title(t('Clone view %view', array('%view' => $view->name)));
 548    return drupal_build_form('views_ui_add_form', $form_state);
 549  }
 550  
 551  /**
 552   * Form constructor callback to create the views Add Form, phase 1.
 553   */
 554  function views_ui_add_form(&$form_state) {
 555    $view = $form_state['view'];
 556    $form = array();
 557  
 558    $form['name'] = array(
 559      '#type' => 'textfield',
 560      '#title' => t('View name'),
 561      '#description' => t('This is the unique name of the view. It must contain only alphanumeric characters and underscores; it is used to identify the view internally and to generate unique theming template names for this view. If overriding a module provided view, the name must not be changed or instead a new view will be created.'),
 562      '#required' => TRUE,
 563      '#maxlength' => 32,
 564      '#default_value' => $view ? $view->name : '',
 565      '#attributes' => array('dir'=>'ltr'),
 566    );
 567  
 568    $form['description'] = array(
 569      '#type' => 'textfield',
 570      '#title' => t('View description'),
 571      '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
 572      '#default_value' => $view ? $view->description : '',
 573    );
 574  
 575    $form['tag'] = array(
 576      '#type' => 'textfield',
 577      '#title' => t('View tag'),
 578      '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
 579      '#default_value' => $view ? $view->tag : '',
 580      '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
 581    );
 582  
 583    $base_tables = array();
 584    foreach (views_fetch_base_tables() as $table => $info) {
 585      $base_tables[$table] = $info['title'] . '<div class="description">' . $info['description'] . '</div>';
 586    }
 587  
 588    $form['base_table'] = array(
 589      '#type' => 'radios',
 590      '#title' => t('View type'),
 591      '#description' => t('The view type is the primary table for which information is being retrieved. The view type controls what arguments, fields, sort criteria and filters are available, so once this is set it <strong>cannot be changed</strong>.'),
 592      '#default_value' => $view ? $view->base_table : 'node',
 593      '#options' => $base_tables,
 594    );
 595  
 596    if ($view) {
 597      $form['base_table']['#disabled'] = TRUE;
 598    }
 599  
 600    $form['submit'] = array(
 601      '#type' => 'submit',
 602      '#value' => t('Next'),
 603      '#validate' => array('views_ui_add_form_validate'),
 604      '#submit' => array('views_ui_add_form_submit'),
 605    );
 606  
 607    return $form;
 608  }
 609  
 610  /**
 611   * Validate the add view form.
 612   */
 613  function views_ui_add_form_validate($form, &$form_state) {
 614    $name = $form_state['values']['name'];
 615  
 616    // View name must be alphanumeric or underscores, no other punctuation.
 617    if (preg_match('/[^a-zA-Z0-9_]/', $name)) {
 618      form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
 619    }
 620  
 621    // View name must already exist.
 622    $view = views_get_view($form_state['values']['name']);
 623    if ($view && $view->type != t('Default')) {
 624      form_error($form['name'], t('You must use a unique name for this view.'));
 625    }
 626  }
 627  
 628  /**
 629   * Process the add view form
 630   */
 631  function views_ui_add_form_submit($form, &$form_state) {
 632    $view = $form_state['view'] ? $form_state['view'] : views_new_view();
 633    $view->name = $form_state['values']['name'];
 634    $view->description = $form_state['values']['description'];
 635    $view->tag = $form_state['values']['tag'];
 636    if (empty($form['base_table']['#disabled'])) {
 637      $view->base_table = $form_state['values']['base_table'];
 638    }
 639  
 640    views_ui_cache_set($view);
 641    $form_state['redirect'] ='admin/build/views/edit/' . $view->name;
 642  }
 643  
 644  /**
 645   * Page to delete a view.
 646   */
 647  function views_ui_delete_confirm(&$form_state, $view) {
 648    $form_state['view'] = &$view;
 649    $form = array();
 650  
 651    $cancel = 'admin/build/views';
 652    if (!empty($_REQUEST['cancel'])) {
 653      $cancel = $_REQUEST['cancel'];
 654    }
 655  
 656    if ($view->type == t('Overridden')) {
 657      $title = t('Are you sure you want to revert the view %name?', array('%name' => $view->name));
 658      $desc = t('Reverting the view will delete the view that is in the database, reverting it to the original default view. Any changes you have made will be lost and cannot be recovered.');
 659      $button = t('Revert');
 660    }
 661    else {
 662      $title = t('Are you sure you want to delete the view %name?', array('%name' => $view->name));
 663      $desc = t('Deleting a view cannot be undone.');
 664      $button = t('Delete');
 665    }
 666  
 667    return confirm_form($form,
 668                    $title,
 669                    $cancel,
 670                    $desc,
 671                    $button,
 672                    t('Cancel'));
 673  }
 674  
 675  /**
 676   * Submit handler to delete a view.
 677   */
 678  function views_ui_delete_confirm_submit(&$form, &$form_state) {
 679    $form_state['view']->delete();
 680    views_object_cache_clear('view', $form_state['view']->name);
 681    drupal_set_message(t('The view has been deleted.'));
 682    $form_state['redirect'] = 'admin/build/views';
 683  }
 684  
 685  /**
 686   * Page to delete a view.
 687   */
 688  function views_ui_break_lock_confirm(&$form_state, $view) {
 689    $form_state['view'] = &$view;
 690    $form = array();
 691  
 692    if (empty($view->locked)) {
 693      return t('There is no lock on view %view to break.', array('%name' => $view->name));
 694    }
 695  
 696    $cancel = 'admin/build/views/edit/' . $view->name;
 697    if (!empty($_REQUEST['cancel'])) {
 698      $cancel = $_REQUEST['cancel'];
 699    }
 700  
 701    $account = user_load($view->locked->uid);
 702    return confirm_form($form,
 703                    t('Are you sure you want to break the lock on view %name?',
 704                    array('%name' => $view->name)),
 705                    $cancel,
 706                    t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', $account))),
 707                    t('Break lock'),
 708                    t('Cancel'));
 709  }
 710  
 711  /**
 712   * Submit handler to break_lock a view.
 713   */
 714  function views_ui_break_lock_confirm_submit(&$form, &$form_state) {
 715    db_query("DELETE FROM {views_object_cache} WHERE obj = 'view' AND name = '%s'", $form_state['view']->name);
 716    $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 717    drupal_set_message(t('The lock has been broken and you may now edit this view.'));
 718  }
 719  
 720  /**
 721   * The main view edit page
 722   */
 723  function views_ui_edit_page($view) {
 724    drupal_set_title(t('Edit view %view', array('%view' => $view->name)));
 725    $output = theme('views_ui_edit_view', $view);
 726    views_ui_check_advanced_help();
 727    return $output;
 728  }
 729  
 730  /**
 731   * Export a view for cut & paste.
 732   */
 733  function views_ui_export_page(&$form_state, $view) {
 734    $code = $view->export();
 735    $lines = substr_count($code, "\n");
 736    $form['code'] = array(
 737      '#type' => 'textarea',
 738      '#title' => $view->name,
 739      '#default_value' => $code,
 740      '#rows' => $lines,
 741    );
 742    return $form;
 743  }
 744  
 745  /**
 746   * Import a view from cut & paste
 747   */
 748  function views_ui_import_page(&$form_state) {
 749    $form['name'] = array(
 750      '#type' => 'textfield',
 751      '#title' => t('View name'),
 752      '#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.'),
 753    );
 754  
 755    $form['view'] = array(
 756      '#type' => 'textarea',
 757      '#title' => t('Paste view code here'),
 758      '#required' => TRUE,
 759    );
 760  
 761    $form['submit'] = array(
 762      '#type' => 'submit',
 763      '#value' => t('Import'),
 764      '#submit' => array('views_ui_import_submit'),
 765      '#validate' => array('views_ui_import_validate'),
 766    );
 767    return $form;
 768  }
 769  
 770  /**
 771   * Validate handler to import a view
 772   */
 773  function views_ui_import_validate($form, &$form_state) {
 774    $view = '';
 775    views_include('view');
 776    ob_start();
 777    eval($form_state['values']['view']);
 778    ob_end_clean();
 779  
 780    if (!is_object($view)) {
 781      return form_error($form['view'], t('Unable to interpret view code.'));
 782    }
 783  
 784    if (empty($view->api_version) || $view->api_version < 2) {
 785      // Check for some value that would only exist on a Views 1 view.
 786      if (isset($view->url) || isset($view->page) || isset($view->block)) {
 787        views_include('convert');
 788        $view = views1_import($view);
 789        drupal_set_message(t('You are importing a view created in Views version 1. You may need to adjust some parameters to work correctly in version 2.'), 'warning');
 790      }
 791      else {
 792        form_error($form['view'], t('That view is not compatible with this version of Views.'));
 793      }
 794    }
 795    elseif ($view->api_version > views_api_version()) {
 796      form_error($form['view'], t('That view is created for the version @import_version of views, but you only have @api_version', array(
 797        '@import_version' => $view->api_version,
 798        '@api_version' => views_api_version())));
 799    }
 800  
 801    // View name must be alphanumeric or underscores, no other punctuation.
 802    if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) {
 803      form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
 804    }
 805  
 806    if ($form_state['values']['name']) {
 807      $view->name = $form_state['values']['name'];
 808    }
 809  
 810    $test = views_get_view($view->name);
 811    if ($test && $test->type != t('Default')) {
 812      form_set_error('', t('A view by that name already exists; please choose a different name'));
 813    }
 814  
 815    $view->init_display();
 816  
 817    $broken = FALSE;
 818    // Make sure that all plugins and handlers needed by this view actually exist.
 819    foreach ($view->display as $id => $display) {
 820      if (empty($display->handler) || !empty($display->handler->broken)) {
 821        drupal_set_message(t('Display plugin @plugin is not available.', array('@plugin' => $display->display_plugin)), 'error');
 822        $broken = TRUE;
 823        continue;
 824      }
 825  
 826      $plugin = views_get_plugin('style', $display->handler->get_option('style_plugin'));
 827      if (!$plugin) {
 828        drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('style_plugin'))), 'error');
 829        $broken = TRUE;
 830      }
 831      else if ($plugin->uses_row_plugin()) {
 832        $plugin = views_get_plugin('row', $display->handler->get_option('row_plugin'));
 833        if (!$plugin) {
 834          drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('row_plugin'))), 'error');
 835          $broken = TRUE;
 836        }
 837      }
 838  
 839      foreach (views_object_types() as $type => $info) {
 840        $handlers = $display->handler->get_handlers($type);
 841        if ($handlers) {
 842          foreach ($handlers as $id => $handler) {
 843            if ($handler->broken()) {
 844              drupal_set_message(t('@type handler @table.@field is not available.', array(
 845                '@type' => $info['stitle'],
 846                '@table' => $handler->table,
 847                '@field' => $handler->field,
 848              )), 'error');
 849              $broken = TRUE;
 850            }
 851          }
 852        }
 853      }
 854    }
 855  
 856    if ($broken) {
 857      form_set_error('', t('Unable to import view.'));
 858    }
 859  
 860    $form_state['view'] = &$view;
 861  }
 862  
 863  /**
 864   * Submit handler for view import
 865   */
 866  function views_ui_import_submit($form, &$form_state) {
 867    // Store in cache and then go to edit.
 868    views_ui_cache_set($form_state['view']);
 869    $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 870  }
 871  
 872  /**
 873   * The main edit view form, which is really just a save/cancel/delete button.
 874   */
 875  function views_ui_edit_view_form(&$form_state, $view) {
 876    $form['buttons']['save'] = array(
 877      '#type' => 'submit',
 878      '#value' => t('Save'),
 879      '#validate' => array('views_ui_edit_view_form_validate'),
 880      '#submit' => array('views_ui_edit_view_form_submit'),
 881    );
 882  
 883    $form['buttons']['cancel'] = array(
 884      '#type' => 'submit',
 885      '#value' => t('Cancel'),
 886      '#submit' => array('views_ui_edit_view_form_cancel'),
 887    );
 888  
 889    if (is_numeric($view->vid)) {
 890      $form['buttons']['delete'] = array(
 891        '#type' => 'submit',
 892        '#value' => $view->type == t('Overridden') ? t('Revert') : t('Delete'),
 893        '#submit' => array('views_ui_edit_view_form_delete'),
 894      );
 895    }
 896  
 897    $form_state['view'] = &$view;
 898    return $form;
 899  }
 900  
 901  /**
 902   * Validate that a view is complete and whole.
 903   */
 904  function views_ui_edit_view_form_validate($form, &$form_state) {
 905    // Do not validate cancel or delete or revert.
 906    if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) {
 907      return;
 908    }
 909  
 910    $errors = $form_state['view']->validate();
 911    if ($errors !== TRUE) {
 912      foreach ($errors as $error) {
 913        form_set_error('', $error);
 914      }
 915    }
 916  }
 917  
 918  /**
 919   * Submit handler for the edit view form.
 920   */
 921  function views_ui_edit_view_form_submit($form, &$form_state) {
 922    // Go through and remove displayed scheduled for removal.
 923    foreach ($form_state['view']->display as $id => $display) {
 924      if (!empty($display->deleted)) {
 925        unset($form_state['view']->display[$id]);
 926      }
 927    }
 928  
 929    $form_state['view']->save();
 930    drupal_set_message(t('The view %name has been saved.', array('%name' => $form_state['view']->name)));
 931  
 932    // Make sure menu items get rebuilt as neces
 933    menu_rebuild();
 934  
 935    // Clear the views cache.
 936    cache_clear_all('*', 'cache_views');
 937  
 938    // Clear the page cache.
 939    cache_clear_all();
 940  
 941    // Remove this view from cache so we can edit it properly.
 942    views_object_cache_clear('view', $form_state['view']->name);
 943  }
 944  
 945  /**
 946   * Submit handler for the edit view form.
 947   */
 948  function views_ui_edit_view_form_cancel($form, &$form_state) {
 949    // Remove this view from cache so edits will be lost.
 950    views_object_cache_clear('view', $form_state['view']->name);
 951    if (empty($form['view']->vid)) {
 952      // I seem to have to drupal_goto here because I can't get fapi to
 953      // honor the redirect target. Not sure what I screwed up here.
 954      drupal_goto('admin/build/views');
 955    }
 956  }
 957  
 958  function views_ui_edit_view_form_delete($form, &$form_state) {
 959    unset($_REQUEST['destination']);
 960    // Redirect to the delete confirm page
 961    $form_state['redirect'] = array('admin/build/views/delete/' . $form_state['view']->name, 'cancel=admin/build/views/edit/' . $form_state['view']->name);
 962  }
 963  
 964  /**
 965   * Preprocess the view edit page.
 966   */
 967  function template_preprocess_views_ui_edit_view(&$vars) {
 968    $view = &$vars['view'];
 969  
 970    $vars['save_button'] = drupal_get_form('views_ui_edit_view_form', $view);
 971  
 972    $table = views_fetch_data($view->base_table);
 973    $vars['base_table'] = !empty($table['table']['base']['title']) ?
 974      $table['table']['base']['title'] : t('Unknown or missing table name');
 975  
 976    views_include('tabs');
 977    $tabs = new views_tabset;
 978  
 979    $vars['message'] = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
 980  
 981    if (!$view->set_display('default')) {
 982      drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error');
 983    }
 984  
 985    foreach ($view->display as $display) {
 986      list($title, $body) = views_ui_display_tab($view, $display);
 987      // The first display is the default.
 988      $tabs->set($display->id, $title, $body);
 989    }
 990  
 991    // This is the area that will render beneath the links
 992    $form_state = array(
 993      'view' => &$view,
 994      'ajax' => FALSE,
 995    );
 996  
 997    $display_button = drupal_build_form('views_ui_add_display_form', $form_state);
 998    $analyze_button = drupal_get_form('views_ui_analyze_view_button', $view);
 999    $tabs->add_extra($display_button . $analyze_button);
1000  
1001    $vars['tabs'] = $tabs->render();
1002  
1003    $form_state = array(
1004      'display_id' => 'default',
1005      'view_args' => '',
1006      'rerender' => FALSE,
1007      'no_redirect' => TRUE,
1008      'view' => &$view,
1009      'input' => array(),
1010    );
1011    $vars['preview'] = drupal_build_form('views_ui_preview_form', $form_state);
1012  
1013    $vars['locked'] = NULL;
1014    if (isset($view->locked) && is_object($view->locked)) {
1015      $account = user_load($view->locked->uid);
1016      $vars['locked'] = theme('username', $account);
1017      $vars['lock_age'] = format_interval(time() - $view->locked->updated);
1018      $vars['break'] = url('admin/build/views/break-lock/' . $view->name);
1019    }
1020  
1021    $vars['quick_links_raw'] = array(
1022      array(
1023        'title' => t('Export'),
1024        'alt' => t("Export this view"),
1025        'href' => "admin/build/views/export/$view->name",
1026      ),
1027      array(
1028        'title' => t('Clone'),
1029        'alt' => t("Create a copy of this view"),
1030        'href' => "admin/build/views/clone/$view->name",
1031      ),
1032    );
1033  
1034    $paths = array();
1035    foreach ($view->display as $id => $display) {
1036      if (!empty($display->handler) && $display->handler->has_path()) {
1037        $path = $display->handler->get_path();
1038        if (strpos($path, '%') === FALSE && !isset($paths[$path])) {
1039          $vars['quick_links_raw'][] = array(
1040            'title' => t('View "@display"', array('@display' => $display->display_title)),
1041            'alt' => t("Go to the real page for this display"),
1042            'href' => $path,
1043          );
1044          // Displays can have the same path; no point in showing more than one link.
1045          $paths[$path] = TRUE;
1046        }
1047      }
1048    }
1049  
1050    $vars['quick_links'] = theme('links', $vars['quick_links_raw']);
1051    views_add_css('views-admin');
1052    views_add_js('ajax');
1053    drupal_add_js('misc/jquery.form.js');
1054  
1055    // Also add any js files required by plugins:
1056    $plugins = views_fetch_plugin_data();
1057    foreach ($plugins as $type => $type_plugins) {
1058      foreach ($type_plugins as $name => $plugin) {
1059        if (!empty($plugin['js'])) {
1060          foreach ($plugin['js'] as $file) {
1061            drupal_add_js($file);
1062          }
1063        }
1064      }
1065    }
1066  
1067    $settings = array('views' => array('ajax' => array(
1068      'id' => '#views-ajax-pad',
1069      'title' => '#views-ajax-title',
1070      'defaultForm' => $vars['message'],
1071    )));
1072  
1073    drupal_add_js($settings, 'setting');
1074  }
1075  
1076  function template_preprocess_views_ui_edit_tab(&$vars) {
1077    $view = $vars['view'];
1078    $display = $vars['display'];
1079    $plugin = $display->handler->definition;
1080  
1081    $top = $left = $middle = $right = '';
1082  
1083    // If this form was submitted it was already handled, so force it not to
1084    // submit again.
1085  
1086    $vars['remove'] = '';
1087    if (empty($plugin['no remove'])) {
1088      if (!empty($_POST['form_id']) && $_POST['form_id'] == 'views_ui_remove_display_form') {
1089        unset($_POST['form_id']);
1090      }
1091      $form_state = array('view' => &$view, 'display_id' => $display->id, 'ajax' => FALSE);
1092      $vars['remove'] = drupal_build_form('views_ui_remove_display_form', $form_state);
1093    }
1094  
1095    // basic fields
1096    $vars['title'] = check_plain($display->display_title);
1097    $vars['description'] = check_plain($plugin['help']);
1098  
1099    // Special fields if tihs is the default display.
1100    $vars['default'] = ($display->id == 'default');
1101    $vars['details_class'] = views_ui_item_css('details');
1102    if (!empty($view->changed_sections['details'])) {
1103      $vars['details_changed'] = TRUE;
1104    }
1105  
1106    $tag = empty($view->tag) ? t('None') : $view->tag;
1107    $vars['details'] = t('Description') . '/' . t('Tag') . ': ' . l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' => 'views-ajax-link')));
1108  
1109    // Calculate options from display plugin.
1110    $options = $categories = array();
1111    $display->handler->options_summary($categories, $options);
1112  
1113    // Build all of the options we were returned and put them into the
1114    // category data fields.
1115    foreach ($options as $id => $option) {
1116      if (empty($categories[$option['category']]['data'])) {
1117        $categories[$option['category']]['data'] = array();
1118      }
1119      $categories[$option['category']]['data'][$id] = array();
1120      $data = &$categories[$option['category']]['data'][$id];
1121      $data['content'] = '';
1122      $data['links'] = '';
1123      $data['overridden'] = FALSE;
1124      $data['defaulted'] = FALSE;
1125  
1126      // If there are optional links, build them first so they float properly.
1127      if (!empty($option['links'])) {
1128        foreach ($option['links'] as $link_id => $link_value) {
1129          $data['links'] .= $display->handler->option_link($link_value, $link_id, 'views-button-configure');
1130        }
1131      }
1132      if (!empty($option['title'])) {
1133        $data['content'] .= $option['title'] . ': ';
1134      }
1135  
1136      $data['content'] .= $display->handler->option_link($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
1137      if (!empty($display->handler->options['defaults'][$id])) {
1138        $display_id = 'default';
1139        $data['defaulted'] = TRUE;
1140      }
1141      else {
1142        $display_id = $display->id;
1143        if (!$display->handler->is_default_display()) {
1144          if ($display->handler->defaultable_sections($id)) {
1145            $data['overridden'] = TRUE;
1146          }
1147        }
1148      }
1149      $data['class'] = views_ui_item_css($display_id . '-' . $id);
1150      if (!empty($view->changed_sections[$display_id . '-' . $id])) {
1151        $data['changed'] = TRUE;
1152      }
1153    }
1154  
1155    $vars['categories'] = $categories;
1156  
1157    // Add a help icon
1158    if (isset($plugin['help topic'])) {
1159      $vars['display_help_icon'] = theme('advanced_help_topic', $plugin['module'], $plugin['help topic']);
1160    }
1161    else {
1162      $vars['display_help_icon'] = '';
1163    }
1164  
1165    // Fetch style plugin info because it has some effect on how/what we render.
1166    $style_plugin = $display->handler->get_plugin();
1167  
1168    $vars['fields'] = '';
1169    $vars['fields'] = theme('views_ui_edit_item', 'field', $view, $display, !($style_plugin && $style_plugin->uses_fields()));
1170    $vars['relationships'] = theme('views_ui_edit_item', 'relationship', $view, $display);
1171    $vars['arguments'] = theme('views_ui_edit_item', 'argument', $view, $display);
1172    $vars['filters'] = theme('views_ui_edit_item', 'filter', $view, $display);
1173    $vars['sorts'] = theme('views_ui_edit_item', 'sort', $view, $display);
1174  }
1175  
1176  /**
1177   * Generate the summary output for a single display to render in a tab.
1178   */
1179  function views_ui_display_tab($view, $display) {
1180    if (isset($display->handler)) {
1181      $plugin = $display->handler->definition;
1182    }
1183    if (empty($plugin)) {
1184      $title = isset($display->display_title) ? $display->display_title : t('Invalid');
1185      return array($title, t("Error: Display @display refers to a plugin named '@plugin', but that plugin doesn't exist!", array('@display' => $display->id, '@plugin' => $display->display_plugin)));
1186  
1187      // @todo We can do a better 'plugin does not exist' tab.
1188    }
1189  
1190    // The display should always be initialized prior to this call.
1191    if (empty($display->handler)) {
1192      return FALSE;
1193    }
1194  
1195    $body = theme('views_ui_edit_tab', $view, $display);
1196    return array($display->display_title, $body);
1197  }
1198  
1199  /**
1200   * Add information about a section to a display.
1201   */
1202  function template_preprocess_views_ui_edit_item(&$vars) {
1203    $type = $vars['type'];
1204    $view = $vars['view'];
1205    $display = $vars['display'];
1206  
1207    $types = views_object_types();
1208  
1209    $vars['overridden'] = FALSE;
1210    $vars['defaulted'] = FALSE;
1211  
1212    if ($vars['no_fields']) {
1213      $vars['title'] = $types[$type]['title'];
1214      $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type);
1215      $vars['rearrange'] = NULL;
1216      $vars['add'] = NULL;
1217      return;
1218    }
1219  
1220    $vars['rearrange'] = l('<span>' . t('Rearrange') . '</span>', "admin/build/views/nojs/rearrange/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-rearrange views-ajax-link', 'title' => t('Rearrange')), 'html' => true));
1221  
1222    $vars['add'] = l('<span>' . t('Add') . '</span>', "admin/build/views/nojs/add-item/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-add views-ajax-link', 'title' => t('Add')), 'html' => true));
1223  
1224    if (!$display->handler->is_default_display()) {
1225      if (!$display->handler->is_defaulted($types[$type]['plural'])) {
1226        $vars['overridden'] = TRUE;
1227      }
1228      else {
1229        $vars['defaulted'] = TRUE;
1230      }
1231    }
1232  
1233    $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link')));
1234  //  $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link')));
1235  
1236    $fields = array();
1237  
1238    static $relationships = NULL;
1239    if (!isset($relationships)) {
1240      // Get relationship labels
1241      $relationships = array();
1242      // @todo: get_handlers()
1243      foreach ($display->handler->get_option('relationships') as $id => $relationship) {
1244        $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
1245        if (empty($handler)) {
1246          continue;
1247        }
1248        $handler->init($view, $relationship);
1249        $relationships[$id] = $handler->label();
1250      }
1251    }
1252  
1253    // @todo: get_handlers()
1254    foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
1255      $fields[$id] = array();
1256  
1257      $handler = views_get_handler($field['table'], $field['field'], $type);
1258      if (empty($handler)) {
1259        $fields[$id]['class'] = 'broken';
1260        $field_name = t('Broken/missing handler: @table > @field', array('@table' => $field['table'], '@field' => $field['field']));
1261        $fields[$id]['title'] = l($field_name, "admin/build/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link'), 'html' => TRUE));
1262        $fields[$id]['info'] = '';
1263        continue;
1264      }
1265      $handler->init($view, $field);
1266  
1267      $field_name = $handler->ui_name(TRUE);
1268      if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
1269        $field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name;
1270      }
1271  
1272      $fields[$id]['title'] = l($field_name, "admin/build/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link'), 'html' => TRUE));
1273      $fields[$id]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $id);
1274      if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $id])) {
1275        $fields[$id]['changed'] = TRUE;
1276      }
1277      $fields[$id]['info'] = $handler->admin_summary();
1278  
1279      if ($handler->has_extra_options()) {
1280        $fields[$id]['links'] = l('<span>' . t('Settings') . '</span>', "admin/build/views/nojs/config-item-extra/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Settings')), 'html' => true));
1281      }
1282  
1283      if ($handler->needs_style_plugin()) {
1284        $style_plugin = views_fetch_plugin_data('style', $handler->options['style_plugin']);
1285        $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title'];
1286        $pid = $id . '-style-plugin';
1287  
1288        if (!empty($style_plugin['uses options'])) {
1289          $fields[$pid]['links'] = l('<span>' . t('Change settings for this style') . '</span>', "admin/build/views/nojs/config-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Settings')), 'html' => true));
1290        }
1291  
1292        $fields[$pid]['title'] = ' ' . t('&nbsp; Style: !style', array('!style' => l($style_title, "admin/build/views/nojs/change-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link')))));
1293        $fields[$pid]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $pid);
1294        if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $pid])) {
1295          $fields[$pid]['changed'] = TRUE;
1296        }
1297        $fields[$pid]['info'] = '';
1298      }
1299    }
1300  
1301    $vars['fields'] = $fields;
1302    $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type);
1303  }
1304  
1305  /**
1306   * Regenerate the tabs for AJAX updates.
1307   */
1308  function views_ui_regenerate_tabs(&$view, $display_id = NULL, $object = NULL) {
1309    if (empty($display_id)) {
1310      $displays = array_keys($view->display);
1311    }
1312    elseif (!is_array($display_id)) {
1313      $displays = array($display_id);
1314      if ($display_id != 'default') {
1315        $displays[] = 'default';
1316      }
1317    }
1318    else {
1319      $displays = $display_id;
1320    }
1321  
1322    if (!$view->set_display('default')) {
1323      views_ajax_render(t('Invalid display id found while regenerating tabs'));
1324    }
1325  
1326    if (!is_object($object)) {
1327      $object = new stdClass();
1328    }
1329  
1330    $object->replace = array();
1331    foreach ($displays as $id) {
1332      list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
1333      $object->replace['#views-tab-' . $id] = $body;
1334      $object->replace['#views-tab-title-' . $id] = check_plain($title);
1335    }
1336  
1337    if (!empty($view->changed)) {
1338      $object->changed = TRUE;
1339    }
1340  
1341    views_ajax_render($object);
1342  }
1343  
1344  /**
1345   * Provide standard buttons for the forms to make it easy. Also provide
1346   * a hidden op operator because the forms plugin doesn't seem to properly
1347   * provide which button was clicked.
1348   */
1349  function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) {
1350    $form['buttons'] = array(
1351      '#prefix' => '<div class="clear-block"><div class="form-buttons">',
1352      '#suffix' => '</div></div>',
1353    );
1354  
1355    if (empty($name)) {
1356      $name = t('Update');
1357    }
1358    // remove default validate handler
1359    $form['#validate'] = array();
1360  
1361    if (empty($form_state['ok_button'])) {
1362      // but be sure submit button validates!
1363      $form['buttons']['submit'] = array(
1364        '#type' => 'submit',
1365        '#value' => $name,
1366        '#submit' => array($form_id . '_submit'),
1367        '#validate' => array('views_ui_standard_submit', $form_id . '_validate'),
1368      );
1369    }
1370  
1371    $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : 'views_ui_standard_cancel';
1372    $form['buttons']['cancel'] = array(
1373      '#type' => 'submit',
1374      '#value' => empty($form_state['ok_button']) ? t('Cancel') : t('Ok'),
1375      '#submit' => array($cancel_submit),
1376      '#validate' => array(),
1377    );
1378  
1379    if ($third) {
1380      if (empty($submit)) {
1381        $submit = 'third';
1382      }
1383      $third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : 'views_ui_standard_cancel';
1384  
1385      $form['buttons'][$submit] = array(
1386        '#type' => 'submit',
1387        '#value' => $third,
1388        '#validate' => array(),
1389        '#submit' => array($third_submit),
1390      );
1391    }
1392  
1393    // Compatibility, to be removed later:
1394    // We used to set these items on the form, but now we want them on the $form_state:
1395    if (isset($form['#title'])) {
1396      $form_state['title'] = $form['#title'];
1397    }
1398    if (isset($form['#help_topic'])) {
1399      $form_state['help_topic'] = $form['#help_topic'];
1400    }
1401    if (isset($form['#help_module'])) {
1402      $form_state['help_module'] = $form['#help_module'];
1403    }
1404    if (isset($form['#url'])) {
1405      $form_state['url'] = $form['#url'];
1406    }
1407    if (isset($form['#js'])) {
1408      if (!empty($form_state['js settings']) && is_array($form_state['js settings'])) {
1409        $form_state['js settings'] = array_merge($form_state['js settings'], $form['#js']);
1410      }
1411      else {
1412        $form_state['js settings'] = $form['#js'];
1413      }
1414    }
1415    if (isset($form['#section'])) {
1416      $form_state['#section'] = $form['#section'];
1417    }
1418    // Finally, we never want these cached -- our object cache does that for us.
1419    $form['#no_cache'] = TRUE;
1420  
1421    // If this isn't an ajaxy form, then we want to set the title.
1422    if (!empty($form['#title'])) {
1423      drupal_set_title($form['#title']);
1424    }
1425    views_add_css('views-admin');
1426  }
1427  
1428  /**
1429   * Basic submit handler applicable to all 'standard' forms
1430   */
1431  function views_ui_standard_submit($form, &$form_state) {
1432    if (!empty($form['#section'])) {
1433      $form_state['view']->changed_sections[$form['#section']] = TRUE;
1434    }
1435  }
1436  
1437  /**
1438   * Submit handler for cancel button
1439   */
1440  function views_ui_standard_cancel($form, &$form_state) {
1441    $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
1442  }
1443  
1444  // --------------------------------------------------------------------------
1445  // Various subforms for editing the pieces of a view.
1446  
1447  function views_ui_ajax_forms($key = NULL) {
1448    $forms = array(
1449      'display' => array(
1450        'form_id' => 'views_ui_edit_display_form',
1451        'args' => array('section'),
1452      ),
1453      'remove-display' => array(
1454        'form_id' => 'views_ui_remove_display_form',
1455        'args' => array(),
1456      ),
1457      'config-type' => array(
1458        'form_id' => 'views_ui_config_type_form',
1459        'args' => array('type'),
1460      ),
1461      'rearrange' => array(
1462        'form_id' => 'views_ui_rearrange_form',
1463        'args' => array('type'),
1464      ),
1465      'add-item' => array(
1466        'form_id' => 'views_ui_add_item_form',
1467        'args' => array('type'),
1468      ),
1469      'config-item' => array(
1470        'form_id' => 'views_ui_config_item_form',
1471        'args' => array('type', 'id'),
1472      ),
1473      'config-item-extra' => array(
1474        'form_id' => 'views_ui_config_item_extra_form',
1475        'args' => array('type', 'id'),
1476      ),
1477      'change-style' => array(
1478        'form_id' => 'views_ui_change_style_form',
1479        'args' => array('type', 'id'),
1480      ),
1481      'config-style' => array(
1482        'form_id' => 'views_ui_config_style_form',
1483        'args' => array('type', 'id'),
1484      ),
1485    );
1486  
1487    if ($key) {
1488      return !empty($forms[$key]) ? $forms[$key] : NULL;
1489    }
1490  
1491    return $forms;
1492  }
1493  
1494  /**
1495   * Build a form identifier that we can use to see if one form
1496   * is the same as another. Since the arguments differ slightly
1497   * we do a lot of spiffy concenation here.
1498   */
1499  function views_ui_build_identifier($key, $view, $display_id, $args) {
1500    $form = views_ui_ajax_forms($key);
1501    $identifier = implode('-', array($key, $view->name, $display_id));
1502  
1503    foreach ($form['args'] as $id) {
1504      $arg = (!empty($args)) ? array_shift($args) : NULL;
1505      $identifier .= '-' . $arg;
1506    }
1507    return $identifier;
1508  }
1509  
1510  /**
1511   * Build up a $form_state object suitable for use with drupal_build_form
1512   * based on known information about a form.
1513   */
1514  function views_ui_build_form_state($js, $key, &$view, $display_id, $args) {
1515    $form = views_ui_ajax_forms($key);
1516    // Build up form state
1517    $form_state = array(
1518      'form_key' => $key,
1519      'form_id' => $form['form_id'],
1520      'view' => &$view,
1521      'ajax' => $js,
1522      'display_id' => $display_id,
1523      'no_redirect' => TRUE,
1524    );
1525  
1526    foreach ($form['args'] as $id) {
1527      $form_state[$id] = (!empty($args)) ? array_shift($args) : NULL;
1528    }
1529  
1530    return $form_state;
1531  }
1532  
1533  /**
1534   * Create the URL for one of our standard AJAX forms based upon known
1535   * information about the form.
1536   */
1537  function views_ui_build_form_url($form_state) {
1538    $form = views_ui_ajax_forms($form_state['form_key']);
1539    $ajax = empty($form_state['ajax']) ? 'nojs' : 'ajax';
1540    $name = $form_state['view']->name;
1541    $url = "admin/build/views/$ajax/$form_state[form_key]/$name/$form_state[display_id]";
1542    foreach ($form['args'] as $arg) {
1543      $url .= '/' . $form_state[$arg];
1544    }
1545    return $url;
1546  }
1547  
1548  /**
1549   * Add another form to the stack; clicking 'update' will go to this form
1550   * rather than closing the ajax pad.
1551   */
1552  function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FALSE) {
1553    if (empty($view->stack)) {
1554      $view->stack = array();
1555    }
1556  
1557    $stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, &$view, $display_id, $args);
1558    if ($top) {
1559      array_unshift($view->stack, $stack);
1560    }
1561    else {
1562      $view->stack[] = $stack;
1563    }
1564  }
1565  
1566  /**
1567   * Generic entry point to handle forms.
1568   *
1569   * We do this for consistency and to make it easy to chain forms
1570   * together. This only works for forms that use both $view
1571   * and $display_id, so we have a couple of ajax forms that we don't
1572   * use with this system.
1573   */
1574  function views_ui_ajax_form($js, $key, $view, $display_id) {
1575    $form = views_ui_ajax_forms($key);
1576    if (empty($form)) {
1577      return drupal_not_found();
1578    }
1579  
1580    views_include('ajax');
1581    $args = func_get_args();
1582    // Remove the known args
1583    array_splice($args, 0, 4);
1584  
1585    $form_state = views_ui_build_form_state($js, $key, $view, $display_id, $args);
1586    // check to see if this is the top form of the stack. If it is, pop
1587    // it off; if it isn't, the user clicked somewhere else and the stack is
1588    // now irrelevant.
1589    if (!empty($view->stack)) {
1590      $identifier = views_ui_build_identifier($key, $view, $display_id, $args);
1591      $top = array_shift($view->stack);
1592      if (array_shift($top) != $identifier) {
1593        $view->stack = array();
1594      }
1595    }
1596  
1597    $output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
1598  
1599    if (!$output) {
1600      // Sometimes we need to re-generate the form for multi-step type operations.
1601      $object = NULL;
1602      if (!empty($view->stack)) {
1603        $stack = $view->stack; // copy so the next shift doesn't break the array
1604        $top = array_shift($stack);
1605        $top[0] = $js; // change identifier into $js setting
1606        $form_state = call_user_func_array('views_ui_build_form_state', $top);
1607        $form_state['input'] = array(); // this is a new form, make sure it
1608        // doesn't try to inherit $_POST info.
1609        if (!$js) {
1610          return drupal_goto(views_ui_build_form_url($form_state));
1611        }
1612        $object = views_ajax_form_wrapper($form_state['form_id'], $form_state);
1613        $object->url = url(views_ui_build_form_url($form_state));
1614      }
1615      else if (!$js) {
1616        // if nothing on the stack, non-js forms just go back to the main view editor.
1617        return drupal_goto("admin/build/views/edit/$view->name");
1618      }
1619      // regenerate all tabs because changes to the default tab could ripple.
1620      return views_ui_regenerate_tabs($view, NULL, $object);
1621    }
1622  
1623    return ($js) ? views_ajax_render($output) : $output;
1624  }
1625  
1626  /**
1627   * AJAX callback to add a display.
1628   */
1629  function views_ui_add_display($js, $view) {
1630    views_include('ajax');
1631    $form_state = array(
1632      'view' => &$view,
1633      'ajax' => $js,
1634    );
1635  
1636    $output = views_ajax_form_wrapper('views_ui_add_display_form', $form_state);
1637  
1638    if ($js) {
1639      // If we don't have an output object, it was submitted. Set up the submission.
1640      if (empty($output)) {
1641        $id = $form_state['id'];
1642  
1643        // Make sure the new display is active
1644        if (!$view->set_display('default')) {
1645          views_ajax_render(t('Unable to initialize default display'));
1646        }
1647  
1648        // Render the new display
1649        list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
1650  
1651        // Instruct the javascript on the browser to render the new tab.
1652        $output = new stdClass;
1653        $output->tab = array('#views-tab-' . $id => array('title' => $title, 'body' => $body));
1654      }
1655      // Render the command object. This automatically exits.
1656      views_ajax_render($output);
1657    }
1658  
1659    // But the non-js variant will return output if it didn't redirect us.
1660    return $output;
1661  }
1662  
1663  /**
1664   * Form to add a display to a view.
1665   */
1666  function views_ui_add_display_form(&$form_state) {
1667    $view = &$form_state['view'];
1668  
1669    $form['display']['display'] = array(
1670      '#type' => 'select',
1671      '#options' => views_fetch_plugin_names('display'),
1672      '#default_value' => 'page',
1673    );
1674  
1675    $form['display']['add_display'] = array(
1676      '#type' => 'submit',
1677      '#value' => t('Add display'),
1678      '#submit' => array('views_ui_add_display_form_submit'),
1679    );
1680  
1681    $form['#id'] = 'views-add-display-form';
1682    $form['#attributes'] = array('class' => 'views-ajax-form');
1683    $form['#action'] = url("admin/build/views/nojs/add-display/$view->name");
1684  
1685    return $form;
1686  }
1687  
1688  /**
1689   * Submit handler to add a display to a view.
1690   */
1691  function views_ui_add_display_form_submit($form, &$form_state) {
1692    // Create the new display
1693    $plugin = $form_state['values']['display'];
1694    $form_state['id'] = $form_state['view']->add_display($plugin);
1695  
1696    // Store in cache
1697    views_ui_cache_set($form_state['view']);
1698  
1699    // Send it back
1700    $form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['id']);
1701  }
1702  
1703  /**
1704   * Form to remove a display from a view.
1705   */
1706  function views_ui_remove_display_form(&$form_state) {
1707    $view = &$form_state['view'];
1708    $display_id = $form_state['display_id'];
1709  
1710    if (empty($view->display[$display_id]->deleted)) {
1711      $form['display'] = array(
1712        '#prefix' => '<div class="display-button remove-display">',
1713        '#suffix' => '</div>',
1714      );
1715      $form['remove_display'] = array(
1716        '#type' => 'submit',
1717        '#value' => t('Remove display'),
1718        '#submit' => array('views_ui_remove_display_form_submit'),
1719      );
1720    }
1721    else {
1722      $form['display'] = array(
1723        '#prefix' => '<div class="display-button restore-display">',
1724        '#suffix' => '</div>',
1725      );
1726      $form['restore_display'] = array(
1727        '#type' => 'submit',
1728        '#value' => t('Restore display'),
1729        '#submit' => array('views_ui_remove_display_form_restore'),
1730      );
1731    }
1732    $form['#action'] = url("admin/build/views/nojs/remove-display/$view->name/$display_id");
1733    $form['#attributes'] = array('class' => 'views-ajax-form');
1734  
1735    return $form;
1736  }
1737  
1738  /**
1739   * Submit handler to add a remove to a display from a view.
1740   */
1741  function views_ui_remove_display_form_submit($form, &$form_state) {
1742    // Create the new display
1743    $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$form_state['display_id']]->display_plugin);
1744    if (empty($plugin['no remove'])) {
1745      $id = $form_state['display_id'];
1746      $form_state['view']->display[$id]->deleted = TRUE;
1747  
1748      // Store in cache
1749      views_ui_cache_set($form_state['view']);
1750    }
1751  }
1752  
1753  /**
1754   * Submit handler to add a restore a removed display to a view.
1755   */
1756  function views_ui_remove_display_form_restore($form, &$form_state) {
1757    // Create the new display
1758    $id = $form_state['display_id'];
1759    $form_state['view']->display[$id]->deleted = FALSE;
1760  
1761    // Store in cache
1762    views_ui_cache_set($form_state['view']);
1763  }
1764  
1765  /**
1766   * Page callback to display analysis information on a view.
1767   */
1768  function views_ui_analyze_view($js, $view) {
1769    views_include('ajax');
1770    $form_state = array(
1771      'view' => &$view,
1772      'ajax' => $js,
1773    );
1774  
1775    $output = views_ajax_form_wrapper('views_ui_analyze_view_form', $form_state);
1776  
1777    if ($js) {
1778      // If we don't have an output object, it was submitted. Set up the submission.
1779      if (empty($output)) {
1780        return views_ui_regenerate_tabs($view);
1781      }
1782      return views_ajax_render($output);
1783  
1784    }
1785    return $output;
1786  }
1787  
1788  /**
1789   * This form doesn't particularly do much; it's really just providing a link
1790   * but a button seems like it would be nicer here.
1791   *
1792   * It has no submit or anything, as we will never actually submit this form
1793   * where the form is placed.
1794   */
1795  function views_ui_analyze_view_button(&$form_state, $view) {
1796    $form['#action'] = url("admin/build/views/nojs/analyze/$view->name");
1797    $form['#attributes'] = array('class' => 'views-ajax-form');
1798    $form['submit'] = array(
1799      '#type' => 'submit',
1800      '#value' => t('Analyze'),
1801    );
1802  
1803    return $form;
1804  }
1805  
1806  /**
1807   * Form constructor callback to display analysis information on a view
1808   */
1809  function views_ui_analyze_view_form(&$form_state) {
1810    $view = &$form_state['view'];
1811  
1812    $form['#title'] = t('View analysis');
1813    $form['#section'] = 'analyze';
1814  
1815    views_include('analyze');
1816    $messages = views_analyze_view($view);
1817  
1818    $form['analysis'] = array(
1819      '#prefix' => '<div class="form-item">',
1820      '#suffix' => '</div>',
1821      '#value' => views_analyze_format_result($view, $messages),
1822    );
1823  
1824    // Inform the standard button function that we want an OK button.
1825    $form_state['ok_button'] = TRUE;
1826    views_ui_standard_form_buttons($form, $form_state, 'views_ui_analyze_view_form');
1827    return $form;
1828  }
1829  
1830  /**
1831   * Submit handler for views_ui_analyze_view_form
1832   */
1833  function views_ui_analyze_view_form_submit($form, &$form_state) {
1834    $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
1835  }
1836  
1837  /**
1838   * Page callback to edit details of a view.
1839   */
1840  function views_ui_edit_details($js, $view) {
1841    views_include('ajax');
1842    $form_state = array(
1843      'view' => &$view,
1844      'ajax' => $js,
1845    );
1846  
1847    $output = views_ajax_form_wrapper('views_ui_edit_details_form', $form_state);
1848  
1849    if ($js) {
1850      // If we don't have an output object, it was submitted. Set up the submission.
1851      if (empty($output)) {
1852        return views_ui_regenerate_tabs($view);
1853      }
1854      return views_ajax_render($output);
1855  
1856    }
1857    return $output;
1858  }
1859  
1860  /**
1861   * Form constructor callback to edit details of a view
1862   */
1863  function views_ui_edit_details_form(&$form_state) {
1864    $view = &$form_state['view'];
1865  
1866    $form['#title'] = t('View details');
1867    $form['#section'] = 'details';
1868  
1869    $form['description'] = array(
1870      '#type' => 'textfield',
1871      '#title' => t('View description'),
1872      '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
1873      '#default_value' => $view->description,
1874    );
1875  
1876    $form['tag'] = array(
1877      '#type' => 'textfield',
1878      '#title' => t('View tag'),
1879      '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
1880      '#default_value' => $view->tag,
1881      '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
1882    );
1883  
1884    views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form');
1885    return $form;
1886  }
1887  
1888  /**
1889   * Submit handler for views_ui_edit_details_form
1890   */
1891  function views_ui_edit_details_form_submit($form, &$form_state) {
1892    $form_state['view']->description = $form_state['values']['description'];
1893    $form_state['view']->tag = $form_state['values']['tag'];
1894    views_ui_cache_set($form_state['view']);
1895    $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
1896  }
1897  
1898  /**
1899   * Form constructor callback to edit display of a view
1900   */
1901  function views_ui_edit_display_form(&$form_state) {
1902    $view = &$form_state['view'];
1903    $display_id = $form_state['display_id'];
1904    $section = $form_state['section'];
1905  
1906    if (!$view->set_display($display_id)) {
1907      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
1908    }
1909    $display = &$view->display[$display_id];
1910  
1911    // Get form from the handler.
1912    $display->handler->options_form($form, $form_state);
1913    $name = NULL;
1914    if (isset($form_state['update_name'])) {
1915      $name = $form_state['update_name'];
1916    }
1917  
1918    views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_display_form', $name);
1919    return $form;
1920  }
1921  
1922  /**
1923   * Validate handler for views_ui_edit_display_form
1924   */
1925  function views_ui_edit_display_form_validate($form, &$form_state) {
1926    $display = &$form_state['view']->display[$form_state['display_id']];
1927    $display->handler->options_validate($form, $form_state);
1928  }
1929  
1930  /**
1931   * Submit handler for views_ui_edit_display_form
1932   */
1933  function views_ui_edit_display_form_submit($form, &$form_state) {
1934    $display = &$form_state['view']->display[$form_state['display_id']];
1935    $display->handler->options_submit($form, $form_state);
1936  
1937    views_ui_cache_set($form_state['view']);
1938  }
1939  
1940  /**
1941   * Override handler for views_ui_edit_display_form
1942   */
1943  function views_ui_edit_display_form_override($form, &$form_state) {
1944    $display = &$form_state['view']->display[$form_state['display_id']];
1945    $display->handler->options_override($form, $form_state);
1946  
1947    views_ui_cache_set($form_state['view']);
1948    $form_state['rerender'] = TRUE;
1949    $form_state['rebuild'] = TRUE;
1950  }
1951  /**
1952   * Form to config items in the views UI.
1953   */
1954  function views_ui_config_type_form(&$form_state) {
1955    $view = &$form_state['view'];
1956    $display_id = $form_state['display_id'];
1957    $type = $form_state['type'];
1958  
1959    $types = views_object_types();
1960    if (!$view->set_display($display_id)) {
1961      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
1962    }
1963    $display = &$view->display[$display_id];
1964    $form['#title'] = check_plain($display->display_title) . ': ';
1965    $form['#title'] .= t('Configure @type', array('@type' => $types[$type]['ltitle']));
1966    $form['#section'] = $display_id . 'config-item';
1967  
1968    if ($display->handler->defaultable_sections($types[$type]['plural'])) {
1969      $form_state['section'] = $types[$type]['plural'];
1970      $display->handler->add_override_button($form, $form_state, $form_state['section']);
1971    }
1972  
1973    if (!empty($types[$type]['options']) && function_exists($types[$type]['options'])) {
1974      $options = $type . '_options';
1975      $form[$options] = array('#tree' => TRUE);
1976      $types[$type]['options']($form, $form_state);
1977    }
1978  
1979    $name = NULL;
1980    if (isset($form_state['update_name'])) {
1981      $name = $form_state['update_name'];
1982    }
1983  
1984    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_type_form', $name);
1985    return $form;
1986  }
1987  
1988  /**
1989   * Submit handler for type configuration form
1990   */
1991  function views_ui_config_type_form_submit($form, &$form_state) {
1992    $types = views_object_types();
1993    $display = &$form_state['view']->display[$form_state['display_id']];
1994  
1995    // Store in cache
1996    views_ui_cache_set($form_state['view']);
1997  }
1998  
1999  /**
2000   * Configure settings particular to filters.
2001   */
2002  function views_ui_config_filters_form(&$form, &$form_state) {
2003  
2004  }
2005  
2006  /**
2007   * Form to rearrange items in the views UI.
2008   */
2009  function views_ui_rearrange_form(&$form_state) {
2010    $view = &$form_state['view'];
2011    $display_id = $form_state['display_id'];
2012    $type = $form_state['type'];
2013  
2014    $types = views_object_types();
2015    if (!$view->set_display($display_id)) {
2016      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2017    }
2018    $display = &$view->display[$display_id];
2019    $form['#title'] = check_plain($display->display_title) . ': ';
2020    $form['#title'] .= t('Rearrange @type', array('@type' => $types[$type]['ltitle']));
2021    $form['#section'] = $display_id . 'rearrange-item';
2022  
2023    if ($display->handler->defaultable_sections($types[$type]['plural'])) {
2024      $form_state['section'] = $types[$type]['plural'];
2025      $display->handler->add_override_button($form, $form_state, $form_state['section']);
2026    }
2027  
2028    $count = 0;
2029  
2030    // Get relationship labels
2031    $relationships = array();
2032    // @todo: get_handlers()
2033    foreach ($display->handler->get_option('relationships') as $id => $relationship) {
2034      $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
2035      if (empty($handler)) {
2036        continue;
2037      }
2038      $handler->init($view, $relationship);
2039      $relationships[$id] = $handler->label();
2040    }
2041  
2042    // @todo: get_handlers()
2043    foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
2044      $form[$id] = array('#tree' => TRUE);
2045      $form[$id]['weight'] = array(
2046        '#type' => 'weight',
2047        '#delta' => 200,
2048        '#default_value' => ++$count,
2049      );
2050      $handler = views_get_handler($field['table'], $field['field'], $type);
2051      if ($handler) {
2052        $handler->init($view, $field);
2053        $name = $handler->ui_name() . ' ' . $handler->admin_summary();
2054        if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
2055          $name = '(' . $relationships[$field['relationship']] . ') ' . $name;
2056        }
2057  
2058        $form[$id]['name'] = array(
2059          '#value' => $name,
2060        );
2061      }
2062      else {
2063        $form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id)));
2064      }
2065      $form[$id]['removed'] = array(
2066        '#type' => 'checkbox',
2067        '#id' => 'views-removed-' . $id,
2068        '#attributes' => array('class' => 'views-remove-checkbox'),
2069        '#default_value' => 0,
2070      );
2071    }
2072  
2073    // Add javascript settings that will be added via $.extend for tabledragging
2074    $form['#js']['tableDrag']['arrange']['weight'][0] = array(
2075      'target' => 'weight',
2076      'source' => NULL,
2077      'relationship' => 'sibling',
2078      'action' => 'order',
2079      'hidden' => TRUE,
2080      'limit' => 0,
2081    );
2082  
2083    $name = NULL;
2084    if (isset($form_state['update_name'])) {
2085      $name = $form_state['update_name'];
2086    }
2087  
2088    views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_form');
2089    return $form;
2090  }
2091  
2092  /**
2093   * Turn the rearrange form into a proper table
2094   */
2095  function theme_views_ui_rearrange_form($form) {
2096    $rows = array();
2097    foreach (element_children($form) as $id) {
2098      if (isset($form[$id]['name'])) {
2099        $row = array();
2100        $row[] = drupal_render($form[$id]['name']);
2101        $form[$id]['weight']['#attributes']['class'] = 'weight';
2102        $row[] = drupal_render($form[$id]['weight']);
2103        $row[] = drupal_render($form[$id]['removed']) . l('<span>' . t('Remove') . '</span>', 'javascript:void()', array('attributes' => array('id' => 'views-remove-link-' . $id, 'class' => 'views-button-remove views-remove-link', 'alt' => t('Remove this item'), 'title' => t('Remove this item')), 'html' => true));
2104  
2105        $rows[] = array('data' => $row, 'class' => 'draggable', 'id' => 'views-row-' . $id);
2106      }
2107    }
2108    if (empty($rows)) {
2109      $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2'));
2110    }
2111  
2112    $header = array('', t('Weight'), t('Remove'));
2113    drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight');
2114    $output = drupal_render($form['override']);
2115    $output .= theme('table', $header, $rows, array('id' => 'arrange'));
2116    $output .= drupal_render($form);
2117    return $output;
2118  
2119  }
2120  
2121  /**
2122   * Submit handler for rearranging form
2123   */
2124  function views_ui_rearrange_form_submit($form, &$form_state) {
2125    $types = views_object_types();
2126    $display = &$form_state['view']->display[$form_state['display_id']];
2127  
2128    $old_fields = $display->handler->get_option($types[$form_state['type']]['plural']);
2129    $new_fields = $order = array();
2130  
2131    // Make an array with the weights
2132    foreach ($form_state['values'] as $field => $info) {
2133      // add each value that is a field with a weight to our list, but only if
2134      // it has had its 'removed' checkbox checked.
2135      if (is_array($info) && isset($info['weight']) && empty($info['removed'])) {
2136        $order[$field] = $info['weight'];
2137      }
2138    }
2139  
2140    // Sort the array
2141    asort($order);
2142  
2143    // Create a new list of fields in the new order.
2144    foreach (array_keys($order) as $field) {
2145      $new_fields[$field] = $old_fields[$field];
2146    }
2147    $display->handler->set_option($types[$form_state['type']]['plural'], $new_fields);
2148  
2149    // Store in cache
2150    views_ui_cache_set($form_state['view']);
2151  }
2152  
2153  /**
2154   * Form to add_item items in the views UI.
2155   */
2156  function views_ui_add_item_form(&$form_state) {
2157    $view = &$form_state['view'];
2158    $display_id = $form_state['display_id'];
2159    $type = $form_state['type'];
2160  
2161    if (!$view->set_display($display_id)) {
2162      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2163    }
2164    $display = &$view->display[$display_id];
2165  
2166    $types = views_object_types();
2167    $form['#title'] = check_plain($display->display_title) . ': ';
2168    $form['#title'] .= t('Add @type', array('@type' => $types[$type]['ltitle']));
2169    $form['#section'] = $display_id . 'add-item';
2170  
2171    // Figure out all the base tables allowed based upon what the relationships provide.
2172    $base_tables = $view->get_base_tables();
2173    $options = views_fetch_fields(array_keys($base_tables), $type);
2174  
2175    if (!empty($options)) {
2176      $groups = array('all' => t('<All>'));
2177      $form['group'] = array(
2178        '#type' => 'select',
2179        '#title' => t('Groups'),
2180        '#options' => array(),
2181        '#attributes' => array('class' => 'views-master-dependent'),
2182      );
2183  
2184      $form['name'] = array(
2185        '#prefix' => '<div class="views-radio-box form-checkboxes">',
2186        '#suffix' => '</div>',
2187        '#tree' => TRUE,
2188        '#default_value' => 'all',
2189      );
2190  
2191      // Group options first to simplify the DOM objects that Views
2192      // dependent JS will act upon.
2193      $grouped_options = array();
2194      foreach ($options as $key => $option) {
2195        $group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group']));
2196        $groups[$group] = $option['group'];
2197        $grouped_options[$group][$key] = $option;
2198      }
2199  
2200      foreach ($grouped_options as $group => $group_options) {
2201        $form['name'][$group . '_start'] = array('#type' => 'markup', '#value' => '<div class="views-dependent-all views-dependent-' . $group . '">');
2202        foreach ($group_options as $key => $option) {
2203          $form['name'][$key] = array(
2204            '#type' => 'checkbox',
2205            '#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
2206            '#description' => $option['help'],
2207            '#return_value' => $key,
2208          );
2209        }
2210        $form['name'][$group . '_end'] = array('#type' => 'markup', '#value' => '</div>');
2211      }
2212  
2213      $form['group']['#options'] = $groups;
2214    }
2215    else {
2216      $form['markup'] = array(
2217        '#value' => '<div class="form-item">' . t('There are no @types available to add.', array('@types' =>  $types[$type]['ltitle'])) . '</div>',
2218      );
2219    }
2220    views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add'));
2221  
2222    return $form;
2223  }
2224  
2225  /**
2226   * Submit handler for adding new item(s) to a view.
2227   */
2228  function views_ui_add_item_form_submit($form, &$form_state) {
2229    $type = $form_state['type'];
2230    $types = views_object_types();
2231  
2232    if (!empty($form_state['values']['name']) && is_array($form_state['values']['name'])) {
2233      // Loop through each of the items that were checked and add them to the view.
2234      foreach (array_keys(array_filter($form_state['values']['name'])) as $field) {
2235        list($table, $field) = explode('.', $field, 2);
2236        $id = $form_state['view']->add_item($form_state['display_id'], $type, $table, $field);
2237  
2238        // check to see if this type has settings, if so add the settings form first
2239        $handler = views_get_handler($table, $field, $type);
2240        if ($handler && $handler->has_extra_options()) {
2241          views_ui_add_form_to_stack('config-item-extra', $form_state['view'], $form_state['display_id'], array($type, $id));
2242        }
2243        // Then add the form to the stack
2244        views_ui_add_form_to_stack('config-item', $form_state['view'], $form_state['display_id'], array($type, $id));
2245      }
2246    }
2247  
2248    // Store in cache
2249    views_ui_cache_set($form_state['view']);
2250  }
2251  
2252  
2253  /**
2254   * Form to config_item items in the views UI.
2255   */
2256  function views_ui_config_item_form(&$form_state) {
2257    $view = &$form_state['view'];
2258    $display_id = $form_state['display_id'];
2259    $type = $form_state['type'];
2260    $id = $form_state['id'];
2261  
2262    $form = array('options' => array('#tree' => TRUE));
2263    if (!$view->set_display($display_id)) {
2264      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2265    }
2266    $item = $view->get_item($display_id, $type, $id);
2267  
2268    if ($item) {
2269      $handler = views_get_handler($item['table'], $item['field'], $type);
2270      if (empty($handler)) {
2271        $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
2272      }
2273      else {
2274        $handler->init($view, $item);
2275        $types = views_object_types();
2276  
2277        if ($view->display_handler->defaultable_sections($types[$type]['plural'])) {
2278          $form_state['section'] = $types[$type]['plural'];
2279          $view->display_handler->add_override_button($form['options'], $form_state, $form_state['section']);
2280        }
2281  
2282        // A whole bunch of code to figure out what relationships are valid for
2283        // this item.
2284        $relationships = $view->display_handler->get_option('relationships');
2285        $relationship_options = array();
2286  
2287        foreach ($relationships as $relationship) {
2288          // relationships can't link back to self. But also, due to ordering,
2289          // relationships can only link to prior relationships.
2290          if ($type == 'relationship' && $id == $relationship['id']) {
2291            break;
2292          }
2293          $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
2294          // ignore invalid/broken relationships.
2295          if (empty($relationship_handler)) {
2296            continue;
2297          }
2298  
2299          // If this relationship is valid for this type, add it to the list.
2300          $data = views_fetch_data($relationship['table']);
2301          $base = $data[$relationship['field']]['relationship']['base'];
2302          $base_fields = views_fetch_fields($base, $form_state['type']);
2303          if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
2304            $relationship_handler->init($view, $relationship);
2305            $relationship_options[$relationship['id']] = $relationship_handler->label();
2306          }
2307        }
2308  
2309        if (!empty($relationship_options)) {
2310          // Make sure the existing relationship is even valid. If not, force
2311          // it to none.
2312          $base_fields = views_fetch_fields($view->base_table, $form_state['type']);
2313          if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
2314            $relationship_options = array_merge(array('none' => t('Do not use a relationship')), $relationship_options);
2315          }
2316          $rel = empty($item['relationship']) ? 'none' : $item['relationship'];
2317          if (empty($relationship_options[$rel])) {
2318            // Pick the first relationship.
2319            $rel = key($relationship_options);
2320            // We want this relationship option to get saved even if the user
2321            // skips submitting the form.
2322            $view->set_item_option($display_id, $type, $id, 'relationship', $rel);
2323            $temp_view = $view->clone_view();
2324            views_ui_cache_set($temp_view);
2325          }
2326  
2327          $form['options']['relationship'] = array(
2328            '#type' => 'select',
2329            '#title' => t('Relationship'),
2330            '#options' => $relationship_options,
2331            '#default_value' => $rel,
2332          );
2333        }
2334        else {
2335          $form['options']['relationship'] = array(
2336            '#type' => 'value',
2337            '#value' => 'none',
2338          );
2339        }
2340  
2341        $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
2342        $form['#title'] .= t('Configure @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
2343  
2344        $form['#section'] = $display_id . '-' . $type . '-' . $id;
2345  
2346        // Get form from the handler.
2347        $handler->options_form($form['options'], $form_state);
2348        $form_state['handler'] = &$handler;
2349      }
2350  
2351      $name = NULL;
2352      if (isset($form_state['update_name'])) {
2353        $name = $form_state['update_name'];
2354      }
2355  
2356      views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove');
2357    }
2358    return $form;
2359  }
2360  
2361  /**
2362   * Submit handler for configing new item(s) to a view.
2363   */
2364  function views_ui_config_item_form_validate($form, &$form_state) {
2365    $form_state['handler']->options_validate($form['options'], $form_state);
2366  }
2367  
2368  /**
2369   * Submit handler for configing new item(s) to a view.
2370   */
2371  function views_ui_config_item_form_submit($form, &$form_state) {
2372    // Run it through the handler's submit function.
2373    $form_state['handler']->options_submit($form['options'], $form_state);
2374    $item = $form_state['handler']->options;
2375  
2376    // Unset a button
2377    unset($form_state['values']['options']['expose_button']);
2378  
2379    // Store the data we're given.
2380    foreach ($form_state['values']['options'] as $key => $value) {
2381      $item[$key] = $value;
2382    }
2383  
2384    // Store the item back on the view
2385    $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
2386  
2387    $handler = views_get_handler($item['table'], $item['field'], $form_state['type']);
2388    $handler->init($form_state['view'], $item);
2389    if ($handler && $handler->needs_style_plugin()) {
2390      views_ui_add_form_to_stack('change-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
2391    }
2392  
2393    // Write to cache
2394    views_ui_cache_set($form_state['view']);
2395  }
2396  
2397  /**
2398   * Submit handler for removing an item from a view
2399   */
2400  function views_ui_config_item_form_remove($form, &$form_state) {
2401    // Store the item back on the view
2402    $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], NULL);
2403  
2404    // Write to cache
2405    views_ui_cache_set($form_state['view']);
2406  }
2407  
2408  /**
2409   * Override handler for views_ui_edit_display_form
2410   */
2411  function views_ui_config_item_form_expose($form, &$form_state) {
2412    $item = &$form_state['handler']->options;
2413    // flip
2414    $item['exposed'] = empty($item['exposed']);
2415  
2416    // If necessary, set new defaults:
2417    if ($item['exposed']) {
2418      $form_state['handler']->expose_options();
2419    }
2420  
2421    $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
2422  
2423    views_ui_cache_set($form_state['view']);
2424    $form_state['rerender'] = TRUE;
2425    $form_state['rebuild'] = TRUE;
2426    $form_state['force_expose_options'] = TRUE;
2427  }
2428  
2429  /**
2430   * Form to config_item items in the views UI.
2431   */
2432  function views_ui_config_item_extra_form(&$form_state) {
2433    $view = &$form_state['view'];
2434    $display_id = $form_state['display_id'];
2435    $type = $form_state['type'];
2436    $id = $form_state['id'];
2437  
2438    $form = array('options' => array('#tree' => TRUE));
2439    if (!$view->set_display($display_id)) {
2440      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2441    }
2442    $item = $view->get_item($display_id, $type, $id);
2443  
2444    if ($item) {
2445      $handler = views_get_handler($item['table'], $item['field'], $type);
2446      if (empty($handler)) {
2447        $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
2448        break;
2449      }
2450      else {
2451        $handler->init($view, $item);
2452        $types = views_object_types();
2453  
2454        $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
2455        $form['#title'] .= t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
2456  
2457        $form['#section'] = $display_id . '-' . $type . '-' . $id;
2458  
2459        // Get form from the handler.
2460        $handler->extra_options_form($form['options'], $form_state);
2461          $form_state['handler'] = &$handler;
2462  
2463      }
2464  
2465      views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_extra_form');
2466    }
2467    return $form;
2468  }
2469  
2470  /**
2471   * Submit handler for configing new item(s) to a view.
2472   */
2473  function views_ui_config_item_extra_form_validate($form, &$form_state) {
2474    $form_state['handler']->extra_options_validate($form['options'], $form_state);
2475  }
2476  
2477  /**
2478   * Submit handler for configing new item(s) to a view.
2479   */
2480  function views_ui_config_item_extra_form_submit($form, &$form_state) {
2481    // Run it through the handler's submit function.
2482    $form_state['handler']->extra_options_submit($form['options'], $form_state);
2483    $item = $form_state['handler']->options;
2484  
2485    // Store the data we're given.
2486    foreach ($form_state['values']['options'] as $key => $value) {
2487      $item[$key] = $value;
2488    }
2489  
2490    // Store the item back on the view
2491    $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
2492  
2493    // Write to cache
2494    views_ui_cache_set($form_state['view']);
2495  }
2496  
2497  /**
2498   * Form to change_style items in the views UI.
2499   */
2500  function views_ui_change_style_form(&$form_state) {
2501    $view = &$form_state['view'];
2502    $display_id = $form_state['display_id'];
2503    $type = $form_state['type'];
2504    $id = $form_state['id'];
2505  
2506    $form = array('options' => array('#tree' => TRUE));
2507    if (!$view->set_display($display_id)) {
2508      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2509    }
2510    $item = $view->get_item($display_id, $type, $id);
2511  
2512    if ($item) {
2513      $handler = views_get_handler($item['table'], $item['field'], $type);
2514      if (empty($handler)) {
2515        $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
2516        break;
2517      }
2518      $handler->init($view, $item);
2519      $types = views_object_types();
2520      $form['#title'] = t('Change summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
2521  
2522      $form['#section'] = $display_id . '-' . $type . '-' . $id . '-style-plugin';
2523  
2524      $form['style_plugin'] =  array(
2525        '#type' => 'radios',
2526        '#options' => views_fetch_plugin_names('style', 'summary'),
2527        '#default_value' => $item['style_plugin'],
2528      );
2529  
2530      $form_state['handler'] = &$handler;
2531  
2532      views_ui_standard_form_buttons($form, $form_state, 'views_ui_change_style_form');
2533    }
2534    return $form;
2535  }
2536  
2537  function views_ui_change_style_form_validate($form, &$form_state) {
2538    // Run it through the handler's submit function.
2539    $form_state['handler']->options_validate($form['options'], $form_state);
2540  
2541    $plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
2542    if (!$plugin) {
2543      form_error($form['style_plugin'], t('Internal error: broken plugin.'));
2544    }
2545  }
2546  
2547  /**
2548   * Submit handler for configing new item(s) to a view.
2549   */
2550  function views_ui_change_style_form_submit($form, &$form_state) {
2551    // Run it through the handler's submit function.
2552    $form_state['handler']->options_submit($form['options'], $form_state);
2553    $item = $form_state['handler']->options;
2554  
2555    $plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
2556    if (!$plugin) {
2557      drupal_set_message(t('Internal error: broken plugin.'), 'error');
2558      return;
2559    }
2560  
2561    $plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]);
2562  
2563    // If changing style plugin, reset options to defaults.
2564    if (empty($item['style_plugin']) || $item['style_plugin'] != $form_state['values']['style_plugin']) {
2565      $item['style_options'] = $plugin->options;
2566    }
2567  
2568    // Store the data we're given.
2569    $item['style_plugin'] = $form_state['values']['style_plugin'];
2570  
2571    // Store the item back on the view
2572    $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
2573  
2574    if (!empty($plugin->definition['uses options'])) {
2575      views_ui_add_form_to_stack('config-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
2576    }
2577  
2578    // Write to cache
2579    views_ui_cache_set($form_state['view']);
2580  }
2581  
2582  /**
2583   * Form to config_style items in the views UI.
2584   */
2585  function views_ui_config_style_form(&$form_state) {
2586    $view = &$form_state['view'];
2587    $display_id = $form_state['display_id'];
2588    $type = $form_state['type'];
2589    $id = $form_state['id'];
2590  
2591    $form = array('options' => array('#tree' => TRUE));
2592    if (!$view->set_display($display_id)) {
2593      views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2594    }
2595    $item = $view->get_item($display_id, $type, $id);
2596  
2597    if ($item) {
2598      $handler = views_get_handler($item['table'], $item['field'], $type);
2599      if (empty($handler)) {
2600        $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
2601        break;
2602      }
2603      $handler->init($view, $item);
2604      $types = views_object_types();
2605  
2606      $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
2607      $form['#title'] .= t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
2608  
2609      $form['#section'] = $display_id . '-' . $type . '-style-options';
2610  
2611      $plugin = views_get_plugin('style', $item['style_plugin']);
2612      if ($plugin) {
2613        $form['style_options'] = array(
2614          '#tree' => TRUE,
2615        );
2616        $plugin->init($view, $view->display[$display_id], $item['style_options']);
2617  
2618        $plugin->options_form($form['style_options'], $form_state);
2619      }
2620  
2621      $form_state['handler'] = &$handler;
2622  
2623      views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_style_form');
2624    }
2625    return $form;
2626  }
2627  
2628  /**
2629   * Submit handler for configing new item(s) to a view.
2630   */
2631  function views_ui_config_style_form_submit($form, &$form_state) {
2632    // Run it through the handler's submit function.
2633    $form_state['handler']->options_submit($form['style_options'], $form_state);
2634    $item = $form_state['handler']->options;
2635  
2636    // Store the data we're given.
2637    $item['style_options'] = $form_state['values']['style_options'];
2638  
2639    // Store the item back on the view
2640    $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
2641  
2642    // Write to cache
2643    views_ui_cache_set($form_state['view']);
2644  }
2645  
2646  /**
2647   * Get a list of roles in the system.
2648   */
2649  function views_ui_get_roles() {
2650    static $roles = NULL;
2651    if (!isset($roles)) {
2652      $roles = array();
2653      $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
2654      while ($obj = db_fetch_object($result)) {
2655        $roles[$obj->rid] = $obj->name;
2656      }
2657    }
2658  
2659    return $roles;
2660  }
2661  
2662  /**
2663   * Get a css safe id for a particular section.
2664   */
2665  function views_ui_item_css($item) {
2666    return views_css_safe('views-item-' . $item);
2667  }
2668  
2669  /**
2670   * Page callback for the Views enable page.
2671   */
2672  function views_ui_enable_page($view) {
2673    if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-enable')) {
2674      $views_status = variable_get('views_defaults', array());
2675      $views_status[$view->name] = FALSE; // false is enabled
2676      variable_set('views_defaults', $views_status);
2677      views_invalidate_cache();
2678      menu_rebuild();
2679      drupal_goto('admin/build/views');
2680    }
2681    else {
2682      return drupal_access_denied();
2683    }
2684  }
2685  
2686  /**
2687   * Page callback for the Views enable page
2688   */
2689  function views_ui_disable_page($view) {
2690    if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-disable')) {
2691      $views_status = variable_get('views_defaults', array());
2692      $views_status[$view->name] = TRUE; // True is disabled
2693      variable_set('views_defaults', $views_status);
2694      views_invalidate_cache();
2695      menu_rebuild();
2696      drupal_goto('admin/build/views');
2697    }
2698    else {
2699      return drupal_access_denied();
2700    }
2701  }
2702  
2703  /**
2704   * Page callback for the tools - other page
2705   */
2706  function views_ui_admin_tools() {
2707    $form['clear_cache'] = array(
2708      '#type' => 'submit',
2709      '#value' => t("Clear Views' cache"),
2710      '#submit' => array('views_ui_tools_clear_cache'),
2711    );
2712  
2713    $form['views_sql_signature'] = array(
2714      '#type' => 'checkbox',
2715      '#title' => t('Add Views signature to all SQL queries'),
2716      '#description' => t("All Views-generated queries will include a special 'VIEWS' = 'VIEWS' string in the WHERE clause. This makes identifying Views queries in database server logs simpler, but should only be used when troubleshooting."),
2717      '#default_value' => variable_get('views_sql_signature', FALSE),
2718    );
2719  
2720    $form['views_skip_cache'] = array(
2721      '#type' => 'checkbox',
2722      '#title' => t('Disable views data caching'),
2723      '#description' => t("Views caches data about tables, modules and views available, to increase performance. By checking this box, Views will skip this cache and always rebuild this data when needed. This can have a serious performance impact on your site."),
2724      '#default_value' => variable_get('views_skip_cache', FALSE),
2725    );
2726  
2727    $form['views_hide_help_message'] = array(
2728      '#type' => 'checkbox',
2729      '#title' => t('Ignore missing advanced help module'),
2730      '#description' => t("Views uses the advanced help module to provide help text; if this module is not present Views will complain, unless this setting is checked."),
2731      '#default_value' => variable_get('views_hide_help_message', FALSE),
2732    );
2733  
2734    $form['views_ui_query_on_top'] = array(
2735      '#type' => 'checkbox',
2736      '#title' => t('Show query above live preview'),
2737      '#description' => t("The live preview feature will show you the output of the view you're creating, as well as the view. Check here to show the query and other information above the view; leave this unchecked to show that information below the view."),
2738      '#default_value' => variable_get('views_ui_query_on_top', FALSE),
2739    );
2740  
2741    $form['views_ui_disable_live_preview'] = array(
2742      '#type' => 'checkbox',
2743      '#title' => t('Disable automatic live preview'),
2744      '#description' => t("Don't automatically update the preview. This can speed up the editing of views a bit.'"),
2745      '#default_value' => variable_get('views_ui_disable_live_preview', 0),
2746    );
2747  
2748    $form['views_show_additional_queries'] = array(
2749      '#type' => 'checkbox',
2750      '#title' => t('Show other queries run during render during live preview'),
2751      '#description' => t("Drupal has the potential to run many queries while a view is being rendered. Checking this box will display every query run during view render as part of the live preview."),
2752      '#default_value' => variable_get('views_show_additional_queries', FALSE),
2753    );
2754  
2755    $form['views_no_hover_links'] = array(
2756      '#type' => 'checkbox',
2757      '#title' => t('Do not show hover links over views'),
2758      '#description' => t("To make it easier to administrate your views, Views provides 'hover' links to take you to the edit and export screen of a view whenever the view is used. This can be distracting on some themes, though; if it is problematic, you can turn it off here."),
2759      '#default_value' => variable_get('views_no_hover_links', FALSE),
2760    );
2761  
2762    $form['views_devel_output'] = array(
2763      '#type' => 'checkbox',
2764      '#title' => t('Enable views performance statistics via the Devel module'),
2765      '#description' => t("Check this to enable some Views query and performance statistics <em>if Devel is installed</em>."),
2766      '#default_value' => variable_get('views_devel_output', FALSE),
2767    );
2768  
2769    $form['views_no_javascript'] = array(
2770      '#type' => 'checkbox',
2771      '#title' => t('Disable javascript with Views'),
2772      '#description' => t("If you are having problems with the javascript, you can disable it here; the Views UI should degrade and still be usable without javascript, it just not as good."),
2773      '#default_value' => variable_get('views_no_javascript', FALSE),
2774    );
2775  
2776    $regions = system_region_list(variable_get('theme_default', 'garland'));
2777    $regions['watchdog'] = t('Watchdog');
2778  
2779    $form['views_devel_region'] = array(
2780      '#type' => 'select',
2781      '#title' => t('Page region to output performance statistics'),
2782      '#default_value' => variable_get('views_devel_region', 'footer'),
2783      '#options' => $regions,
2784    );
2785  
2786    $form['views_exposed_filter_any_label'] = array(
2787      '#type' => 'select',
2788      '#title' => t('Label for "Any" value on optional single-select exposed filters'),
2789      '#options' => array('old_any' => '<Any>', 'new_any' => t('- Any -')),
2790      '#default_value' => variable_get('views_exposed_filter_any_label', 'old_any'),
2791    );
2792  
2793    return system_settings_form($form);
2794  }
2795  
2796  /**
2797   * Submit hook to clear the views cache.
2798   */
2799  function views_ui_tools_clear_cache() {
2800    views_invalidate_cache();
2801    drupal_set_message(t('The cache has been cleared.'));
2802  }
2803  
2804  /**
2805   * Submit hook to clear Drupal's theme registry (thereby triggering
2806   * a templates rescan).
2807   */
2808  function views_ui_config_item_form_rescan($form, &$form_state) {
2809    drupal_rebuild_theme_registry();
2810  
2811    // The 'Theme: Information' page is about to be shown again. That page
2812    // analyzes the output of theme_get_registry(). However, this latter
2813    // function uses an internal cache (which was initialized before we
2814    // called drupal_rebuild_theme_registry()) so it won't reflect the
2815    // current state of our theme registry. The only way to clear that cache
2816    // is to re-initialize the theme system:
2817    unset($GLOBALS['theme']);
2818    init_theme();
2819  
2820    $form_state['rerender'] = TRUE;
2821    $form_state['rebuild'] = TRUE;
2822  }
2823  
2824  /**
2825   * Override handler for views_ui_edit_display_form
2826   */
2827  function views_ui_edit_display_form_change_theme($form, &$form_state) {
2828    // This is just a temporary variable.
2829    $form_state['view']->theme = $form_state['values']['theme'];
2830  
2831    views_ui_cache_set($form_state['view']);
2832    $form_state['rerender'] = TRUE;
2833    $form_state['rebuild'] = TRUE;
2834  }
2835  
2836  /**
2837   * Page callback for views tag autocomplete
2838   */
2839  function views_ui_autocomplete_tag($string = '') {
2840    $matches = array();
2841    // get matches from default views:
2842    views_include('view');
2843    $views = views_discover_default_views();
2844    foreach ($views as $view) {
2845      if (!empty($view->tag) && strpos($view->tag, $string) === 0) {
2846        $matches[$view->tag] = $view->tag;
2847      }
2848    }
2849  
2850    if ($string) {
2851      $result = db_query_range("SELECT DISTINCT tag FROM {views_view} WHERE LOWER(tag) LIKE LOWER('%s%%')", $string, 0, 10 - count($matches));
2852      while ($view = db_fetch_object($result)) {
2853        $matches[$view->tag] = check_plain($view->tag);
2854      }
2855    }
2856  
2857    drupal_json($matches);
2858  }
2859  
2860  // ------------------------------------------------------------------
2861  // Get information from the Views data
2862  
2863  function _views_weight_sort($a, $b) {
2864    if ($a['weight'] != $b['weight']) {
2865      return $a['weight'] < $b['weight'] ? -1 : 1;
2866    }
2867    if ($a['title'] != $b['title']) {
2868      return $a['title'] < $b['title'] ? -1 : 1;
2869    }
2870  
2871    return 0;
2872  }
2873  
2874  /**
2875   * Fetch a list of all base tables available
2876   *
2877   * @return
2878   *   A keyed array of in the form of 'base_table' => 'Description'.
2879   */
2880  function views_fetch_base_tables() {
2881    static $base_tables = array();
2882    if (empty($base_tables)) {
2883      $weights = array();
2884      $tables = array();
2885      $data = views_fetch_data();
2886      foreach ($data as $table => $info) {
2887        if (!empty($info['table']['base'])) {
2888          $tables[$table] = array(
2889            'title' => $info['table']['base']['title'],
2890            'description' => $info['table']['base']['help'],
2891            'weight' => !empty($info['table']['base']['weight']) ? $info['table']['base']['weight'] : 0,
2892          );
2893        }
2894      }
2895      uasort($tables, '_views_weight_sort');
2896      $base_tables = $tables;
2897    }
2898  
2899    return $base_tables;
2900  }
2901  
2902  function _views_sort_types($a, $b) {
2903    if ($a['group'] != $b['group']) {
2904      return $a['group'] < $b['group'] ? -1 : 1;
2905    }
2906  
2907    if ($a['title'] != $b['title']) {
2908      return $a['title'] < $b['title'] ? -1 : 1;
2909    }
2910  
2911    return 0;
2912  }
2913  
2914  /**
2915   * Fetch a list of all fields available for a given base type.
2916   *
2917   * @return
2918   *   A keyed array of in the form of 'base_table' => 'Description'.
2919   */
2920  function views_fetch_fields($base, $type) {
2921    static $fields = array();
2922    if (empty($fields)) {
2923      $data = views_fetch_data();
2924      $start = views_microtime();
2925      // This constructs this ginormous multi dimensional array to
2926      // collect the important data about fields. In the end,
2927      // the structure looks a bit like this (using nid as an example)
2928      // $strings['nid']['filter']['title'] = 'string'.
2929      //
2930      // This is constructed this way because the above referenced strings
2931      // can appear in different places in the actual data structure so that
2932      // the data doesn't have to be repeated a lot. This essentially lets
2933      // each field have a cheap kind of inheritance.
2934  
2935      foreach ($data as $table => $table_data) {
2936        $bases = array();
2937        $strings = array();
2938        $skip_bases = array();
2939        foreach ($table_data as $field => $info) {
2940          // Collect table data from this table
2941          if ($field == 'table') {
2942            // calculate what tables this table can join to.
2943            if (!empty($info['join'])) {
2944              $bases = array_keys($info['join']);
2945            }
2946            // And it obviously joins to itself.
2947            $bases[] = $table;
2948            continue;
2949          }
2950          foreach (array('field', 'sort', 'filter', 'argument', 'relationship') as $key) {
2951            if (!empty($info[$key])) {
2952              if (!empty($info[$key]['skip base'])) {
2953                foreach ((array) $info[$key]['skip base'] as $base_name) {
2954                  $skip_bases[$field][$key][$base_name] = TRUE;
2955                }
2956              }
2957              elseif (!empty($info['skip base'])) {
2958                foreach ((array) $info['skip base'] as $base_name) {
2959                  $skip_bases[$field][$key][$base_name] = TRUE;
2960                }
2961              }
2962              foreach (array('title', 'group', 'help', 'base') as $string) {
2963                // First, try the lowest possible level
2964                if (!empty($info[$key][$string])) {
2965                  $strings[$field][$key][$string] = $info[$key][$string];
2966                }
2967                // Then try the field level
2968                elseif (!empty($info[$string])) {
2969                  $strings[$field][$key][$string] = $info[$string];
2970                }
2971                // Finally, try the table level
2972                elseif (!empty($table_data['table'][$string])) {
2973                  $strings[$field][$key][$string] = $table_data['table'][$string];
2974                }
2975                else {
2976                  if ($string != 'base') {
2977                    $strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string));
2978                  }
2979                }
2980              }
2981            }
2982          }
2983        }
2984        foreach ($bases as $base_name) {
2985          foreach ($strings as $field => $field_strings) {
2986            foreach ($field_strings as $type_name => $type_strings) {
2987              if (empty($skip_bases[$field][$type_name][$base_name])) {
2988                $fields[$base_name][$type_name]["$table.$field"] = $type_strings;
2989              }
2990            }
2991          }
2992        }
2993      }
2994  //    vsm('Views UI data build time: ' . (views_microtime() - $start) * 1000 . ' ms');
2995    }
2996  
2997    // If we have an array of base tables available, go through them
2998    // all and add them together. Duplicate keys will be lost and that's
2999    // Just Fine.
3000    if (is_array($base)) {
3001      $strings = array();
3002      foreach ($base as $base_table) {
3003        if (isset($fields[$base_table][$type])) {
3004          $strings += $fields[$base_table][$type];
3005        }
3006      }
3007      uasort($strings, '_views_sort_types');
3008      return $strings;
3009    }
3010  
3011    if (isset($fields[$base][$type])) {
3012      uasort($fields[$base][$type], '_views_sort_types');
3013      return $fields[$base][$type];
3014    }
3015    return array();
3016  }
3017  
3018  /**
3019   * Fetch a list of all base tables available
3020   *
3021   * @param $type
3022   *   Either 'display', 'style' or 'row'
3023   * @param $key
3024   *   For style plugins, this is an optional type to restrict to. May be 'normal',
3025   *   'summary', 'feed' or others based on the neds of the display.
3026   * @param $base
3027   *   An array of possible base tables.
3028   *
3029   * @return
3030   *   A keyed array of in the form of 'base_table' => 'Description'.
3031   */
3032  function views_fetch_plugin_names($type, $key = NULL, $base = array()) {
3033    $data = views_fetch_plugin_data();
3034  
3035    $plugins[$type] = array();
3036  
3037    foreach ($data[$type] as $id => $plugin) {
3038      // Skip plugins that don't conform to our key.
3039      if ($key && (empty($plugin['type']) || $plugin['type'] != $key)) {
3040        continue;
3041      }
3042      if (empty($plugin['no ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
3043        $plugins[$type][$id] = $plugin['title'];
3044      }
3045    }
3046  
3047    if (!empty($plugins[$type])) {
3048      asort($plugins[$type]);
3049      return $plugins[$type];
3050    }
3051    // fall-through
3052    return array();
3053  }
3054  
3055  
3056  /**
3057   * Theme the form for the table style plugin
3058   */
3059  function theme_views_ui_style_plugin_table($form) {
3060    $output = drupal_render($form['description_markup']);
3061  
3062    $header = array(
3063      t('Field'),
3064      t('Column'),
3065      t('Separator'),
3066      array(
3067        'data' => t('Sortable'),
3068        'align' => 'center',
3069      ),
3070      array(
3071        'data' => t('Default sort'),
3072        'align' => 'center',
3073      ),
3074    );
3075    $rows = array();
3076    foreach (element_children($form['columns']) as $id) {
3077      $row = array();
3078      $row[] = drupal_render($form['info'][$id]['name']);
3079      $row[] = drupal_render($form['columns'][$id]);
3080      $row[] = drupal_render($form['info'][$id]['separator']);
3081      if (!empty($form['info'][$id]['sortable'])) {
3082        $row[] = array(
3083          'data' => drupal_render($form['info'][$id]['sortable']),
3084          'align' => 'center',
3085        );
3086        $row[] = array(
3087          'data' => drupal_render($form['default'][$id]),
3088          'align' => 'center',
3089        );
3090      }
3091      else {
3092        $row[] = '';
3093        $row[] = '';
3094      }
3095      $rows[] = $row;
3096    }
3097  
3098    // Add the special 'None' row.
3099    $rows[] = array(t('None'), '', '', '', array('align' => 'center', 'data' => drupal_render($form['default'][-1])));
3100  
3101    $output .= theme('table', $header, $rows);
3102    $output .= drupal_render($form);
3103    return $output;
3104  }
3105  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7