Skip to content
views_plugin_display.inc 90.4 KiB
Newer Older
David Rothstein's avatar
David Rothstein committed
// $Id: views_plugin_display.inc,v 1.27.4.58 2011/02/06 14:29:02 dereine Exp $
/**
 * @file
 * Contains the base display plugin.
 */

/**
 * @defgroup views_display_plugins Views' display plugins
 * @{
 * Display plugins control how Views interact with the rest of Drupal.
 *
 * They can handle creating Views from a Drupal page hook; they can
 * handle creating Views from a Drupal block hook. They can also
 * handle creating Views from an external module source, such as
 * a Panels pane, or an insert view, or a CCK field type.
 *
 * @see hook_views_plugins
 */

/**
 * The default display plugin handler. Display plugins handle options and
 * basic mechanisms for different output methods.
 *
 * @ingroup views_display_plugins
 */
class views_plugin_display extends views_plugin {
David Rothstein's avatar
David Rothstein committed
  /**
   * The top object of a view.
David Rothstein's avatar
David Rothstein committed
   * @var view
   */
  var $view = NULL;

  var $handlers = array();

  function init(&$view, &$display, $options = NULL) {
    $this->view = &$view;
    $this->display = &$display;

    // Make some modifications:
    if (!isset($options) && isset($display->display_options)) {
      $options = $display->display_options;
    }

    if ($this->is_default_display() && isset($options['defaults'])) {
      unset($options['defaults']);
    }

    $this->unpack_options($this->options, $options);

    // Translate changed settings:
    // Check if any of the previous values now managed by
    // pluggable pagers have been changed.
    // If yes, perform the conversion
    $items_per_page = $this->get_option('items_per_page');
    $offset = $this->get_option('offset');
    $type = $this->get_option('use_pager');
    if ((!empty($items_per_page) && $items_per_page != 10) || !empty($offset) || !empty($type)) {
      if (!$type) {
        $type = $items_per_page ? 'some' : 'none';
      }

      if ($type == 1) {
        $type = 'full';
      }

      $pager = array(
        'type' => $type,
        'options' => array(
          'offset' => $offset
        ),
      );

      if ($items_per_page) {
        $pager['options']['items_per_page'] = $items_per_page;
      }
      if ($id = $this->get_option('pager_element')) {
        $pager['options']['id'] = $id;
      }

      // Unset the previous options
      // After edit and save the view they will be erased
      $this->set_option('items_per_page', NULL);
      $this->set_option('offset', NULL);
      $this->set_option('use_pager', NULL);
      $this->set_option('pager', $pager);
    }

    // Plugable headers, footer and empty texts are
    // not compatible with previous version of views
    // This code converts old values into a configured handler for each area
    foreach (array('header', 'footer', 'empty') as $area) {
      $converted = FALSE;
      if (isset($this->options[$area]) && !is_array($this->options[$area])) {
        if (!empty($this->options[$area])) {
          $content = $this->get_option($area);
          if (!empty($content) && !is_array($content)) {
            $format = $this->get_option($area . '_format');
            $options = array(
              'id' => 'area',
              'table' => 'views',
              'field' => 'area',
              'label' => '',
              'relationship' => 'none',
              'group_type' => 'group',
              'content' => $content,
              'format' => !empty($format) ? $format : filter_default_format(),
            );

            if ($area != 'empty' && $empty = $this->get_option($area . '_empty')) {
              $options['empty'] = $empty;
            }
            $this->set_option($area, array('text' => $options));
            $converted = TRUE;
          }
        }
        // Ensure that options are at least an empty array
        if (!$converted) {
          $this->set_option($area, array());
        }
      }
    }

    // Convert distinct setting from display to query settings.
    $distinct = $this->get_option('distinct');
    if (!empty($distinct)) {
      $query_settings = $this->get_option('query');
      $query_settings['options']['distinct'] = $distinct;
      $this->set_option('query', $query_settings);
      // Clear the values
      $this->set_option('distinct', NULL);
    }
  }

  function destroy() {
    parent::destroy();

    foreach ($this->handlers as $type => $handlers) {
      foreach ($handlers as $id => $handler) {
        if (is_object($handler)) {
          $this->handlers[$type][$id]->destroy();
        }
      }
    }

    if (isset($this->default_display)) {
      unset($this->default_display);
    }
  }

  /**
   * Determine if this display is the 'default' display which contains
   * fallback settings
   */
  function is_default_display() { return FALSE; }

  /**
   * Determine if this display uses exposed filters, so the view
   * will know whether or not to build them.
   */
  function uses_exposed() {
    if (!isset($this->has_exposed)) {
      foreach ($this->handlers as $type => $value) {
        foreach ($this->view->$type as $id => $handler) {
          if ($handler->can_expose() && $handler->is_exposed()) {
            // one is all we need; if we find it, return true.
            $this->has_exposed = TRUE;
            return TRUE;
          }
        }
      }
      $pager = $this->get_plugin('pager');
      if (isset($pager) && $pager->uses_exposed()) {
        $this->has_exposed = TRUE;
        return TRUE;
      }
      $this->has_exposed = FALSE;
    }

    return $this->has_exposed;
  }

  /**
   * Determine if this display should display the exposed
   * filters widgets, so the view will know whether or not
   * to render them.
   *
   * Regardless of what this function
   * returns, exposed filters will not be used nor
   * displayed unless uses_exposed() returns TRUE.
   */
  function displays_exposed() {
    return TRUE;
  }

  /**
   * Does the display use AJAX?
   */
  function use_ajax() {
    if (!empty($this->definition['use ajax'])) {
      return $this->get_option('use_ajax');
    }
    return FALSE;
  }

  /**
   * Does the display have a pager enabled?
   */
  function use_pager() {
    $pager = $this->get_plugin('pager');
    if ($pager) {
      return $pager->use_pager();
    }
  }

  /**
   * Does the display have a more link enabled?
   */
  function use_more() {
    if (!empty($this->definition['use more'])) {
      return $this->get_option('use_more');
    }
    return FALSE;
  }

  /**
   * Does the display have a more link enabled?
   */
  function use_group_by() {
    return $this->get_option('group_by');
  }

  /**
   * Should the enabled display more link be shown when no more items?
   */
  function use_more_always() {
    if (!empty($this->definition['use more'])) {
      return $this->get_option('use_more_always');
    }
    return FALSE;
  }

  /**
   * Does the display have custom link text?
   */
  function use_more_text() {
    if (!empty($this->definition['use more'])) {
      return $this->get_option('use_more_text');
    }
    return FALSE;
  }

  /**
   * Can this display accept attachments?
   */
  function accept_attachments() {
David Rothstein's avatar
David Rothstein committed
    if (empty($this->definition['accept attachments'])) {
      return FALSE;
    }
    if (!empty($this->view->argument) && $this->get_option('hide_attachment_summary')) {
      foreach ($this->view->argument as $argument_id => $argument) {
        if ($argument->needs_style_plugin() && empty($argument->argument_validated)) {
          return FALSE;
        }
      }
    }
    return TRUE;
  }

  /**
   * Allow displays to attach to other views.
   */
  function attach_to($display_id) { }

  /**
   * Static member function to list which sections are defaultable
   * and what items each section contains.
   */
  function defaultable_sections($section = NULL) {
    $sections = array(
      'access' => array('access'),
      'cache' => array('cache'),
      'title' => array('title'),
Katherine Senzee's avatar
Katherine Senzee committed
      'enabled' => array('enabled'),
      'css_class' => array('css_class'),
      'use_ajax' => array('use_ajax'),
David Rothstein's avatar
David Rothstein committed
      'hide_attachment_summary' => array('hide_attachment_summary'),
      'query' => array('query'),
      'items_per_page' => array('items_per_page', 'offset', 'use_pager', 'pager_element'),
      'pager' => array('pager'),
      'use_more' => array('use_more', 'use_more_always', 'use_more_text'),
      'link_display' => array('link_display'),
      'exposed_block' => array('exposed_block'),
      'exposed_form' => array('exposed_form'),

      // Force these to cascade properly.
      'style_plugin' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
      'style_options' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
      'row_plugin' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
      'row_options' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),

      // These guys are special
      'header' => array('header'),
      'footer' => array('footer'),
      'empty' => array('empty'),
      'relationships' => array('relationships'),
      'fields' => array('fields'),
      'sorts' => array('sorts'),
      'arguments' => array('arguments'),
Katherine Senzee's avatar
Katherine Senzee committed
      'filters' => array('filters', 'filter_groups'),
Peter Wolanin's avatar
Peter Wolanin committed

    // If the display cannot use a pager, then we cannot default it.
    if (empty($this->definition['use pager'])) {
      unset($sections['pager']);
      unset($sections['items_per_page']);
    }

    if ($section) {
      if (!empty($sections[$section])) {
        return $sections[$section];
      }
    }
    else {
      return $sections;
    }
  }

  function option_definition() {
    $options = array(
      'defaults' => array(
        'default' => array(
          'access' => TRUE,
          'cache' => TRUE,
          'query' => TRUE,
          'title' => TRUE,
Katherine Senzee's avatar
Katherine Senzee committed
          'display_comment' => TRUE,
          'enabled' => TRUE,
          'css_class' => TRUE,

Katherine Senzee's avatar
Katherine Senzee committed
          'display_description' => FALSE,
          'use_ajax' => TRUE,
David Rothstein's avatar
David Rothstein committed
          'hide_attachment_summary' => TRUE,
          'items_per_page' => TRUE,
          'use_pager' => TRUE,
          'offset' => TRUE,
          'pager' => TRUE,
          'use_more' => TRUE,
          'use_more_always' => TRUE,
          'use_more_text' => TRUE,
          'exposed_block' => TRUE,
          'exposed_form' => TRUE,

          'link_display' => TRUE,
          'group_by' => TRUE,

          'style_plugin' => TRUE,
          'style_options' => TRUE,
          'row_plugin' => TRUE,
          'row_options' => TRUE,

          'header' => TRUE,
          'footer' => TRUE,
          'empty' => TRUE,

          'relationships' => TRUE,
          'fields' => TRUE,
          'sorts' => TRUE,
          'arguments' => TRUE,
          'filters' => TRUE,
Katherine Senzee's avatar
Katherine Senzee committed
          'filter_groups' => TRUE,
        ),
        'export' => FALSE,
      ),

      'title' => array(
        'default' => '',
        'translatable' => TRUE,
      ),
Katherine Senzee's avatar
Katherine Senzee committed
      'enabled' => array(
        'default' => TRUE,
        'translatable' => FALSE,
        'bool' => TRUE,
      ),
      'display_comment' => array(
        'default' => '',
      ),
      'css_class' => array(
        'default' => '',
        'translatable' => FALSE,
      ),
Katherine Senzee's avatar
Katherine Senzee committed
      'display_description' => array(
        'default' => '',
        'translatable' => TRUE,
      ),
      'use_ajax' => array(
        'default' => FALSE,
        'bool' => TRUE,
      ),
David Rothstein's avatar
David Rothstein committed
      'hide_attachment_summary' => array(
        'default' => FALSE,
        'bool' => TRUE,
      ),
      'items_per_page' => array(
        'default' => 10,
      ),
      'offset' => array(
        'default' => 0,
      ),
      'use_pager' => array(
        'default' => FALSE,
        'bool' => TRUE,
      ),
      'use_more' => array(
        'default' => FALSE,
        'bool' => TRUE,
      ),
      'use_more_always' => array(
        'default' => FALSE,
        'bool' => TRUE,
      ),
      'use_more_text' => array(
        'default' => 'more',
        'translatable' => TRUE,
      ),
      'link_display' => array(
        'default' => '',
      ),
      'group_by' => array(
        'default' => FALSE,
        'bool' => TRUE,
      ),

      // These types are all plugins that can have individual settings
      // and therefore need special handling.
      'access' => array(
        'contains' => array(
Katherine Senzee's avatar
Katherine Senzee committed
          'type' => array('default' => 'none', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
         ),
      ),
      'cache' => array(
        'contains' => array(
Katherine Senzee's avatar
Katherine Senzee committed
          'type' => array('default' => 'none', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
         ),
      ),
      'query' => array(
        'contains' => array(
          'type' => array('default' => 'views_query', 'export' => 'export_plugin'),
          'options' => array('default' => array(), 'export' => FALSE),
         ),
      ),
      // Note that exposed_form plugin has options in a separate array,
      // while access and cache do not. access and cache are legacy and
      // that pattern should not be repeated, but it is left as is to
      // reduce the need to modify older views. Let's consider the
      // pattern used here to be the template from which future plugins
      // should be copied.
      'exposed_form' => array(
        'contains' => array(
Katherine Senzee's avatar
Katherine Senzee committed
          'type' => array('default' => 'basic', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
          'options' => array('default' => array(), 'export' => FALSE),
         ),
      ),
      'pager' => array(
        'contains' => array(
Katherine Senzee's avatar
Katherine Senzee committed
          'type' => array('default' => 'full', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
          'options' => array('default' => array(), 'export' => FALSE),
         ),
      ),

      // Note that the styles have their options completely independent.
      // Like access and cache above, this is a legacy pattern and
      // should not be repeated.
      'style_plugin' => array(
        'default' => 'default',
        'export' => 'export_style',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_style',
      ),
      'style_options' => array(
        'default' => array(),
        'export' => FALSE,
      ),
      'row_plugin' => array(
        'default' => 'fields',
        'export' => 'export_style',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_style',
      ),
      'row_options' => array(
        'default' => array(),
        'export' => FALSE,
      ),

      'exposed_block' => array(
        'default' => FALSE,
      ),

      'header' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
      ),
      'footer' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
      ),
      'empty' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
      ),

      // We want these to export last.
      // These are the 5 handler types.
      'relationships' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',

      ),
      'fields' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
      ),
      'sorts' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
      ),
      'arguments' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
      ),
      'filter_groups' => array(
        'contains' => array(
          'operator' => array('default' => 'AND'),
          'groups' => array('default' => array(0 => 'AND')),
        ),
      ),
      'filters' => array(
        'default' => array(),
        'export' => 'export_handler',
Katherine Senzee's avatar
Katherine Senzee committed
        'unpack_translatable' => 'unpack_handler',
Peter Wolanin's avatar
Peter Wolanin committed
    if (empty($this->definition['use pager'])) {
      $options['defaults']['default']['use_pager'] = FALSE;
      $options['defaults']['default']['items_per_page'] = FALSE;
      $options['defaults']['default']['offset'] = FALSE;
      $options['defaults']['default']['pager'] = FALSE;
      $options['pager']['contains']['type']['default'] = 'some';
    }

    if ($this->is_default_display()) {
      unset($options['defaults']);
    }
    return $options;
  }

  /**
   * Check to see if the display has a 'path' field.
   *
   * This is a pure function and not just a setting on the definition
   * because some displays (such as a panel pane) may have a path based
   * upon configuration.
   *
   * By default, displays do not have a path.
   */
  function has_path() { return FALSE; }

  /**
   * Check to see if the display has some need to link to another display.
   *
   * For the most part, displays without a path will use a link display. However,
   * sometimes displays that have a path might also need to link to another display.
   * This is true for feeds.
   */
  function uses_link_display() { return !$this->has_path(); }

  /**
   * Check to see which display to use when creating links within
   * a view using this display.
   */
  function get_link_display() {
    $display_id = $this->get_option('link_display');
    // If unknown, pick the first one.
    if (empty($display_id) || empty($this->view->display[$display_id])) {
      foreach ($this->view->display as $display_id => $display) {
        if (!empty($display->handler) && $display->handler->has_path()) {
          return $display_id;
        }
      }
    }
    else {
      return $display_id;
    }
    // fall-through returns NULL
  }

  /**
   * Return the base path to use for this display.
   *
   * This can be overridden for displays that do strange things
   * with the path.
   */
  function get_path() {
    if ($this->has_path()) {
      return $this->get_option('path');
    }

    $display_id = $this->get_link_display();
    if ($display_id && !empty($this->view->display[$display_id]) && is_object($this->view->display[$display_id]->handler)) {
      return $this->view->display[$display_id]->handler->get_path();
    }
  }

  /**
   * Check to see if the display needs a breadcrumb
   *
   * By default, displays do not need breadcrumbs
   */
  function uses_breadcrumb() { return FALSE; }

  /**
   * Determine if a given option is set to use the default display or the
   * current display
   *
   * @return
   *   TRUE for the default display
   */
  function is_defaulted($option) {
    return !$this->is_default_display() && !empty($this->default_display) && !empty($this->options['defaults'][$option]);
  }

  /**
   * Intelligently get an option either from this display or from the
   * default display, if directed to do so.
   */
  function get_option($option) {
    if ($this->is_defaulted($option)) {
      return $this->default_display->get_option($option);
    }

    if (array_key_exists($option, $this->options)) {
      return $this->options[$option];
    }
  }

  /**
   * Determine if the display's style uses fields.
   */
  function uses_fields() {
    $plugin = $this->get_plugin();
    if ($plugin) {
      return $plugin->uses_fields();
    }
  }

  /**
   * Get the display or row plugin, if it exists.
   */
  function get_plugin($type = 'style', $name = NULL) {
    static $cache = array();
    if (!isset($cache[$type][$name])) {
      switch ($type) {
        case 'style':
        case 'row':
          $option_name = $type . '_plugin';
          $options = $this->get_option($type . '_options');
          if (!$name) {
            $name = $this->get_option($option_name);
          }

          break;
        case 'query':
          $views_data = views_fetch_data($this->view->base_table);
          $name = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query';
        default:
          $option_name = $type;
          $options = $this->get_option($type);
          if (!$name) {
            $name = $options['type'];
          }

          // access & cache store their options as siblings with the
          // type; all others use an 'options' array.
          if ($type != 'access' && $type != 'cache') {
            $options = $options['options'];
          }
      }
      $plugin = views_get_plugin($type, $name);

      if (!$plugin) {
        return;
      }
      if ($type != 'query') {
        $plugin->init($this->view, $this->display, $options);
      }
      else {
David Rothstein's avatar
David Rothstein committed
        $display_id = $this->is_defaulted($option_name) ? $this->display->id : 'default';
        $plugin->localization_keys = array($display_id, $type);

Katherine Senzee's avatar
Katherine Senzee committed
        if (!isset($this->base_field)) {
          $views_data = views_fetch_data($this->view->base_table);
          $this->view->base_field = $views_data['table']['base']['field'];
        }
        $plugin->init($this->view->base_table, $this->view->base_field, $options);
      }
      $cache[$type][$name] = $plugin;
    }

    return $cache[$type][$name];
  }

  /**
   * Get the handler object for a single handler.
   */
  function &get_handler($type, $id) {
    if (!isset($this->handlers[$type])) {
      $this->get_handlers($type);
    }

    if (isset($this->handlers[$type][$id])) {
      return $this->handlers[$type][$id];
    }

    // So we can return a reference.
    $null = NULL;
    return $null;
  }

  /**
   * Get a full array of handlers for $type. This caches them.
   */
  function get_handlers($type) {
    if (!isset($this->handlers[$type])) {
      $this->handlers[$type] = array();
      $types = views_object_types();
      $plural = $types[$type]['plural'];
      foreach ($this->get_option($plural) as $id => $info) {
        if ($info['id'] != $id) {
          $info['id'] = $id;
        }

        // If aggregation is on, the group type might override the actual
        // handler that is in use. This piece of code checks that and,
        // if necessary, sets the override handler.
        $override = NULL;
        if ($this->use_group_by() && !empty($info['group_type'])) {
          if (empty($this->view->query)) {
            $this->view->init_query();
          }
          $aggregate = $this->view->query->get_aggregation_info();
          if (!empty($aggregate[$info['group_type']]['handler'][$type])) {
            $override = $aggregate[$info['group_type']]['handler'][$type];
          }
        }

        if (!empty($types[$type]['type'])) {
          $handler_type = $types[$type]['type'];
        }
        else {
          $handler_type = $type;
        }

        $handler = views_get_handler($info['table'], $info['field'], $handler_type, $override);
        if ($handler) {
David Rothstein's avatar
David Rothstein committed
          // Special override for area types so they know where they come from.
          if ($handler_type == 'area') {
            $handler->handler_type = $type;
          }

          $handler->init($this->view, $info);
          $this->handlers[$type][$id] = &$handler;
        }

        // Prevent reference problems.
        unset($handler);
      }
    }

    return $this->handlers[$type];
  }

  /**
   * Retrieve a list of fields for the current display with the
   *  relationship associated if it exists.
   */
  function get_field_labels() {
    $options = array();
    foreach ($this->get_handlers('relationship') as $relationship => $handler) {
      if ($label = $handler->label()) {
        $relationships[$relationship] = $label;
      }
      else {
        $relationships[$relationship] = $handler->ui_name();
      }
    }

    foreach ($this->get_handlers('field') as $id => $handler) {
      if ($label = $handler->label()) {
        $options[$id] = $label;
      }
      else {
        $options[$id] = $handler->ui_name();
      }
      if (!empty($handler->options['relationship']) && !empty($relationships[$handler->options['relationship']])) {
        $options[$id] = '(' . $relationships[$handler->options['relationship']] . ') ' . $options[$id];
      }
    }
    return $options;
  }

  /**
   * Intelligently set an option either from this display or from the
   * default display, if directed to do so.
   */
  function set_option($option, $value) {
    if ($this->is_defaulted($option)) {
      return $this->default_display->set_option($option, $value);
    }

    // Set this in two places: On the handler where we'll notice it
    // but also on the display object so it gets saved. This should
    // only be a temporary fix.
    $this->display->display_options[$option] = $value;
    return $this->options[$option] = $value;
  }

  /**
   * Set an option and force it to be an override.
   */
  function override_option($option, $value) {
    $this->set_override($option, FALSE);
    $this->set_option($option, $value);
  }

  /**
   * Because forms may be split up into sections, this provides
   * an easy URL to exactly the right section. Don't override this.
   */
  function option_link($text, $section, $class = '', $title = '') {
    views_add_js('ajax');
    if (!empty($class)) {
      $text = '<span>' . $text . '</span>';
    }

    if (!trim($text)) {
      $text = t('Broken field');
    }

    if (empty($title)) {
      $title = $text;
    }

    return l($text, 'admin/structure/views/nojs/display/' . $this->view->name . '/' . $this->display->id . '/' . $section, array('attributes' => array('class' => 'views-ajax-link ' . $class, 'title' => $title, 'id' => drupal_html_id('views-' . $this->display->id . '-' . $section)), 'html' => TRUE));
  }

  /**
   * Provide the default summary for options in the views UI.
   *
   * This output is returned as an array.
   */
  function options_summary(&$categories, &$options) {
    $categories = array(
      'title' => array(
        'title' => t('Title'),
        'column' => 'first',
      ),
      'format' => array(
        'title' => t('Format'),
        'column' => 'first',
      ),
      'filters' => array(
        'title' => t('Filters'),
        'column' => 'first',
      ),
      'fields' => array(
        'title' => t('Fields'),
        'column' => 'first',
      ),
      'pager' => array(
        'title' => t('Pager'),
        'column' => 'second',
      ),
      'exposed' => array(
        'title' => t('Exposed form'),
        'column' => 'third',
        'build' => array(
          '#weight' => 1,
        ),
      ),
        'title' => '',
      'other' => array(
        'title' => t('Other'),
        'column' => 'third',
        'build' => array(
          '#weight' => 2,
        ),
      ),
    );

    if ($this->display->id != 'default') {
      $options['display_id'] = array(
        'category' => 'other',
        'title' => t('Machine Name'),
        'value' => !empty($this->display->new_id) ? check_plain($this->display->new_id) : check_plain($this->display->id),
        'desc' => t('Change the machine name of this display.'),
      );
    }

Katherine Senzee's avatar
Katherine Senzee committed
    $display_comment = drupal_substr($this->get_option('display_comment'), 0, 10);
    $options['display_comment'] = array(
      'category' => 'other',
Katherine Senzee's avatar
Katherine Senzee committed
      'title' => t('Comment'),
      'value' => !empty($display_comment) ? $display_comment : t('No comment'),
      'desc' => t('Comment or document this display.'),
    );

    $title = strip_tags($this->get_option('title'));
    if (!$title) {
      $title = t('None');
    }

    $options['title'] = array(
      'category' => 'title',
      'title' => t('Title'),
      'value' => $title,
      'desc' => t('Change the title that this display will use.'),
    );

Katherine Senzee's avatar
Katherine Senzee committed
    $options['enabled'] = array(
      'category' => 'other',
Katherine Senzee's avatar
Katherine Senzee committed
      'title' => t('Display status'),
      'value' => $this->get_option('enabled') ? t('Enabled') : t('Disabled'),
      'desc' => t('Define if this display is or is not enabled.'),
    );

    $style_plugin = views_fetch_plugin_data('style', $this->get_option('style_plugin'));
    $style_plugin_instance = $this->get_plugin('style');
    $style_summary = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->summary_title();
    $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->plugin_title();

    $style = '';

    $options['style_plugin'] = array(
      'category' => 'format',
      'title' => t('Format'),
      'value' => $style_title,
      'setting' => $style_summary,
      'desc' => t('Change the way content is formatted.'),
    );

    // This adds a 'Settings' link to the style_options setting if the style has options.
    if (!empty($style_plugin['uses options'])) {
      $options['style_plugin']['links']['style_options'] = t('Change settings for this format');
    }

    if (!empty($style_plugin['uses row plugin'])) {
      $row_plugin = views_fetch_plugin_data('row', $this->get_option('row_plugin'));
      $row_plugin_instance = $this->get_plugin('row');
      $row_summary = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->summary_title();
      $row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->plugin_title();

      $options['row_plugin'] = array(
        'category' => 'format',
        'title' => t('Show'),
        'value' => $row_title,
        'setting' => $row_summary,
        'desc' => t('Change the row plugin.'),
      );
      // This adds a 'Settings' link to the row_options setting if the row style has options.
      if (!empty($row_plugin['uses options'])) {
        $options['row_plugin']['links']['row_options'] = t('Change settings for this style');
      }
    }
    if (!empty($this->definition['use ajax'])) {
      $options['use_ajax'] = array(
        'category' => 'other',
        'title' => t('Use AJAX'),
        'value' => $this->get_option('use_ajax') ? t('Yes') : t('No'),
        'desc' => t('Change whether or not this display will use AJAX.'),
      );
    }
David Rothstein's avatar
David Rothstein committed
    if (!empty($this->definition['accept attachments'])) {
      $options['hide_attachment_summary'] = array(
        'category' => 'other',
David Rothstein's avatar
David Rothstein committed
        'title' => t('Hide attachments in summary'),
        'value' => $this->get_option('hide_attachment_summary') ? t('Yes') : t('No'),
        'desc' => t('Change whether or not to display attachments when displaying an argument summary.'),