• Main Page
  • Related Pages
  • Modules
  • Classes
  • Files
  • File List
  • File Members

plugins/views_plugin_display.inc

Go to the documentation of this file.
00001 <?php
00026 class views_plugin_display extends views_plugin {
00032   var $view = NULL;
00033 
00034   var $handlers = array();
00035 
00039   var $extender = array();
00040 
00041   function init(&$view, &$display, $options = NULL) {
00042     $this->view = &$view;
00043     $this->display = &$display;
00044 
00045     // Track changes that the user should know about.
00046     $changed = FALSE;
00047 
00048     // Make some modifications:
00049     if (!isset($options) && isset($display->display_options)) {
00050       $options = $display->display_options;
00051     }
00052 
00053     if ($this->is_default_display() && isset($options['defaults'])) {
00054       unset($options['defaults']);
00055     }
00056 
00057     // Cache for unpack_options, but not if we are in the ui.
00058     static $unpack_options = array();
00059     if (empty($view->editing)) {
00060       $cid = 'unpack_options:' . md5(serialize(array($this->options, $options)));
00061       if (empty($unpack_options[$cid])) {
00062         $cache = views_cache_get($cid, TRUE);
00063         if (!empty($cache->data)) {
00064           $this->options = $cache->data;
00065         }
00066         else {
00067           $this->unpack_options($this->options, $options);
00068           views_cache_set($cid, $this->options, TRUE);
00069         }
00070         $unpack_options[$cid] = $this->options;
00071       }
00072       else {
00073         $this->options = $unpack_options[$cid];
00074       }
00075     }
00076     else {
00077       $this->unpack_options($this->options, $options);
00078     }
00079 
00080     // Translate changed settings:
00081     $items_per_page = $this->get_option('items_per_page');
00082     $offset = $this->get_option('offset');
00083     $use_pager = $this->get_option('use_pager');
00084     $pager = $this->get_option('pager');
00085     // Check if the pager options were already converted.
00086     // The pager settings of a Views 2.x view specifying 10 items with an
00087     // offset of 0 and no pager is the same as of a Views 3.x view with
00088     // default settings. In this case, the only way to determine which case we
00089     // are dealing with is checking the API version but that's only available
00090     // for exported Views as it's not stored in the database.
00091     // If you would like to change this code, really take care that you thought
00092     // of every possibility.
00093     // @TODO: Provide a way to convert the database views as well.
00094     if (((!empty($items_per_page) && $items_per_page != 10) || !empty($offset) || !empty($use_pager))
00095       || (!empty($view->api_version) && $view->api_version == 2)) {
00096       // Find out the right pager type.
00097       // If the view "use pager" it's a normal/full pager.
00098       if ($use_pager) {
00099         $type = 'full';
00100       }
00101       // If it does not use pager, but 0 items per page it should not page
00102       // else it should display just a certain amount of items.
00103       else {
00104         $type = $items_per_page ? 'some' : 'none';
00105       }
00106 
00107       // Setup the pager options.
00108       $pager = array(
00109         'type' => $type,
00110         'options' => array(
00111           'offset' => intval($offset)
00112         ),
00113       );
00114 
00115       if ($items_per_page) {
00116         $pager['options']['items_per_page'] = $items_per_page;
00117       }
00118       // Setup the pager element.
00119       if ($id = $this->get_option('pager_element')) {
00120         $pager['options']['id'] = $id;
00121       }
00122 
00123       // Unset the previous options
00124       // After edit and save the view they will be erased
00125       $this->set_option('items_per_page', NULL);
00126       $this->set_option('offset', NULL);
00127       $this->set_option('use_pager', NULL);
00128       $this->set_option('pager', $pager);
00129       $changed = TRUE;
00130     }
00131 
00132 
00133     // Plugable headers, footer and empty texts are
00134     // not compatible with previous version of views
00135     // This code converts old values into a configured handler for each area
00136     foreach (array('header', 'footer', 'empty') as $area) {
00137       $converted = FALSE;
00138       if (isset($this->options[$area]) && !is_array($this->options[$area])) {
00139         if (!empty($this->options[$area])) {
00140           $content = $this->get_option($area);
00141           if (!empty($content) && !is_array($content)) {
00142             $format = $this->get_option($area . '_format');
00143             $options = array(
00144               'id' => 'area',
00145               'table' => 'views',
00146               'field' => 'area',
00147               'label' => '',
00148               'relationship' => 'none',
00149               'group_type' => 'group',
00150               'content' => $content,
00151               'format' => !empty($format) ? $format : filter_default_format(),
00152             );
00153 
00154             if ($area != 'empty' && $empty = $this->get_option($area . '_empty')) {
00155               $options['empty'] = $empty;
00156             }
00157             $this->set_option($area, array('text' => $options));
00158             $converted = TRUE;
00159             $changed = TRUE;
00160           }
00161         }
00162         // Ensure that options are at least an empty array
00163         if (!$converted) {
00164           $this->set_option($area, array());
00165         }
00166       }
00167     }
00168 
00169     // Convert distinct setting from display to query settings.
00170     $distinct = $this->get_option('distinct');
00171     if (!empty($distinct)) {
00172       $query_settings = $this->get_option('query');
00173       $query_settings['options']['distinct'] = $distinct;
00174       $this->set_option('query', $query_settings);
00175       // Clear the values
00176       $this->set_option('distinct', NULL);
00177       $changed = TRUE;
00178     }
00179 
00180     // Convert field language settings.
00181     $query_options = $this->get_option('query');
00182     if (isset($query_options['options']['field_language'])) {
00183       $this->set_option('field_language', $query_options['options']['field_language']);
00184       unset($query_options['options']['field_language']);
00185       $changed = TRUE;
00186     }
00187     if (isset($query_options['options']['field_language_add_to_query'])) {
00188       $this->set_option('field_language_add_to_query', $query_options['options']['field_language_add_to_query']);
00189       unset($query_options['options']['field_language_add_to_query']);
00190       $changed = TRUE;
00191     }
00192     $this->set_option('query', $query_options);
00193 
00194     // Convert filter groups.
00195     $filter_groups = $this->get_option('filter_groups');
00196     // Only convert if it wasn't converted yet, which is the case if there is a 0 group.
00197     if (isset($filter_groups['groups'][0])) {
00198       // Update filter groups.
00199       $filter_groups ['groups'] = views_array_key_plus($filter_groups['groups']);
00200       $this->set_option('filter_groups', $filter_groups);
00201       // Update the filter group on each filter.
00202       $filters = $this->get_option('filters');
00203       foreach ($filters as &$filter) {
00204         if (isset($filter['group'])) {
00205           $filter['group']++;
00206         }
00207         else {
00208           $filter['group'] = 1;
00209         }
00210       }
00211       $this->set_option('filters', $filters);
00212       $changed = TRUE;
00213     }
00214 
00215     // Mark the view as changed so the user has a chance to save it.
00216     if ($changed) {
00217       $this->view->changed = TRUE;
00218     }
00219   }
00220 
00221   function construct() {
00222     // Load extenders as soon as possible
00223     $this->extender = array();
00224     $extenders = views_get_enabled_display_extenders();
00225     // If you update to the dev version the registry might not be loaded yet.
00226     if (!empty($extenders) && class_exists('views_plugin_display_extender')) {
00227       foreach ($extenders as $extender) {
00228         $data = views_fetch_plugin_data('display_extender', $extender);
00229         if (isset($data['handler']) && class_exists($data['handler'])) {
00230           $this->extender[$extender] = new $data['handler']($this->view, $this);
00231         }
00232         else {
00233           vpr('Invalid display extender @extender', array('@handler' => $extender));
00234         }
00235       }
00236     }
00237     parent::construct();
00238   }
00239 
00240   function destroy() {
00241     parent::destroy();
00242 
00243     foreach ($this->handlers as $type => $handlers) {
00244       foreach ($handlers as $id => $handler) {
00245         if (is_object($handler)) {
00246           $this->handlers[$type][$id]->destroy();
00247         }
00248       }
00249     }
00250 
00251     if (isset($this->default_display)) {
00252       unset($this->default_display);
00253     }
00254 
00255     foreach ($this->extender as $extender) {
00256       $extender->destroy();
00257     }
00258   }
00259 
00264   function is_default_display() { return FALSE; }
00265 
00270   function uses_exposed() {
00271     if (!isset($this->has_exposed)) {
00272       foreach ($this->handlers as $type => $value) {
00273         foreach ($this->view->$type as $id => $handler) {
00274           if ($handler->can_expose() && $handler->is_exposed()) {
00275             // one is all we need; if we find it, return true.
00276             $this->has_exposed = TRUE;
00277             return TRUE;
00278           }
00279         }
00280       }
00281       $pager = $this->get_plugin('pager');
00282       if (isset($pager) && $pager->uses_exposed()) {
00283         $this->has_exposed = TRUE;
00284         return TRUE;
00285       }
00286       $this->has_exposed = FALSE;
00287     }
00288 
00289     return $this->has_exposed;
00290   }
00291 
00301   function displays_exposed() {
00302     return TRUE;
00303   }
00304 
00308   function use_ajax() {
00309     if (!empty($this->definition['use ajax'])) {
00310       return $this->get_option('use_ajax');
00311     }
00312     return FALSE;
00313   }
00314 
00318   function use_pager() {
00319     $pager = $this->get_plugin('pager');
00320     if ($pager) {
00321       return $pager->use_pager();
00322     }
00323   }
00324 
00328   function use_more() {
00329     if (!empty($this->definition['use more'])) {
00330       return $this->get_option('use_more');
00331     }
00332     return FALSE;
00333   }
00334 
00338   function use_group_by() {
00339     return $this->get_option('group_by');
00340   }
00341 
00345   function use_more_always() {
00346     if (!empty($this->definition['use more'])) {
00347       return $this->get_option('use_more_always');
00348     }
00349     return FALSE;
00350   }
00351 
00355   function use_more_text() {
00356     if (!empty($this->definition['use more'])) {
00357       return $this->get_option('use_more_text');
00358     }
00359     return FALSE;
00360   }
00361 
00365   function accept_attachments() {
00366     if (empty($this->definition['accept attachments'])) {
00367       return FALSE;
00368     }
00369     if (!empty($this->view->argument) && $this->get_option('hide_attachment_summary')) {
00370       foreach ($this->view->argument as $argument_id => $argument) {
00371         if ($argument->needs_style_plugin() && empty($argument->argument_validated)) {
00372           return FALSE;
00373         }
00374       }
00375     }
00376     return TRUE;
00377   }
00378 
00382   function attach_to($display_id) { }
00383 
00388   function defaultable_sections($section = NULL) {
00389     $sections = array(
00390       'access' => array('access', 'access_options'),
00391       'access_options' => array('access', 'access_options'),
00392       'cache' => array('cache', 'cache_options'),
00393       'cache_options' => array('cache', 'cache_options'),
00394       'title' => array('title'),
00395       'css_class' => array('css_class'),
00396       'use_ajax' => array('use_ajax'),
00397       'hide_attachment_summary' => array('hide_attachment_summary'),
00398       'group_by' => array('group_by'),
00399       'query' => array('query'),
00400       'use_more' => array('use_more', 'use_more_always', 'use_more_text'),
00401       'link_display' => array('link_display', 'link_url'),
00402 
00403       // Force these to cascade properly.
00404       'style_plugin' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
00405       'style_options' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
00406       'row_plugin' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
00407       'row_options' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
00408 
00409       'pager' => array('pager', 'pager_options'),
00410       'pager_options' => array('pager', 'pager_options'),
00411 
00412       'exposed_form' => array('exposed_form', 'exposed_form_options'),
00413       'exposed_form_options' => array('exposed_form', 'exposed_form_options'),
00414 
00415       // These guys are special
00416       'header' => array('header'),
00417       'footer' => array('footer'),
00418       'empty' => array('empty'),
00419       'relationships' => array('relationships'),
00420       'fields' => array('fields'),
00421       'sorts' => array('sorts'),
00422       'arguments' => array('arguments'),
00423       'filters' => array('filters', 'filter_groups'),
00424     );
00425 
00426     // If the display cannot use a pager, then we cannot default it.
00427     if (empty($this->definition['use pager'])) {
00428       unset($sections['pager']);
00429       unset($sections['items_per_page']);
00430     }
00431 
00432     foreach ($this->extender as $extender) {
00433       $extender->defaultable_sections($sections, $section);
00434     }
00435 
00436     if ($section) {
00437       if (!empty($sections[$section])) {
00438         return $sections[$section];
00439       }
00440     }
00441     else {
00442       return $sections;
00443     }
00444   }
00445 
00446   function option_definition() {
00447     $options = array(
00448       'defaults' => array(
00449         'default' => array(
00450           'access' => TRUE,
00451           'cache' => TRUE,
00452           'query' => TRUE,
00453           'title' => TRUE,
00454           'css_class' => TRUE,
00455 
00456           'display_description' => FALSE,
00457           'use_ajax' => TRUE,
00458           'hide_attachment_summary' => TRUE,
00459           'pager' => TRUE,
00460           'pager_options' => TRUE,
00461           'use_more' => TRUE,
00462           'use_more_always' => TRUE,
00463           'use_more_text' => TRUE,
00464           'exposed_form' => TRUE,
00465           'exposed_form_options' => TRUE,
00466 
00467           'link_display' => TRUE,
00468           'link_url' => '',
00469           'group_by' => TRUE,
00470 
00471           'style_plugin' => TRUE,
00472           'style_options' => TRUE,
00473           'row_plugin' => TRUE,
00474           'row_options' => TRUE,
00475 
00476           'header' => TRUE,
00477           'footer' => TRUE,
00478           'empty' => TRUE,
00479 
00480           'relationships' => TRUE,
00481           'fields' => TRUE,
00482           'sorts' => TRUE,
00483           'arguments' => TRUE,
00484           'filters' => TRUE,
00485           'filter_groups' => TRUE,
00486         ),
00487         'export' => FALSE,
00488       ),
00489 
00490       'title' => array(
00491         'default' => '',
00492         'translatable' => TRUE,
00493       ),
00494       'enabled' => array(
00495         'default' => TRUE,
00496         'translatable' => FALSE,
00497         'bool' => TRUE,
00498       ),
00499       'display_comment' => array(
00500         'default' => '',
00501       ),
00502       'css_class' => array(
00503         'default' => '',
00504         'translatable' => FALSE,
00505       ),
00506       'display_description' => array(
00507         'default' => '',
00508         'translatable' => TRUE,
00509       ),
00510       'use_ajax' => array(
00511         'default' => FALSE,
00512         'bool' => TRUE,
00513       ),
00514       'hide_attachment_summary' => array(
00515         'default' => FALSE,
00516         'bool' => TRUE,
00517       ),
00518       // This is legacy code:
00519       // Items_per/offset/use_pager is moved to the pager plugin
00520       // but the automatic update path needs this items defined, so don't remove it.
00521       // @see views_plugin_display::init()
00522       'items_per_page' => array(
00523         'default' => 10,
00524       ),
00525       'offset' => array(
00526         'default' => 0,
00527       ),
00528       'use_pager' => array(
00529         'default' => FALSE,
00530         'bool' => TRUE,
00531       ),
00532       'use_more' => array(
00533         'default' => FALSE,
00534         'bool' => TRUE,
00535       ),
00536       'use_more_always' => array(
00537         'default' => FALSE,
00538         'bool' => FALSE,
00539       ),
00540       'use_more_text' => array(
00541         'default' => 'more',
00542         'translatable' => TRUE,
00543       ),
00544       'link_display' => array(
00545         'default' => '',
00546       ),
00547       'link_url' => array(
00548         'default' => '',
00549       ),
00550       'group_by' => array(
00551         'default' => FALSE,
00552         'bool' => TRUE,
00553       ),
00554       'field_language' => array(
00555         'default' => '***CURRENT_LANGUAGE***',
00556       ),
00557       'field_language_add_to_query' => array(
00558         'default' => 1,
00559       ),
00560 
00561       // These types are all plugins that can have individual settings
00562       // and therefore need special handling.
00563       'access' => array(
00564         'contains' => array(
00565           'type' => array('default' => 'none', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
00566          ),
00567       ),
00568       'cache' => array(
00569         'contains' => array(
00570           'type' => array('default' => 'none', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
00571          ),
00572       ),
00573       'query' => array(
00574         'contains' => array(
00575           'type' => array('default' => 'views_query', 'export' => 'export_plugin'),
00576           'options' => array('default' => array(), 'export' => FALSE),
00577          ),
00578       ),
00579       // Note that exposed_form plugin has options in a separate array,
00580       // while access and cache do not. access and cache are legacy and
00581       // that pattern should not be repeated, but it is left as is to
00582       // reduce the need to modify older views. Let's consider the
00583       // pattern used here to be the template from which future plugins
00584       // should be copied.
00585       'exposed_form' => array(
00586         'contains' => array(
00587           'type' => array('default' => 'basic', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
00588           'options' => array('default' => array(), 'export' => FALSE),
00589          ),
00590       ),
00591       'pager' => array(
00592         'contains' => array(
00593           'type' => array('default' => 'full', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
00594           'options' => array('default' => array(), 'export' => FALSE),
00595          ),
00596       ),
00597 
00598       // Note that the styles have their options completely independent.
00599       // Like access and cache above, this is a legacy pattern and
00600       // should not be repeated.
00601       'style_plugin' => array(
00602         'default' => 'default',
00603         'export' => 'export_style',
00604         'unpack_translatable' => 'unpack_style',
00605       ),
00606       'style_options' => array(
00607         'default' => array(),
00608         'export' => FALSE,
00609       ),
00610       'row_plugin' => array(
00611         'default' => 'fields',
00612         'export' => 'export_style',
00613         'unpack_translatable' => 'unpack_style',
00614       ),
00615       'row_options' => array(
00616         'default' => array(),
00617         'export' => FALSE,
00618       ),
00619 
00620       'exposed_block' => array(
00621         'default' => FALSE,
00622       ),
00623 
00624       'header' => array(
00625         'default' => array(),
00626         'export' => 'export_handler',
00627         'unpack_translatable' => 'unpack_handler',
00628       ),
00629       'footer' => array(
00630         'default' => array(),
00631         'export' => 'export_handler',
00632         'unpack_translatable' => 'unpack_handler',
00633       ),
00634       'empty' => array(
00635         'default' => array(),
00636         'export' => 'export_handler',
00637         'unpack_translatable' => 'unpack_handler',
00638       ),
00639 
00640       // We want these to export last.
00641       // These are the 5 handler types.
00642       'relationships' => array(
00643         'default' => array(),
00644         'export' => 'export_handler',
00645         'unpack_translatable' => 'unpack_handler',
00646 
00647       ),
00648       'fields' => array(
00649         'default' => array(),
00650         'export' => 'export_handler',
00651         'unpack_translatable' => 'unpack_handler',
00652       ),
00653       'sorts' => array(
00654         'default' => array(),
00655         'export' => 'export_handler',
00656         'unpack_translatable' => 'unpack_handler',
00657       ),
00658       'arguments' => array(
00659         'default' => array(),
00660         'export' => 'export_handler',
00661         'unpack_translatable' => 'unpack_handler',
00662       ),
00663       'filter_groups' => array(
00664         'contains' => array(
00665           'operator' => array('default' => 'AND'),
00666           'groups' => array('default' => array(1 => 'AND')),
00667         ),
00668       ),
00669       'filters' => array(
00670         'default' => array(),
00671         'export' => 'export_handler',
00672         'unpack_translatable' => 'unpack_handler',
00673       ),
00674     );
00675 
00676     if (empty($this->definition['use pager'])) {
00677       $options['defaults']['default']['use_pager'] = FALSE;
00678       $options['defaults']['default']['items_per_page'] = FALSE;
00679       $options['defaults']['default']['offset'] = FALSE;
00680       $options['defaults']['default']['pager'] = FALSE;
00681       $options['pager']['contains']['type']['default'] = 'some';
00682     }
00683 
00684     if ($this->is_default_display()) {
00685       unset($options['defaults']);
00686     }
00687 
00688     foreach ($this->extender as $extender) {
00689       $extender->option_definition($options);
00690     }
00691 
00692     return $options;
00693   }
00694 
00704   function has_path() { return FALSE; }
00705 
00713   function uses_link_display() { return !$this->has_path(); }
00714 
00723   function uses_exposed_form_in_block() { return $this->has_path(); }
00724 
00729   function get_link_display() {
00730     $display_id = $this->get_option('link_display');
00731     // If unknown, pick the first one.
00732     if (empty($display_id) || empty($this->view->display[$display_id])) {
00733       foreach ($this->view->display as $display_id => $display) {
00734         if (!empty($display->handler) && $display->handler->has_path()) {
00735           return $display_id;
00736         }
00737       }
00738     }
00739     else {
00740       return $display_id;
00741     }
00742     // fall-through returns NULL
00743   }
00744 
00751   function get_path() {
00752     if ($this->has_path()) {
00753       return $this->get_option('path');
00754     }
00755 
00756     $display_id = $this->get_link_display();
00757     if ($display_id && !empty($this->view->display[$display_id]) && is_object($this->view->display[$display_id]->handler)) {
00758       return $this->view->display[$display_id]->handler->get_path();
00759     }
00760   }
00761 
00767   function uses_breadcrumb() { return FALSE; }
00768 
00776   function is_defaulted($option) {
00777     return !$this->is_default_display() && !empty($this->default_display) && !empty($this->options['defaults'][$option]);
00778   }
00779 
00784   function get_option($option) {
00785     if ($this->is_defaulted($option)) {
00786       return $this->default_display->get_option($option);
00787     }
00788 
00789     if (array_key_exists($option, $this->options)) {
00790       return $this->options[$option];
00791     }
00792   }
00793 
00797   function uses_fields() {
00798     $plugin = $this->get_plugin();
00799     if ($plugin) {
00800       return $plugin->uses_fields();
00801     }
00802   }
00803 
00814   function get_plugin($type = 'style', $name = NULL) {
00815     static $cache = array();
00816     if (!isset($cache[$type][$name])) {
00817       switch ($type) {
00818         case 'style':
00819         case 'row':
00820           $option_name = $type . '_plugin';
00821           $options = $this->get_option($type . '_options');
00822           if (!$name) {
00823             $name = $this->get_option($option_name);
00824           }
00825 
00826           break;
00827         case 'query':
00828           $views_data = views_fetch_data($this->view->base_table);
00829           $name = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query';
00830         default:
00831           $option_name = $type;
00832           $options = $this->get_option($type);
00833           if (!$name) {
00834             $name = $options['type'];
00835           }
00836 
00837           // access & cache store their options as siblings with the
00838           // type; all others use an 'options' array.
00839           if ($type != 'access' && $type != 'cache') {
00840             $options = $options['options'];
00841           }
00842       }
00843       $plugin = views_get_plugin($type, $name);
00844 
00845       if (!$plugin) {
00846         return;
00847       }
00848       if ($type != 'query') {
00849         $plugin->init($this->view, $this->display, $options);
00850       }
00851       else {
00852         $display_id = $this->is_defaulted($option_name) ? $this->display->id : 'default';
00853         $plugin->localization_keys = array($display_id, $type);
00854 
00855         if (!isset($this->base_field)) {
00856           $views_data = views_fetch_data($this->view->base_table);
00857           $this->view->base_field = !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : '';
00858         }
00859         $plugin->init($this->view->base_table, $this->view->base_field, $options);
00860       }
00861       $cache[$type][$name] = $plugin;
00862     }
00863 
00864     return $cache[$type][$name];
00865   }
00866 
00870   function &get_handler($type, $id) {
00871     if (!isset($this->handlers[$type])) {
00872       $this->get_handlers($type);
00873     }
00874 
00875     if (isset($this->handlers[$type][$id])) {
00876       return $this->handlers[$type][$id];
00877     }
00878 
00879     // So we can return a reference.
00880     $null = NULL;
00881     return $null;
00882   }
00883 
00887   function get_handlers($type) {
00888     if (!isset($this->handlers[$type])) {
00889       $this->handlers[$type] = array();
00890       $types = views_object_types();
00891       $plural = $types[$type]['plural'];
00892 
00893       foreach ($this->get_option($plural) as $id => $info) {
00894         // If this is during form submission and there are temporary options
00895         // which can only appear if the view is in the edit cache, use those
00896         // options instead. This is used for AJAX multi-step stuff.
00897         if (isset($_POST['form_id']) && isset($this->view->temporary_options[$type][$id])) {
00898           $info = $this->view->temporary_options[$type][$id];
00899         }
00900 
00901         if ($info['id'] != $id) {
00902           $info['id'] = $id;
00903         }
00904 
00905         // If aggregation is on, the group type might override the actual
00906         // handler that is in use. This piece of code checks that and,
00907         // if necessary, sets the override handler.
00908         $override = NULL;
00909         if ($this->use_group_by() && !empty($info['group_type'])) {
00910           if (empty($this->view->query)) {
00911             $this->view->init_query();
00912           }
00913           $aggregate = $this->view->query->get_aggregation_info();
00914           if (!empty($aggregate[$info['group_type']]['handler'][$type])) {
00915             $override = $aggregate[$info['group_type']]['handler'][$type];
00916           }
00917         }
00918 
00919         if (!empty($types[$type]['type'])) {
00920           $handler_type = $types[$type]['type'];
00921         }
00922         else {
00923           $handler_type = $type;
00924         }
00925 
00926         $handler = views_get_handler($info['table'], $info['field'], $handler_type, $override);
00927         if ($handler) {
00928           // Special override for area types so they know where they come from.
00929           if ($handler_type == 'area') {
00930             $handler->handler_type = $type;
00931           }
00932 
00933           $handler->init($this->view, $info);
00934           $this->handlers[$type][$id] = &$handler;
00935         }
00936 
00937         // Prevent reference problems.
00938         unset($handler);
00939       }
00940     }
00941 
00942     return $this->handlers[$type];
00943   }
00944 
00949   function get_field_labels() {
00950     $options = array();
00951     foreach ($this->get_handlers('relationship') as $relationship => $handler) {
00952       if ($label = $handler->label()) {
00953         $relationships[$relationship] = $label;
00954       }
00955       else {
00956         $relationships[$relationship] = $handler->ui_name();
00957       }
00958     }
00959 
00960     foreach ($this->get_handlers('field') as $id => $handler) {
00961       if ($label = $handler->label()) {
00962         $options[$id] = $label;
00963       }
00964       else {
00965         $options[$id] = $handler->ui_name();
00966       }
00967       if (!empty($handler->options['relationship']) && !empty($relationships[$handler->options['relationship']])) {
00968         $options[$id] = '(' . $relationships[$handler->options['relationship']] . ') ' . $options[$id];
00969       }
00970     }
00971     return $options;
00972   }
00973 
00978   function set_option($option, $value) {
00979     if ($this->is_defaulted($option)) {
00980       return $this->default_display->set_option($option, $value);
00981     }
00982 
00983     // Set this in two places: On the handler where we'll notice it
00984     // but also on the display object so it gets saved. This should
00985     // only be a temporary fix.
00986     $this->display->display_options[$option] = $value;
00987     return $this->options[$option] = $value;
00988   }
00989 
00993   function override_option($option, $value) {
00994     $this->set_override($option, FALSE);
00995     $this->set_option($option, $value);
00996   }
00997 
01002   function option_link($text, $section, $class = '', $title = '') {
01003     views_add_js('ajax');
01004     if (!empty($class)) {
01005       $text = '<span>' . $text . '</span>';
01006     }
01007 
01008     if (!trim($text)) {
01009       $text = t('Broken field');
01010     }
01011 
01012     if (empty($title)) {
01013       $title = $text;
01014     }
01015 
01016     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));
01017   }
01018 
01025   function get_arguments_tokens() {
01026     $tokens = array();
01027     if (!empty($this->view->build_info['substitutions'])) {
01028       $tokens = $this->view->build_info['substitutions'];
01029     }
01030     $count = 0;
01031     foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
01032       $token = '%' . ++$count;
01033       if (!isset($tokens[$token])) {
01034         $tokens[$token] = '';
01035       }
01036 
01037       // Use strip tags as there should never be HTML in the path.
01038       // However, we need to preserve special characters like " that
01039       // were removed by check_plain().
01040       $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(decode_entities($this->view->args[$count - 1])) : '';
01041     }
01042 
01043     return $tokens;
01044   }
01045 
01051   function options_summary(&$categories, &$options) {
01052     $categories = array(
01053       'title' => array(
01054         'title' => t('Title'),
01055         'column' => 'first',
01056       ),
01057       'format' => array(
01058         'title' => t('Format'),
01059         'column' => 'first',
01060       ),
01061       'filters' => array(
01062         'title' => t('Filters'),
01063         'column' => 'first',
01064       ),
01065       'fields' => array(
01066         'title' => t('Fields'),
01067         'column' => 'first',
01068       ),
01069       'pager' => array(
01070         'title' => t('Pager'),
01071         'column' => 'second',
01072       ),
01073       'exposed' => array(
01074         'title' => t('Exposed form'),
01075         'column' => 'third',
01076         'build' => array(
01077           '#weight' => 1,
01078         ),
01079       ),
01080       'access' => array(
01081         'title' => '',
01082         'column' => 'second',
01083         'build' => array(
01084           '#weight' => -5,
01085         ),
01086       ),
01087       'other' => array(
01088         'title' => t('Other'),
01089         'column' => 'third',
01090         'build' => array(
01091           '#weight' => 2,
01092         ),
01093       ),
01094     );
01095 
01096     if ($this->display->id != 'default') {
01097       $options['display_id'] = array(
01098         'category' => 'other',
01099         'title' => t('Machine Name'),
01100         'value' => !empty($this->display->new_id) ? check_plain($this->display->new_id) : check_plain($this->display->id),
01101         'desc' => t('Change the machine name of this display.'),
01102       );
01103     }
01104 
01105     $display_comment = check_plain(drupal_substr($this->get_option('display_comment'), 0, 10));
01106     $options['display_comment'] = array(
01107       'category' => 'other',
01108       'title' => t('Comment'),
01109       'value' => !empty($display_comment) ? $display_comment : t('No comment'),
01110       'desc' => t('Comment or document this display.'),
01111     );
01112 
01113     $title = strip_tags($this->get_option('title'));
01114     if (!$title) {
01115       $title = t('None');
01116     }
01117 
01118     $options['title'] = array(
01119       'category' => 'title',
01120       'title' => t('Title'),
01121       'value' => $title,
01122       'desc' => t('Change the title that this display will use.'),
01123     );
01124 
01125     $style_plugin = views_fetch_plugin_data('style', $this->get_option('style_plugin'));
01126     $style_plugin_instance = $this->get_plugin('style');
01127     $style_summary = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->summary_title();
01128     $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->plugin_title();
01129 
01130     $style = '';
01131 
01132     $options['style_plugin'] = array(
01133       'category' => 'format',
01134       'title' => t('Format'),
01135       'value' => $style_title,
01136       'setting' => $style_summary,
01137       'desc' => t('Change the way content is formatted.'),
01138     );
01139 
01140     // This adds a 'Settings' link to the style_options setting if the style has options.
01141     if (!empty($style_plugin['uses options'])) {
01142       $options['style_plugin']['links']['style_options'] = t('Change settings for this format');
01143     }
01144 
01145     if (!empty($style_plugin['uses row plugin'])) {
01146       $row_plugin = views_fetch_plugin_data('row', $this->get_option('row_plugin'));
01147       $row_plugin_instance = $this->get_plugin('row');
01148       $row_summary = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->summary_title();
01149       $row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->plugin_title();
01150 
01151       $options['row_plugin'] = array(
01152         'category' => 'format',
01153         'title' => t('Show'),
01154         'value' => $row_title,
01155         'setting' => $row_summary,
01156         'desc' => t('Change the way each row in the view is styled.'),
01157       );
01158       // This adds a 'Settings' link to the row_options setting if the row style has options.
01159       if (!empty($row_plugin['uses options'])) {
01160         $options['row_plugin']['links']['row_options'] = t('Change settings for this style');
01161       }
01162     }
01163     if (!empty($this->definition['use ajax'])) {
01164       $options['use_ajax'] = array(
01165         'category' => 'other',
01166         'title' => t('Use AJAX'),
01167         'value' => $this->get_option('use_ajax') ? t('Yes') : t('No'),
01168         'desc' => t('Change whether or not this display will use AJAX.'),
01169       );
01170     }
01171     if (!empty($this->definition['accept attachments'])) {
01172       $options['hide_attachment_summary'] = array(
01173         'category' => 'other',
01174         'title' => t('Hide attachments in summary'),
01175         'value' => $this->get_option('hide_attachment_summary') ? t('Yes') : t('No'),
01176         'desc' => t('Change whether or not to display attachments when displaying a contextual filter summary.'),
01177       );
01178     }
01179 
01180     $pager_plugin = $this->get_plugin('pager');
01181     if (!$pager_plugin) {
01182       // default to the no pager plugin.
01183       $pager_plugin = views_get_plugin('pager', 'none');
01184     }
01185 
01186     $pager_str = $pager_plugin->summary_title();
01187 
01188     $options['pager'] = array(
01189       'category' => 'pager',
01190       'title' => t('Use pager'),
01191       'value' => $pager_plugin->plugin_title(),
01192       'setting' => $pager_str,
01193       'desc' => t("Change this display's pager setting."),
01194     );
01195 
01196     // If pagers aren't allowed, change the text of the item:
01197     if (empty($this->definition['use pager'])) {
01198       $options['pager']['title'] = t('Items to display');
01199     }
01200 
01201     if (!empty($pager_plugin->definition['uses options'])) {
01202       $options['pager']['links']['pager_options'] = t('Change settings for this pager type.');
01203     }
01204 
01205     if (!empty($this->definition['use more'])) {
01206       $options['use_more'] = array(
01207         'category' => 'pager',
01208         'title' => t('More link'),
01209         'value' => $this->get_option('use_more') ? t('Yes') : t('No'),
01210         'desc' => t('Specify whether this display will provide a "more" link.'),
01211       );
01212     }
01213 
01214     $this->view->init_query();
01215     if ($this->view->query->get_aggregation_info()) {
01216       $options['group_by'] = array(
01217         'category' => 'other',
01218         'title' => t('Use aggregation'),
01219         'value' => $this->get_option('group_by') ? t('Yes') : t('No'),
01220         'desc' => t('Allow grouping and aggregation (calculation) of fields.'),
01221       );
01222     }
01223 
01224     $options['query'] = array(
01225       'category' => 'other',
01226       'title' => t('Query settings'),
01227       'value' => t('Settings'),
01228       'desc' => t('Allow to set some advanced settings for the query plugin'),
01229     );
01230 
01231     $languages = array(
01232         '***CURRENT_LANGUAGE***' => t("Current user's language"),
01233         '***DEFAULT_LANGUAGE***' => t("Default site language"),
01234         LANGUAGE_NONE => t('Language neutral'),
01235     );
01236     if (module_exists('locale')) {
01237       $languages = array_merge($languages, locale_language_list());
01238     }
01239     $field_language = array();
01240     $options['field_language'] = array(
01241       'category' => 'other',
01242       'title' => t('Field Language'),
01243       'value' => $languages[$this->get_option('field_language')],
01244       'desc' => t('All fields which support translations will be displayed in the selected language.'),
01245     );
01246 
01247     $access_plugin = $this->get_plugin('access');
01248     if (!$access_plugin) {
01249       // default to the no access control plugin.
01250       $access_plugin = views_get_plugin('access', 'none');
01251     }
01252 
01253     $access_str = $access_plugin->summary_title();
01254 
01255     $options['access'] = array(
01256       'category' => 'access',
01257       'title' => t('Access'),
01258       'value' => $access_plugin->plugin_title(),
01259       'setting' => $access_str,
01260       'desc' => t('Specify access control type for this display.'),
01261     );
01262 
01263     if (!empty($access_plugin->definition['uses options'])) {
01264       $options['access']['links']['access_options'] = t('Change settings for this access type.');
01265     }
01266 
01267     $cache_plugin = $this->get_plugin('cache');
01268     if (!$cache_plugin) {
01269       // default to the no cache control plugin.
01270       $cache_plugin = views_get_plugin('cache', 'none');
01271     }
01272 
01273     $cache_str = $cache_plugin->summary_title();
01274 
01275     $options['cache'] = array(
01276       'category' => 'other',
01277       'title' => t('Caching'),
01278       'value' => $cache_plugin->plugin_title(),
01279       'setting' => $cache_str,
01280       'desc' => t('Specify caching type for this display.'),
01281     );
01282 
01283     if (!empty($cache_plugin->definition['uses options'])) {
01284       $options['cache']['links']['cache_options'] = t('Change settings for this caching type.');
01285     }
01286 
01287     if (!empty($access_plugin->definition['uses options'])) {
01288       $options['access']['links']['access_options'] = t('Change settings for this access type.');
01289     }
01290 
01291     if ($this->uses_link_display()) {
01292       $display_id = $this->get_link_display();
01293       $link_display = empty($this->view->display[$display_id]) ? t('None') : check_plain($this->view->display[$display_id]->display_title);
01294       $link_display =  $this->get_option('link_display') == 'custom_url' ? t('Custom URL') : $link_display;
01295       $options['link_display'] = array(
01296         'category' => 'other',
01297         'title' => t('Link display'),
01298         'value' => $link_display,
01299         'desc' => t('Specify which display or custom url this display will link to.'),
01300       );
01301     }
01302 
01303     if ($this->uses_exposed_form_in_block()) {
01304       $options['exposed_block'] = array(
01305         'category' => 'exposed',
01306         'title' => t('Exposed form in block'),
01307         'value' => $this->get_option('exposed_block') ? t('Yes') : t('No'),
01308         'desc' => t('Allow the exposed form to appear in a block instead of the view.'),
01309       );
01310     }
01311 
01312     $exposed_form_plugin = $this->get_plugin('exposed_form');
01313     if (!$exposed_form_plugin) {
01314       // default to the no cache control plugin.
01315       $exposed_form_plugin = views_get_plugin('exposed_form', 'basic');
01316     }
01317 
01318     $exposed_form_str = $exposed_form_plugin->summary_title();
01319 
01320     $options['exposed_form'] = array(
01321       'category' => 'exposed',
01322       'title' => t('Exposed form style'),
01323       'value' => $exposed_form_plugin->plugin_title(),
01324       'setting' => $exposed_form_str,
01325       'desc' => t('Select the kind of exposed filter to use.'),
01326     );
01327 
01328     if (!empty($exposed_form_plugin->definition['uses options'])) {
01329       $options['exposed_form']['links']['exposed_form_options'] = t('Exposed form settings for this exposed form style.');
01330     }
01331 
01332     $css_class = check_plain(trim($this->get_option('css_class')));
01333     if (!$css_class) {
01334       $css_class = t('None');
01335     }
01336 
01337     $options['css_class'] = array(
01338       'category' => 'other',
01339       'title' => t('CSS class'),
01340       'value' => $css_class,
01341       'desc' => t('Change the CSS class name(s) that will be added to this display.'),
01342     );
01343 
01344     $options['analyze-theme'] = array(
01345       'category' => 'other',
01346       'title' => t('Theme'),
01347       'value' => t('Information'),
01348       'desc' => t('Get information on how to theme this display'),
01349     );
01350 
01351     foreach ($this->extender as $extender) {
01352       $extender->options_summary($categories, $options);
01353     }
01354   }
01355 
01359   function options_form(&$form, &$form_state) {
01360     parent::options_form($form, $form_state);
01361     if ($this->defaultable_sections($form_state['section'])) {
01362       views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
01363     }
01364     $form['#title'] = check_plain($this->display->display_title) . ': ';
01365 
01366     // Set the 'section' to hilite on the form.
01367     // If it's the item we're looking at is pulling from the default display,
01368     // reflect that. Don't use is_defaulted since we want it to show up even
01369     // on the default display.
01370     if (!empty($this->options['defaults'][$form_state['section']])) {
01371       $form['#section'] = 'default-' . $form_state['section'];
01372     }
01373     else {
01374       $form['#section'] = $this->display->id . '-' . $form_state['section'];
01375     }
01376 
01377     switch ($form_state['section']) {
01378       case 'display_id':
01379         $form['#title'] .= t('The machine name of this display');
01380         $form['display_id'] = array(
01381           '#type' => 'textfield',
01382           '#description' => t('This is machine name of the display.'),
01383           '#default_value' => !empty($this->display->new_id) ? $this->display->new_id : $this->display->id,
01384           '#required' => TRUE,
01385           '#size' => 64,
01386         );
01387         break;
01388       case 'display_title':
01389         $form['#title'] .= t('The name and the description of this display');
01390         $form['display_title'] = array(
01391           '#title' => t('Name'),
01392           '#type' => 'textfield',
01393           '#description' => t('This name will appear only in the administrative interface for the View.'),
01394           '#default_value' => $this->display->display_title,
01395         );
01396         $form['display_description'] = array(
01397           '#title' => t('Description'),
01398           '#type' => 'textfield',
01399           '#description' => t('This description will appear only in the administrative interface for the View.'),
01400           '#default_value' => $this->get_option('display_description'),
01401         );
01402         break;
01403       case 'display_comment':
01404         $form['#title'] .= t("This display's comments");
01405         $form['display_comment'] = array(
01406           '#type' => 'textarea',
01407           '#description' => t('This value will be seen and used only within the Views UI and can be used to document this display. You can use this to provide notes for other or future maintainers of your site about how or why this display is configured.'),
01408           '#default_value' => $this->get_option('display_comment'),
01409         );
01410         break;
01411       case 'title':
01412         $form['#title'] .= t('The title of this view');
01413         $form['title'] = array(
01414           '#type' => 'textfield',
01415           '#description' => t('This title will be displayed with the view, wherever titles are normally displayed; i.e, as the page title, block title, etc.'),
01416           '#default_value' => $this->get_option('title'),
01417         );
01418         break;
01419       case 'css_class':
01420         $form['#title'] .= t('CSS class');
01421         $form['css_class'] = array(
01422           '#type' => 'textfield',
01423           '#description' => t('The CSS class names will be added to the view. This enables you to use specific CSS code for each view. You may define multiples classes separated by spaces.'),
01424           '#default_value' => $this->get_option('css_class'),
01425         );
01426         break;
01427       case 'use_ajax':
01428         $form['#title'] .= t('Use AJAX when available to load this view');
01429         $form['description'] = array(
01430           '#markup' => '<div class="description form-item">' . t('If set, this view will use an AJAX mechanism for paging, table sorting and exposed filters. This means the entire page will not refresh. It is not recommended that you use this if this view is the main content of the page as it will prevent deep linking to specific pages, but it is very useful for side content.') . '</div>',
01431         );
01432         $form['use_ajax'] = array(
01433           '#type' => 'radios',
01434           '#options' => array(1 => t('Yes'), 0 => t('No')),
01435           '#default_value' => $this->get_option('use_ajax') ? 1 : 0,
01436         );
01437         break;
01438       case 'hide_attachment_summary':
01439         $form['#title'] .= t('Hide attachments when displaying a contextual filter summary');
01440         $form['hide_attachment_summary'] = array(
01441           '#type' => 'radios',
01442           '#options' => array(1 => t('Yes'), 0 => t('No')),
01443           '#default_value' => $this->get_option('hide_attachment_summary') ? 1 : 0,
01444         );
01445         break;
01446       case 'use_more':
01447         $form['#title'] .= t('Add a more link to the bottom of the display.');
01448         $form['use_more'] = array(
01449           '#type' => 'checkbox',
01450           '#title' => t('Create more link'),
01451           '#description' => t("This will add a more link to the bottom of this view, which will link to the page view. If you have more than one page view, the link will point to the display specified in 'Link display' above. You can override the url at the link display setting."),
01452           '#default_value' => $this->get_option('use_more'),
01453         );
01454         $form['use_more_always'] = array(
01455           '#type' => 'checkbox',
01456           '#title' => t('Do not display more link unless there is more content'),
01457           '#description' => t("This will display the more link even if there are no more items to display."),
01458           '#default_value' => !$this->get_option('use_more_always'),
01459             '#dependency' => array(
01460               'edit-use-more' => array(TRUE),
01461             ),
01462         );
01463         $form['use_more_text'] = array(
01464           '#type' => 'textfield',
01465           '#title' => t('More link text'),
01466           '#description' => t("The text to display for the more link."),
01467           '#default_value' => $this->get_option('use_more_text'),
01468           '#dependency' => array(
01469             'edit-use-more' => array(TRUE),
01470           ),
01471         );
01472         break;
01473       case 'group_by':
01474         $form['#title'] .= t('Allow grouping and aggregation (calculation) of fields.');
01475         $form['group_by'] = array(
01476           '#type' => 'checkbox',
01477           '#title' => t('Aggregate'),
01478           '#description' => t('If enabled, some fields may become unavailable. All fields that are selected for grouping will be collapsed to one record per distinct value. Other fields which are selected for aggregation will have the function run on them. For example, you can group nodes on title and count the number of nids in order to get a list of duplicate titles.'),
01479           '#default_value' => $this->get_option('group_by'),
01480         );
01481         break;
01482       case 'access':
01483         $form['#title'] .= t('Access restrictions');
01484         $form['access'] = array(
01485           '#prefix' => '<div class="clearfix">',
01486           '#suffix' => '</div>',
01487           '#tree' => TRUE,
01488         );
01489 
01490         $access = $this->get_option('access');
01491         $form['access']['type'] =  array(
01492           '#type' => 'radios',
01493           '#options' => views_fetch_plugin_names('access', NULL, array($this->view->base_table)),
01494           '#default_value' => $access['type'],
01495         );
01496 
01497         $access_plugin = views_fetch_plugin_data('access', $access['type']);
01498         if (!empty($access_plugin['uses options'])) {
01499           $form['markup'] = array(
01500             '#prefix' => '<div class="form-item description">',
01501             '#markup' => t('You may also adjust the !settings for the currently selected access restriction.', array('!settings' => $this->option_link(t('settings'), 'access_options'))),
01502             '#suffix' => '</div>',
01503           );
01504         }
01505 
01506         break;
01507       case 'access_options':
01508         $access = $this->get_option('access');
01509         $plugin = $this->get_plugin('access');
01510         $form['#title'] .= t('Access options');
01511         if ($plugin) {
01512           $form['#help_topic'] = $plugin->definition['help topic'];
01513           $form['#help_module'] = $plugin->definition['module'];
01514 
01515           $form['access_options'] = array(
01516             '#tree' => TRUE,
01517           );
01518           $form['access_options']['type'] = array(
01519             '#type' => 'value',
01520             '#value' => $access['type'],
01521           );
01522           $plugin->options_form($form['access_options'], $form_state);
01523         }
01524         break;
01525       case 'cache':
01526         $form['#title'] .= t('Caching');
01527         $form['cache'] = array(
01528           '#prefix' => '<div class="clearfix">',
01529           '#suffix' => '</div>',
01530           '#tree' => TRUE,
01531         );
01532 
01533         $cache = $this->get_option('cache');
01534         $form['cache']['type'] =  array(
01535           '#type' => 'radios',
01536           '#options' => views_fetch_plugin_names('cache', NULL, array($this->view->base_table)),
01537           '#default_value' => $cache['type'],
01538         );
01539 
01540         $cache_plugin = views_fetch_plugin_data('cache', $cache['type']);
01541         if (!empty($cache_plugin['uses options'])) {
01542           $form['markup'] = array(
01543             '#prefix' => '<div class="form-item description">',
01544             '#suffix' => '</div>',
01545             '#markup' => t('You may also adjust the !settings for the currently selected cache mechanism.', array('!settings' => $this->option_link(t('settings'), 'cache_options'))),
01546           );
01547         }
01548         break;
01549       case 'cache_options':
01550         $cache = $this->get_option('cache');
01551         $plugin = $this->get_plugin('cache');
01552         $form['#title'] .= t('Caching options');
01553         if ($plugin) {
01554           $form['#help_topic'] = $plugin->definition['help topic'];
01555           $form['#help_module'] = $plugin->definition['module'];
01556 
01557           $form['cache_options'] = array(
01558             '#tree' => TRUE,
01559           );
01560           $form['cache_options']['type'] = array(
01561             '#type' => 'value',
01562             '#value' => $cache['type'],
01563           );
01564           $plugin->options_form($form['cache_options'], $form_state);
01565         }
01566         break;
01567       case 'query':
01568         $query_options = $this->get_option('query');
01569         $plugin_name = $query_options['type'];
01570 
01571         $form['#title'] .= t('Query options');
01572         $this->view->init_query();
01573         if ($this->view->query) {
01574           if (isset($this->view->query->definition['help topic'])) {
01575             $form['#help_topic'] = $this->view->query->definition['help topic'];
01576           }
01577 
01578           if (isset($this->view->query->definition['module'])) {
01579             $form['#help_module'] = $this->view->query->definition['module'];
01580           }
01581 
01582           $form['query'] = array(
01583             '#tree' => TRUE,
01584             'type' => array(
01585               '#type' => 'value',
01586               '#value' => $plugin_name,
01587             ),
01588             'options' => array(
01589               '#tree' => TRUE,
01590             ),
01591           );
01592 
01593           $this->view->query->options_form($form['query']['options'], $form_state);
01594         }
01595         break;
01596       case 'field_language':
01597         $form['#title'] .= t('Field Language');
01598 
01599         $entities = entity_get_info();
01600         $entity_tables = array();
01601         $has_translation_handlers = FALSE;
01602         foreach ($entities as $type => $entity_info) {
01603           $entity_tables[] = $entity_info['base table'];
01604 
01605           if (!empty($entity_info['translation'])) {
01606             $has_translation_handlers = TRUE;
01607           }
01608         }
01609 
01610         // Doesn't make sense to show a field setting here if we aren't querying
01611         // an entity base table. Also, we make sure that there's at least one
01612         // entity type with a translation handler attached.
01613         if (in_array($this->view->base_table, $entity_tables) && $has_translation_handlers) {
01614           $languages = array(
01615             '***CURRENT_LANGUAGE***' => t("Current user's language"),
01616             '***DEFAULT_LANGUAGE***' => t("Default site language"),
01617             LANGUAGE_NONE => t('Language neutral'),
01618           );
01619           $languages = array_merge($languages, views_language_list());
01620 
01621           $form['field_language'] = array(
01622             '#type' => 'select',
01623             '#title' => t('Field Language'),
01624             '#description' => t('All fields which support translations will be displayed in the selected language.'),
01625             '#options' => $languages,
01626             '#default_value' => $this->get_option('field_language'),
01627           );
01628           $form['field_language_add_to_query'] = array(
01629             '#type' => 'checkbox',
01630             '#title' => t('When needed, add the field language condition to the query'),
01631             '#default_value' => $this->get_option('field_language_add_to_query'),
01632           );
01633         }
01634         else {
01635           $form['field_language']['#markup'] = t("You don't have translatable entity types.");
01636         }
01637         break;
01638       case 'style_plugin':
01639         $form['#title'] .= t('How should this view be styled');
01640         $form['#help_topic'] = 'style';
01641         $form['style_plugin'] =  array(
01642           '#type' => 'radios',
01643           '#options' => views_fetch_plugin_names('style', $this->get_style_type(), array($this->view->base_table)),
01644           '#default_value' => $this->get_option('style_plugin'),
01645           '#description' => t('If the style you choose has settings, be sure to click the settings button that will appear next to it in the View summary.'),
01646         );
01647 
01648         $style_plugin = views_fetch_plugin_data('style', $this->get_option('style_plugin'));
01649         if (!empty($style_plugin['uses options'])) {
01650           $form['markup'] = array(
01651             '#markup' => '<div class="form-item description">' . t('You may also adjust the !settings for the currently selected style.', array('!settings' => $this->option_link(t('settings'), 'style_options'))) . '</div>',
01652           );
01653         }
01654 
01655         break;
01656       case 'style_options':
01657         $form['#title'] .= t('Style options');
01658         $style = TRUE;
01659         $type = 'style_plugin';
01660         $name = $this->get_option('style_plugin');
01661 
01662       case 'row_options':
01663         if (!isset($name)) {
01664           $name = $this->get_option('row_plugin');
01665         }
01666         // if row, $style will be empty.
01667         if (empty($style)) {
01668           $form['#title'] .= t('Row style options');
01669           $type = 'row_plugin';
01670         }
01671         $plugin = $this->get_plugin(empty($style) ? 'row' : 'style');
01672         if ($plugin) {
01673           if (isset($plugin->definition['help topic'])) {
01674             $form['#help_topic'] = $plugin->definition['help topic'];
01675             $form['#help_module'] = $plugin->definition['module'];
01676           }
01677           $form[$form_state['section']] = array(
01678             '#tree' => TRUE,
01679           );
01680           $plugin->options_form($form[$form_state['section']], $form_state);
01681         }
01682         break;
01683       case 'row_plugin':
01684         $form['#title'] .= t('How should each row in this view be styled');
01685         $form['#help_topic'] = 'style-row';
01686         $form['row_plugin'] =  array(
01687           '#type' => 'radios',
01688           '#options' => views_fetch_plugin_names('row', $this->get_style_type(), array($this->view->base_table)),
01689           '#default_value' => $this->get_option('row_plugin'),
01690         );
01691 
01692         $row_plugin = views_fetch_plugin_data('row', $this->get_option('row_plugin'));
01693         if (!empty($row_plugin['uses options'])) {
01694           $form['markup'] = array(
01695             '#markup' => '<div class="form-item description">' . t('You may also adjust the !settings for the currently selected row style.', array('!settings' => $this->option_link(t('settings'), 'row_options'))) . '</div>',
01696           );
01697         }
01698 
01699         break;
01700       case 'link_display':
01701         $form['#title'] .= t('Which display to use for path');
01702         foreach ($this->view->display as $display_id => $display) {
01703           if ($display->handler->has_path()) {
01704             $options[$display_id] = $display->display_title;
01705           }
01706         }
01707         $options['custom_url'] = t('Custom URL');
01708         if (count($options)) {
01709           $form['link_display'] = array(
01710             '#type' => 'radios',
01711             '#options' => $options,
01712             '#description' => t("Which display to use to get this display's path for things like summary links, rss feed links, more links, etc."),
01713             '#default_value' => $this->get_option('link_display'),
01714           );
01715         }
01716 
01717         $options = array();
01718         $count = 0; // This lets us prepare the key as we want it printed.
01719         foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
01720           $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
01721           $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
01722         }
01723 
01724         // Default text.
01725         // We have some options, so make a list.
01726         $output = '';
01727         if (!empty($options)) {
01728           $output = t('<p>The following tokens are available for this link.</p>');
01729           foreach (array_keys($options) as $type) {
01730             if (!empty($options[$type])) {
01731               $items = array();
01732               foreach ($options[$type] as $key => $value) {
01733                 $items[] = $key . ' == ' . $value;
01734               }
01735               $output .= theme('item_list',
01736                 array(
01737                   'items' => $items,
01738                   'type' => $type
01739                 ));
01740             }
01741           }
01742         }
01743 
01744         $form['link_url'] = array(
01745           '#type' => 'textfield',
01746           '#title' => t('Custom URL'),
01747           '#default_value' => $this->get_option('link_url'),
01748           '#description' => t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.') . $output,
01749           '#dependency' => array('radio:link_display' => array('custom_url')),
01750         );
01751         break;
01752       case 'analyze-theme':
01753         $form['#title'] .= t('Theming information');
01754         $form['#help_topic'] = 'analyze-theme';
01755 
01756         if (isset($_POST['theme'])) {
01757           $this->theme = $_POST['theme'];
01758         }
01759         elseif (empty($this->theme)) {
01760           $this->theme = variable_get('theme_default', 'bartik');
01761         }
01762 
01763         if (isset($GLOBALS['theme']) && $GLOBALS['theme'] == $this->theme) {
01764           $this->theme_registry = theme_get_registry();
01765           $theme_engine = $GLOBALS['theme_engine'];
01766         }
01767         else {
01768           $themes = list_themes();
01769           $theme = $themes[$this->theme];
01770 
01771           // Find all our ancestor themes and put them in an array.
01772           $base_theme = array();
01773           $ancestor = $this->theme;
01774           while ($ancestor && isset($themes[$ancestor]->base_theme)) {
01775             $ancestor = $themes[$ancestor]->base_theme;
01776             $base_theme[] = $themes[$ancestor];
01777           }
01778 
01779           // The base themes should be initialized in the right order.
01780           $base_theme = array_reverse($base_theme);
01781 
01782           // This code is copied directly from _drupal_theme_initialize()
01783           $theme_engine = NULL;
01784 
01785           // Initialize the theme.
01786           if (isset($theme->engine)) {
01787             // Include the engine.
01788             include_once DRUPAL_ROOT . '/' . $theme->owner;
01789 
01790             $theme_engine = $theme->engine;
01791             if (function_exists($theme_engine . '_init')) {
01792               foreach ($base_theme as $base) {
01793                 call_user_func($theme_engine . '_init', $base);
01794               }
01795               call_user_func($theme_engine . '_init', $theme);
01796             }
01797           }
01798           else {
01799             // include non-engine theme files
01800             foreach ($base_theme as $base) {
01801               // Include the theme file or the engine.
01802               if (!empty($base->owner)) {
01803                 include_once DRUPAL_ROOT . '/' . $base->owner;
01804               }
01805             }
01806             // and our theme gets one too.
01807             if (!empty($theme->owner)) {
01808               include_once DRUPAL_ROOT . '/' . $theme->owner;
01809             }
01810           }
01811           $this->theme_registry = _theme_load_registry($theme, $base_theme, $theme_engine);
01812         }
01813 
01814         // If there's a theme engine involved, we also need to know its extension
01815         // so we can give the proper filename.
01816         $this->theme_extension = '.tpl.php';
01817         if (isset($theme_engine)) {
01818           $extension_function = $theme_engine . '_extension';
01819           if (function_exists($extension_function)) {
01820             $this->theme_extension = $extension_function();
01821           }
01822         }
01823 
01824         $funcs = array();
01825         // Get theme functions for the display. Note that some displays may
01826         // not have themes. The 'feed' display, for example, completely
01827         // delegates to the style.
01828         if (!empty($this->definition['theme'])) {
01829           $funcs[] = $this->option_link(t('Display output'), 'analyze-theme-display') . ': '  . $this->format_themes($this->theme_functions());
01830           $themes = $this->additional_theme_functions();
01831           if ($themes) {
01832             foreach ($themes as $theme) {
01833               $funcs[] = $this->option_link(t('Alternative display output'), 'analyze-theme-display') . ': '  . $this->format_themes($theme);
01834             }
01835           }
01836         }
01837 
01838         $plugin = $this->get_plugin();
01839         if ($plugin) {
01840           $funcs[] = $this->option_link(t('Style output'), 'analyze-theme-style') . ': ' . $this->format_themes($plugin->theme_functions(), $plugin->additional_theme_functions());
01841           $themes = $plugin->additional_theme_functions();
01842           if ($themes) {
01843             foreach ($themes as $theme) {
01844               $funcs[] = $this->option_link(t('Alternative style'), 'analyze-theme-style') . ': '  . $this->format_themes($theme);
01845             }
01846           }
01847 
01848           if ($plugin->uses_row_plugin()) {
01849             $row_plugin = $this->get_plugin('row');
01850             if ($row_plugin) {
01851               $funcs[] = $this->option_link(t('Row style output'), 'analyze-theme-row') . ': ' . $this->format_themes($row_plugin->theme_functions());
01852               $themes = $row_plugin->additional_theme_functions();
01853               if ($themes) {
01854                 foreach ($themes as $theme) {
01855                   $funcs[] = $this->option_link(t('Alternative row style'), 'analyze-theme-row') . ': '  . $this->format_themes($theme);
01856                 }
01857               }
01858             }
01859           }
01860 
01861           if ($plugin->uses_fields()) {
01862             foreach ($this->get_handlers('field') as $id => $handler) {
01863               $funcs[] = $this->option_link(t('Field @field (ID: @id)', array('@field' => $handler->ui_name(), '@id' => $id)), 'analyze-theme-field') . ': ' . $this->format_themes($handler->theme_functions());
01864             }
01865           }
01866         }
01867 
01868         $form['important'] = array(
01869           '#markup' => '<div class="form-item description"><p>' . t('This section lists all possible templates for the display plugin and for the style plugins, ordered roughly from the least specific to the most specific. The active template for each plugin -- which is the most specific template found on the system -- is highlighted in bold.') . '</p></div>',
01870         );
01871 
01872         if (isset($this->view->display[$this->view->current_display]->new_id)) {
01873           $form['important']['new_id'] = array(
01874             '#prefix' => '<div class="description">',
01875             '#suffix' => '</div>',
01876             '#value' => t("<strong>Important!</strong> You have changed the display's machine name. Anything that attached to this display specifically, such as theming, may stop working until it is updated. To see theme suggestions for it, you need to save the view."),
01877           );
01878         }
01879 
01880         foreach (list_themes() as $key => $theme) {
01881           if (!empty($theme->info['hidden'])) {
01882             continue;
01883           }
01884           $options[$key] = $theme->info['name'];
01885         }
01886 
01887         $form['box'] = array(
01888           '#prefix' => '<div class="container-inline">',
01889           '#suffix' => '</div>',
01890         );
01891         $form['box']['theme'] = array(
01892           '#type' => 'select',
01893           '#options' => $options,
01894           '#default_value' => $this->theme,
01895         );
01896 
01897         $form['box']['change'] = array(
01898           '#type' => 'submit',
01899           '#value' => t('Change theme'),
01900           '#submit' => array('views_ui_edit_display_form_change_theme'),
01901         );
01902 
01903         $form['analysis'] = array(
01904           '#markup' => '<div class="form-item">' . theme('item_list', array('items' => $funcs)) . '</div>',
01905         );
01906 
01907         $form['rescan_button'] = array(
01908           '#prefix' => '<div class="form-item">',
01909           '#suffix' => '</div>',
01910         );
01911         $form['rescan_button']['button'] = array(
01912           '#type' => 'submit',
01913           '#value' => t('Rescan template files'),
01914           '#submit' => array('views_ui_config_item_form_rescan'),
01915         );
01916         $form['rescan_button']['markup'] = array(
01917           '#markup' => '<div class="description">' . t("<strong>Important!</strong> When adding, removing, or renaming template files, it is necessary to make Drupal aware of the changes by making it rescan the files on your system. By clicking this button you clear Drupal's theme registry and thereby trigger this rescanning process. The highlighted templates above will then reflect the new state of your system.") . '</div>',
01918         );
01919 
01920         $form_state['ok_button'] = TRUE;
01921         break;
01922       case 'analyze-theme-display':
01923         $form['#title'] .= t('Theming information (display)');
01924         $output = '<p>' . t('Back to !info.', array('!info' => $this->option_link(t('theming information'), 'analyze-theme'))) . '</p>';
01925 
01926         if (empty($this->definition['theme'])) {
01927           $output .= t('This display has no theming information');
01928         }
01929         else {
01930           $output .= '<p>' . t('This is the default theme template used for this display.') . '</p>';
01931           $output .= '<pre>' . check_plain(file_get_contents('./' . $this->definition['theme path'] . '/' . strtr($this->definition['theme'], '_', '-') . '.tpl.php')) . '</pre>';
01932         }
01933 
01934         if (!empty($this->definition['additional themes'])) {
01935           foreach ($this->definition['additional themes'] as $theme => $type) {
01936             $output .= '<p>' . t('This is an alternative template for this display.') . '</p>';
01937             $output .= '<pre>' . check_plain(file_get_contents('./' . $this->definition['theme path'] . '/' . strtr($theme, '_', '-') . '.tpl.php')) . '</pre>';
01938           }
01939         }
01940 
01941         $form['analysis'] = array(
01942           '#markup' => '<div class="form-item">' . $output . '</div>',
01943         );
01944 
01945         $form_state['ok_button'] = TRUE;
01946         break;
01947       case 'analyze-theme-style':
01948         $form['#title'] .= t('Theming information (style)');
01949         $output = '<p>' . t('Back to !info.', array('!info' => $this->option_link(t('theming information'), 'analyze-theme'))) . '</p>';
01950 
01951         $plugin = $this->get_plugin();
01952 
01953         if (empty($plugin->definition['theme'])) {
01954           $output .= t('This display has no style theming information');
01955         }
01956         else {
01957           $output .= '<p>' . t('This is the default theme template used for this style.') . '</p>';
01958           $output .= '<pre>' . check_plain(file_get_contents('./' . $plugin->definition['theme path'] . '/' . strtr($plugin->definition['theme'], '_', '-') . '.tpl.php')) . '</pre>';
01959         }
01960 
01961         if (!empty($plugin->definition['additional themes'])) {
01962           foreach ($plugin->definition['additional themes'] as $theme => $type) {
01963             $output .= '<p>' . t('This is an alternative template for this style.') . '</p>';
01964             $output .= '<pre>' . check_plain(file_get_contents('./' . $plugin->definition['theme path'] . '/' . strtr($theme, '_', '-') . '.tpl.php')) . '</pre>';
01965           }
01966         }
01967 
01968         $form['analysis'] = array(
01969           '#markup' => '<div class="form-item">' . $output . '</div>',
01970         );
01971 
01972         $form_state['ok_button'] = TRUE;
01973         break;
01974       case 'analyze-theme-row':
01975         $form['#title'] .= t('Theming information (row style)');
01976         $output = '<p>' . t('Back to !info.', array('!info' => $this->option_link(t('theming information'), 'analyze-theme'))) . '</p>';
01977 
01978         $plugin = $this->get_plugin('row');
01979 
01980         if (empty($plugin->definition['theme'])) {
01981           $output .= t('This display has no row style theming information');
01982         }
01983         else {
01984           $output .= '<p>' . t('This is the default theme template used for this row style.') . '</p>';
01985           $output .= '<pre>' . check_plain(file_get_contents('./' . $plugin->definition['theme path'] . '/' . strtr($plugin->definition['theme'], '_', '-') . '.tpl.php')) . '</pre>';
01986         }
01987 
01988         if (!empty($plugin->definition['additional themes'])) {
01989           foreach ($plugin->definition['additional themes'] as $theme => $type) {
01990             $output .= '<p>' . t('This is an alternative template for this row style.') . '</p>';
01991             $output .= '<pre>' . check_plain(file_get_contents('./' . $plugin->definition['theme path'] . '/' . strtr($theme, '_', '-') . '.tpl.php')) . '</pre>';
01992           }
01993         }
01994 
01995         $form['analysis'] = array(
01996           '#markup' => '<div class="form-item">' . $output . '</div>',
01997         );
01998 
01999         $form_state['ok_button'] = TRUE;
02000         break;
02001       case 'analyze-theme-field':
02002         $form['#title'] .= t('Theming information (row style)');
02003         $output = '<p>' . t('Back to !info.', array('!info' => $this->option_link(t('theming information'), 'analyze-theme'))) . '</p>';
02004 
02005         $output .= '<p>' . t('This is the default theme template used for this row style.') . '</p>';
02006 
02007         // Field templates aren't registered the normal way...and they're always
02008         // this one, anyhow.
02009         $output .= '<pre>' . check_plain(file_get_contents(drupal_get_path('module', 'views') . '/theme/views-view-field.tpl.php')) . '</pre>';
02010 
02011         $form['analysis'] = array(
02012           '#markup' => '<div class="form-item">' . $output . '</div>',
02013         );
02014         $form_state['ok_button'] = TRUE;
02015         break;
02016 
02017       case 'exposed_block':
02018         $form['#title'] .= t('Put the exposed form in a block');
02019         $form['description'] = array(
02020           '#markup' => '<div class="description form-item">' . t('If set, any exposed widgets will not appear with this view. Instead, a block will be made available to the Drupal block administration system, and the exposed form will appear there. Note that this block must be enabled manually, Views will not enable it for you.') . '</div>',
02021         );
02022         $form['exposed_block'] = array(
02023           '#type' => 'radios',
02024           '#options' => array(1 => t('Yes'), 0 => t('No')),
02025           '#default_value' => $this->get_option('exposed_block') ? 1 : 0,
02026         );
02027         break;
02028       case 'exposed_form':
02029         $form['#title'] .= t('Exposed Form');
02030         $form['exposed_form'] = array(
02031           '#prefix' => '<div class="clearfix">',
02032           '#suffix' => '</div>',
02033           '#tree' => TRUE,
02034         );
02035 
02036         $exposed_form = $this->get_option('exposed_form');
02037         $form['exposed_form']['type'] =  array(
02038           '#type' => 'radios',
02039           '#options' => views_fetch_plugin_names('exposed_form', NULL, array($this->view->base_table)),
02040           '#default_value' => $exposed_form['type'],
02041         );
02042 
02043         $exposed_form_plugin = views_fetch_plugin_data('exposed_form', $exposed_form['type']);
02044         if (!empty($exposed_form_plugin['uses options'])) {
02045           $form['markup'] = array(
02046             '#prefix' => '<div class="form-item description">',
02047             '#suffix' => '</div>',
02048             '#markup' => t('You may also adjust the !settings for the currently selected style.', array('!settings' => $this->option_link(t('settings'), 'exposed_form_options'))),
02049           );
02050         }
02051         break;
02052       case 'exposed_form_options':
02053         $plugin = $this->get_plugin('exposed_form');
02054         $form['#title'] .= t('Exposed form options');
02055         if ($plugin) {
02056           $form['#help_topic'] = $plugin->definition['help topic'];
02057 
02058           $form['exposed_form_options'] = array(
02059             '#tree' => TRUE,
02060           );
02061           $plugin->options_form($form['exposed_form_options'], $form_state);
02062         }
02063         break;
02064       case 'pager':
02065         $form['#title'] .= t('Select which pager, if any, to use for this view');
02066         $form['pager'] = array(
02067           '#prefix' => '<div class="clearfix">',
02068           '#suffix' => '</div>',
02069           '#tree' => TRUE,
02070         );
02071 
02072         $pager = $this->get_option('pager');
02073         $form['pager']['type'] =  array(
02074           '#type' => 'radios',
02075           '#options' => views_fetch_plugin_names('pager', empty($this->definition['use pager']) ? 'basic' : NULL, array($this->view->base_table)),
02076           '#default_value' => $pager['type'],
02077         );
02078 
02079         $pager_plugin = views_fetch_plugin_data('pager', $pager['type'], array($this->view->base_table));
02080         if (!empty($pager_plugin['uses options'])) {
02081           $form['markup'] = array(
02082             '#prefix' => '<div class="form-item description">',
02083             '#suffix' => '</div>',
02084             '#markup' => t('You may also adjust the !settings for the currently selected pager.', array('!settings' => $this->option_link(t('settings'), 'pager_options'))),
02085           );
02086         }
02087 
02088         break;
02089       case 'pager_options':
02090         $plugin = $this->get_plugin('pager');
02091         $form['#title'] .= t('Pager options');
02092         if ($plugin) {
02093           $form['#help_topic'] = $plugin->definition['help topic'];
02094 
02095           $form['pager_options'] = array(
02096             '#tree' => TRUE,
02097           );
02098           $plugin->options_form($form['pager_options'], $form_state);
02099         }
02100         break;
02101     }
02102 
02103     foreach ($this->extender as $extender) {
02104       $extender->options_form($form, $form_state);
02105     }
02106   }
02107 
02111   function format_themes($themes) {
02112     $registry = $this->theme_registry;
02113     $extension = $this->theme_extension;
02114 
02115     $output = '';
02116     $picked = FALSE;
02117     foreach ($themes as $theme) {
02118       $template = strtr($theme, '_', '-') . $extension;
02119       if (!$picked && !empty($registry[$theme])) {
02120         $template_path = isset($registry[$theme]['path']) ? $registry[$theme]['path'] . '/' : './';
02121         if (file_exists($template_path . $template)) {
02122           $hint = t('File found in folder @template-path', array('@template-path' => $template_path));
02123           $template = '<strong title="'. $hint .'">' . $template . '</strong>';
02124         }
02125         else {
02126           $template = '<strong class="error">' . $template . ' ' . t('(File not found, in folder @template-path)', array('@template-path' => $template_path)) . '</strong>';
02127         }
02128         $picked = TRUE;
02129       }
02130       $fixed[] = $template;
02131     }
02132 
02133     return implode(', ', array_reverse($fixed));
02134   }
02135 
02139   function options_validate(&$form, &$form_state) {
02140     switch ($form_state['section']) {
02141       case 'display_title':
02142         if (empty($form_state['values']['display_title'])) {
02143           form_error($form['display_title'], t('Display title may not be empty.'));
02144         }
02145         break;
02146       case 'css_class':
02147         $css_class = $form_state['values']['css_class'];
02148         if (preg_match('/[^a-zA-Z0-9-_ ]/', $css_class)) {
02149           form_error($form['css_class'], t('CSS classes must be alphanumeric or dashes only.'));
02150         }
02151       break;
02152       case 'display_id':
02153         if ($form_state['values']['display_id']) {
02154           if (preg_match('/[^a-z0-9_]/', $form_state['values']['display_id'])) {
02155             form_error($form['display_id'], t('Display name must be letters, numbers, or underscores only.'));
02156           }
02157 
02158           foreach ($this->view->display as $id => $display) {
02159             if ($id != $this->view->current_display && ($form_state['values']['display_id'] == $id || (isset($display->new_id) && $form_state['values']['display_id'] == $display->new_id))) {
02160               form_error($form['display_id'], t('Display id should be unique.'));
02161             }
02162           }
02163         }
02164         break;
02165       case 'style_options':
02166         $style = TRUE;
02167       case 'row_options':
02168         // if row, $style will be empty.
02169         $plugin = $this->get_plugin(empty($style) ? 'row' : 'style');
02170         if ($plugin) {
02171           $plugin->options_validate($form[$form_state['section']], $form_state);
02172         }
02173         break;
02174       case 'access_options':
02175         $plugin = $this->get_plugin('access');
02176         if ($plugin) {
02177           $plugin->options_validate($form['access_options'], $form_state);
02178         }
02179         break;
02180       case 'query':
02181         if ($this->view->query) {
02182           $this->view->query->options_validate($form['query'], $form_state);
02183         }
02184         break;
02185       case 'cache_options':
02186         $plugin = $this->get_plugin('cache');
02187         if ($plugin) {
02188           $plugin->options_validate($form['cache_options'], $form_state);
02189         }
02190         break;
02191       case 'exposed_form_options':
02192         $plugin = $this->get_plugin('exposed_form');
02193         if ($plugin) {
02194           $plugin->options_validate($form['exposed_form_options'], $form_state);
02195         }
02196         break;
02197       case 'pager_options':
02198         $plugin = $this->get_plugin('pager');
02199         if ($plugin) {
02200           $plugin->options_validate($form['pager_options'], $form_state);
02201         }
02202         break;
02203     }
02204 
02205     foreach ($this->extender as $extender) {
02206       $extender->options_validate($form, $form_state);
02207     }
02208   }
02209 
02214   function options_submit(&$form, &$form_state) {
02215     // Not sure I like this being here, but it seems (?) like a logical place.
02216     $cache_plugin = $this->get_plugin('cache');
02217     if ($cache_plugin) {
02218       $cache_plugin->cache_flush();
02219     }
02220 
02221     $section = $form_state['section'];
02222     switch ($section) {
02223       case 'display_id':
02224         if (isset($form_state['values']['display_id'])) {
02225           $this->display->new_id = $form_state['values']['display_id'];
02226         }
02227         break;
02228       case 'display_title':
02229         $this->display->display_title = $form_state['values']['display_title'];
02230         $this->set_option('display_description', $form_state['values']['display_description']);
02231         break;
02232       case 'access':
02233         $access = $this->get_option('access');
02234         if ($access['type'] != $form_state['values']['access']['type']) {
02235           $plugin = views_get_plugin('access', $form_state['values']['access']['type']);
02236           if ($plugin) {
02237             $access = array('type' => $form_state['values']['access']['type']);
02238             $this->set_option('access', $access);
02239             if (!empty($plugin->definition['uses options'])) {
02240               views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('access_options'));
02241             }
02242           }
02243         }
02244 
02245         break;
02246       case 'access_options':
02247         $plugin = views_get_plugin('access', $form_state['values'][$section]['type']);
02248         if ($plugin) {
02249           $plugin->options_submit($form['access_options'], $form_state);
02250           $this->set_option('access', $form_state['values'][$section]);
02251         }
02252         break;
02253       case 'cache':
02254         $cache = $this->get_option('cache');
02255         if ($cache['type'] != $form_state['values']['cache']['type']) {
02256           $plugin = views_get_plugin('cache', $form_state['values']['cache']['type']);
02257           if ($plugin) {
02258             $cache = array('type' => $form_state['values']['cache']['type']);
02259             $this->set_option('cache', $cache);
02260             if (!empty($plugin->definition['uses options'])) {
02261               views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('cache_options'));
02262             }
02263           }
02264         }
02265 
02266         break;
02267       case 'cache_options':
02268         $plugin = views_get_plugin('cache', $form_state['values'][$section]['type']);
02269         if ($plugin) {
02270           $plugin->options_submit($form['cache_options'], $form_state);
02271           $this->set_option('cache', $form_state['values'][$section]);
02272         }
02273         break;
02274       case 'query':
02275         $plugin = $this->get_plugin('query');
02276         if ($plugin) {
02277           $plugin->options_submit($form['query']['options'], $form_state);
02278           $this->set_option('query', $form_state['values'][$section]);
02279         }
02280         break;
02281 
02282       case 'link_display':
02283         $this->set_option('link_url', $form_state['values']['link_url']);
02284       case 'title':
02285       case 'css_class':
02286       case 'display_comment':
02287         $this->set_option($section, $form_state['values'][$section]);
02288         break;
02289       case 'field_language':
02290         $this->set_option('field_language', $form_state['values']['field_language']);
02291         $this->set_option('field_language_add_to_query', $form_state['values']['field_language_add_to_query']);
02292         break;
02293       case 'use_ajax':
02294       case 'hide_attachment_summary':
02295         $this->set_option($section, (bool)$form_state['values'][$section]);
02296         break;
02297       case 'use_more':
02298         $this->set_option($section, intval($form_state['values'][$section]));
02299         $this->set_option('use_more_always', !intval($form_state['values']['use_more_always']));
02300         $this->set_option('use_more_text', $form_state['values']['use_more_text']);
02301       case 'distinct':
02302         $this->set_option($section, $form_state['values'][$section]);
02303         break;
02304       case 'group_by':
02305         $this->set_option($section, $form_state['values'][$section]);
02306         break;
02307       case 'row_plugin':
02308         // This if prevents resetting options to default if they don't change
02309         // the plugin.
02310         if ($this->get_option($section) != $form_state['values'][$section]) {
02311           $plugin = views_get_plugin('row', $form_state['values'][$section]);
02312           if ($plugin) {
02313             $this->set_option($section, $form_state['values'][$section]);
02314             $this->set_option('row_options', array());
02315 
02316             // send ajax form to options page if we use it.
02317             if (!empty($plugin->definition['uses options'])) {
02318               views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('row_options'));
02319             }
02320           }
02321         }
02322         break;
02323       case 'style_plugin':
02324         // This if prevents resetting options to default if they don't change
02325         // the plugin.
02326         if ($this->get_option($section) != $form_state['values'][$section]) {
02327           $plugin = views_get_plugin('style', $form_state['values'][$section]);
02328           if ($plugin) {
02329             $this->set_option($section, $form_state['values'][$section]);
02330             $this->set_option('style_options', array());
02331             // send ajax form to options page if we use it.
02332             if (!empty($plugin->definition['uses options'])) {
02333               views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('style_options'));
02334             }
02335           }
02336         }
02337         break;
02338       case 'style_options':
02339         $style = TRUE;
02340       case 'row_options':
02341         // if row, $style will be empty.
02342         $plugin = $this->get_plugin(empty($style) ? 'row' : 'style');
02343         if ($plugin) {
02344           $plugin->options_submit($form['options'][$section], $form_state);
02345         }
02346         $this->set_option($section, $form_state['values'][$section]);
02347         break;
02348       case 'exposed_block':
02349         $this->set_option($section, (bool) $form_state['values'][$section]);
02350         break;
02351       case 'exposed_form':
02352         $exposed_form = $this->get_option('exposed_form');
02353         if ($exposed_form['type'] != $form_state['values']['exposed_form']['type']) {
02354           $plugin = views_get_plugin('exposed_form', $form_state['values']['exposed_form']['type']);
02355           if ($plugin) {
02356             $exposed_form = array('type' => $form_state['values']['exposed_form']['type'], 'options' => array());
02357             $this->set_option('exposed_form', $exposed_form);
02358             if (!empty($plugin->definition['uses options'])) {
02359               views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('exposed_form_options'));
02360             }
02361           }
02362         }
02363 
02364         break;
02365       case 'exposed_form_options':
02366         $plugin = $this->get_plugin('exposed_form');
02367         if ($plugin) {
02368           $exposed_form = $this->get_option('exposed_form');
02369           $plugin->options_submit($form['exposed_form_options'], $form_state);
02370           $exposed_form['options'] = $form_state['values'][$section];
02371           $this->set_option('exposed_form', $exposed_form);
02372         }
02373         break;
02374       case 'pager':
02375         $pager = $this->get_option('pager');
02376         if ($pager['type'] != $form_state['values']['pager']['type']) {
02377           $plugin = views_get_plugin('pager', $form_state['values']['pager']['type']);
02378           if ($plugin) {
02379             // Because pagers have very similar options, let's allow pagers to
02380             // try to carry the options over.
02381             $plugin->init($this->view, $this->display, $pager['options']);
02382 
02383             $pager = array('type' => $form_state['values']['pager']['type'], 'options' => $plugin->options);
02384             $this->set_option('pager', $pager);
02385             if (!empty($plugin->definition['uses options'])) {
02386               views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('pager_options'));
02387             }
02388           }
02389         }
02390 
02391         break;
02392       case 'pager_options':
02393         $plugin = $this->get_plugin('pager');
02394         if ($plugin) {
02395           $pager = $this->get_option('pager');
02396           $plugin->options_submit($form['pager_options'], $form_state);
02397           $pager['options'] = $form_state['values'][$section];
02398           $this->set_option('pager', $pager);
02399         }
02400         break;
02401     }
02402 
02403     foreach ($this->extender as $extender) {
02404       $extender->options_submit($form, $form_state);
02405     }
02406   }
02407 
02411   function options_override($form, &$form_state) {
02412     $this->set_override($form_state['section']);
02413   }
02414 
02418   function set_override($section, $new_state = NULL) {
02419     $options = $this->defaultable_sections($section);
02420     if (!$options) {
02421       return;
02422     }
02423 
02424     if (!isset($new_state)) {
02425       $new_state = empty($this->options['defaults'][$section]);
02426     }
02427 
02428     // For each option that is part of this group, fix our settings.
02429     foreach ($options as $option) {
02430       if ($new_state) {
02431         // Revert to defaults.
02432         unset($this->options[$option]);
02433         unset($this->display->display_options[$option]);
02434       }
02435       else {
02436         // copy existing values into our display.
02437         $this->options[$option] = $this->get_option($option);
02438         $this->display->display_options[$option] = $this->options[$option];
02439       }
02440       $this->options['defaults'][$option] = $new_state;
02441       $this->display->display_options['defaults'][$option] = $new_state;
02442     }
02443   }
02444 
02448   function query() {
02449     foreach ($this->extender as $extender) {
02450       $extender->query();
02451     }
02452   }
02453 
02457   function render_filters() { }
02458 
02462   function render_pager() {
02463     return TRUE;
02464   }
02465 
02469   function render_more_link() {
02470     if ($this->use_more() && ($this->use_more_always() || (!empty($this->view->query->pager) && $this->view->query->pager->has_more_records()))) {
02471       $path = $this->get_path();
02472 
02473       if ($this->get_option('link_display') == 'custom_url' && $override_path = $this->get_option('link_url')) {
02474         $tokens = $this->get_arguments_tokens();
02475         $path = strtr($override_path, $tokens);
02476       }
02477 
02478       if ($path) {
02479         if (empty($override_path)) {
02480           $path = $this->view->get_url(NULL, $path);
02481         }
02482         $url_options = array();
02483         if (!empty($this->view->exposed_raw_input)) {
02484           $url_options['query'] = $this->view->exposed_raw_input;
02485         }
02486         $theme = views_theme_functions('views_more', $this->view, $this->display);
02487         $path = check_url(url($path, $url_options));
02488 
02489         return theme($theme, array('more_url' => $path, 'link_text' => check_plain($this->use_more_text()), 'view' => $this->view));
02490       }
02491     }
02492   }
02493 
02494 
02502   function render_header() {
02503     $empty = !empty($this->view->result);
02504     return $this->render_area('header', $empty);
02505   }
02506 
02510   function render_footer() {
02511     $empty = !empty($this->view->result);
02512     return $this->render_area('footer', $empty);
02513   }
02514 
02515   function render_empty() {
02516     return $this->render_area('empty');
02517   }
02518 
02522   function hook_block_list($delta = 0, $edit = array()) { return array(); }
02523 
02527   function hook_menu() { return array(); }
02528 
02532   function render() {
02533     return theme($this->theme_functions(), array('view' => $this->view));
02534   }
02535 
02536   function render_area($area, $empty = FALSE) {
02537     $return = '';
02538     foreach ($this->get_handlers($area) as $area) {
02539       $return .= $area->render($empty);
02540     }
02541     return $return;
02542   }
02543 
02544 
02548   function access($account = NULL) {
02549     if (!isset($account)) {
02550       global $user;
02551       $account = $user;
02552     }
02553 
02554     // Full override.
02555     if (user_access('access all views', $account)) {
02556       return TRUE;
02557     }
02558 
02559     $plugin = $this->get_plugin('access');
02560     if ($plugin) {
02561       return $plugin->access($account);
02562     }
02563 
02564     // fallback to all access if no plugin.
02565     return TRUE;
02566   }
02567 
02573   function pre_execute() {
02574     $this->view->set_use_ajax($this->use_ajax());
02575     if ($this->use_more() && !$this->use_more_always()) {
02576       $this->view->get_total_rows = TRUE;
02577     }
02578     $this->view->init_handlers();
02579     if ($this->uses_exposed()) {
02580       $exposed_form = $this->get_plugin('exposed_form');
02581       $exposed_form->pre_execute();
02582     }
02583 
02584     foreach ($this->extender as $extender) {
02585       $extender->pre_execute();
02586     }
02587   }
02588 
02595   function execute() { }
02596 
02601   function preview() { return $this->view->render(); }
02602 
02607   function get_style_type() { return 'normal'; }
02608 
02615   function validate() {
02616     $errors = array();
02617     // Make sure displays that use fields HAVE fields.
02618     if ($this->uses_fields()) {
02619       $fields = FALSE;
02620       foreach ($this->get_handlers('field') as $field) {
02621         if (empty($field->options['exclude'])) {
02622           $fields = TRUE;
02623         }
02624       }
02625 
02626       if (!$fields) {
02627         $errors[] = t('Display "@display" uses fields but there are none defined for it or all are excluded.', array('@display' => $this->display->display_title));
02628       }
02629     }
02630 
02631     if ($this->has_path() && !$this->get_option('path')) {
02632       $errors[] = t('Display "@display" uses a path but the path is undefined.', array('@display' => $this->display->display_title));
02633     }
02634 
02635     // Validate style plugin
02636     $style = $this->get_plugin();
02637     if (empty($style)) {
02638       $errors[] = t('Display "@display" has an invalid style plugin.', array('@display' => $this->display->display_title));
02639     }
02640     else {
02641       $result = $style->validate();
02642       if (!empty($result) && is_array($result)) {
02643         $errors = array_merge($errors, $result);
02644       }
02645     }
02646 
02647     // Validate query plugin.
02648     $query = $this->get_plugin('query');
02649     $result = $query->validate();
02650     if (!empty($result) && is_array($result)) {
02651       $errors = array_merge($errors, $result);
02652     }
02653 
02654     // Validate handlers
02655     foreach (views_object_types() as $type => $info) {
02656       foreach ($this->get_handlers($type) as $handler) {
02657         $result = $handler->validate();
02658         if (!empty($result) && is_array($result)) {
02659           $errors = array_merge($errors, $result);
02660         }
02661       }
02662     }
02663 
02664     return $errors;
02665   }
02666 
02670   function is_identifier_unique($id, $identifier) {
02671     foreach (views_object_types() as $type => $info) {
02672       foreach ($this->get_handlers($type) as $key => $handler) {
02673         if ($handler->can_expose() && $handler->is_exposed()) {
02674           if ($id != $key && $identifier == $handler->options['expose']['identifier']) {
02675             return FALSE;
02676           }
02677         }
02678       }
02679     }
02680     return TRUE;
02681   }
02682 
02686   function get_special_blocks() {
02687     $blocks = array();
02688 
02689     if ($this->uses_exposed_form_in_block()) {
02690       $delta = '-exp-' . $this->view->name . '-' . $this->display->id;
02691       $desc = t('Exposed form: @view-@display_id', array('@view' => $this->view->name, '@display_id' => $this->display->id));
02692 
02693       $blocks[$delta] = array(
02694         'info' => $desc,
02695         'cache' => DRUPAL_NO_CACHE,
02696       );
02697     }
02698 
02699     return $blocks;
02700   }
02701 
02705   function view_special_blocks($type) {
02706     if ($type == '-exp') {
02707       // avoid interfering with the admin forms.
02708       if (arg(0) == 'admin' && arg(1) == 'structure' && arg(2) == 'views') {
02709         return;
02710       }
02711       $this->view->init_handlers();
02712 
02713       if ($this->uses_exposed() && $this->get_option('exposed_block')) {
02714         $exposed_form = $this->get_plugin('exposed_form');
02715         return array(
02716           'content' => $exposed_form->render_exposed_form(TRUE),
02717         );
02718       }
02719     }
02720   }
02721 
02728   function export_option($indent, $prefix, $storage, $option, $definition, $parents) {
02729     // The $prefix is wrong because we store our actual options a little differently:
02730     $prefix = '$handler->display->display_options';
02731     $output = '';
02732     if (!$parents && !$this->is_default_display()) {
02733       // Do not export items that are not overridden.
02734       if ($this->is_defaulted($option)) {
02735         return;
02736       }
02737 
02738       // If this is not defaulted and is overrideable, flip the switch to say this
02739       // is overridden.
02740       if ($this->defaultable_sections($option)) {
02741         $output .= $indent . $prefix . "['defaults']['$option'] = FALSE;\n";
02742       }
02743     }
02744 
02745     $output .= parent::export_option($indent, $prefix, $storage, $option, $definition, $parents);
02746     return $output;
02747   }
02748 
02757   function export_handler($indent, $prefix, $storage, $option, $definition, $parents) {
02758     $output = '';
02759 
02760     // cut the 's' off because the data is stored as the plural form but we need
02761     // the singular form. Who designed that anyway? Oh yeah, I did. :(
02762     if ($option != 'header' && $option != 'footer' && $option != 'empty') {
02763       $type = substr($option, 0, -1);
02764     }
02765     else {
02766       $type = $option;
02767     }
02768     $types = views_object_types();
02769     foreach ($storage[$option] as $id => $info) {
02770       if (!empty($types[$type]['type'])) {
02771         $handler_type = $types[$type]['type'];
02772       }
02773       else {
02774         $handler_type = $type;
02775       }
02776       // If aggregation is on, the group type might override the actual
02777       // handler that is in use. This piece of code checks that and,
02778       // if necessary, sets the override handler.
02779       $override = NULL;
02780       if ($this->use_group_by() && !empty($info['group_type'])) {
02781         if (empty($this->view->query)) {
02782           $this->view->init_query();
02783         }
02784         $aggregate = $this->view->query->get_aggregation_info();
02785         if (!empty($aggregate[$info['group_type']]['handler'][$type])) {
02786           $override = $aggregate[$info['group_type']]['handler'][$type];
02787         }
02788       }
02789       $handler = views_get_handler($info['table'], $info['field'], $handler_type, $override);
02790       if ($handler) {
02791         $handler->init($this->view, $info);
02792         $output .= $indent . '/* ' . $types[$type]['stitle'] . ': ' . $handler->ui_name() . " */\n";
02793         $output .= $handler->export_options($indent, $prefix . "['$option']['$id']");
02794       }
02795 
02796       // Prevent reference problems.
02797       unset($handler);
02798     }
02799 
02800     return $output;
02801   }
02802 
02810   function export_style($indent, $prefix, $storage, $option, $definition, $parents) {
02811     $output = '';
02812     $style_plugin = $this->get_plugin();
02813     if ($option == 'style_plugin') {
02814       $type = 'style';
02815       $options_field = 'style_options';
02816       $plugin = $style_plugin;
02817     }
02818     else {
02819       if (!$style_plugin || !$style_plugin->uses_row_plugin()) {
02820         return;
02821       }
02822 
02823       $type = 'row';
02824       $options_field = 'row_options';
02825       $plugin = $this->get_plugin('row');
02826       // If the style plugin doesn't use row plugins, don't even bother.
02827     }
02828 
02829     if ($plugin) {
02830       // Write which plugin to use.
02831       $value = $this->get_option($option);
02832       $output .= $indent . $prefix . "['$option'] = '$value';\n";
02833 
02834       // Pass off to the plugin to export itself.
02835       $output .= $plugin->export_options($indent, $prefix . "['$options_field']");
02836     }
02837 
02838     return $output;
02839   }
02840 
02849   function export_plugin($indent, $prefix, $storage, $option, $definition, $parents) {
02850     $output = '';
02851     $plugin_type = end($parents);
02852     $plugin = $this->get_plugin($plugin_type);
02853     if ($plugin) {
02854       // Write which plugin to use.
02855       $value = $storage[$option];
02856       $new_prefix = $prefix . "['$plugin_type']";
02857 
02858       $output .= $indent . $new_prefix . "['$option'] = '$value';\n";
02859 
02860       if ($plugin_type != 'access' && $plugin_type!= 'cache') {
02861         $new_prefix .= "['options']";
02862       }
02863 
02864       // Pass off to the plugin to export itself.
02865       $output .= $plugin->export_options($indent, $new_prefix);
02866     }
02867 
02868     return $output;
02869   }
02870 
02871   function unpack_style($indent, $prefix, $storage, $option, $definition, $parents) {
02872     $output = '';
02873     $style_plugin = $this->get_plugin();
02874     if ($option == 'style_plugin') {
02875       $type = 'style';
02876       $options_field = 'style_options';
02877       $plugin = $style_plugin;
02878     }
02879     else {
02880       if (!$style_plugin || !$style_plugin->uses_row_plugin()) {
02881         return;
02882       }
02883 
02884       $type = 'row';
02885       $options_field = 'row_options';
02886       $plugin = $this->get_plugin('row');
02887       // If the style plugin doesn't use row plugins, don't even bother.
02888     }
02889 
02890     if ($plugin) {
02891       return $plugin->unpack_translatables($translatable, $parents);
02892     }
02893   }
02894 
02898   function unpack_plugin(&$translatable, $storage, $option, $definition, $parents) {
02899     $plugin_type = end($parents);
02900     $plugin = $this->get_plugin($plugin_type);
02901     if ($plugin) {
02902       // Write which plugin to use.
02903       return $plugin->unpack_translatables($translatable, $parents);
02904     }
02905   }
02906 
02915   function unpack_handler(&$translatable, $storage, $option, $definition, $parents) {
02916     $output = '';
02917 
02918     // cut the 's' off because the data is stored as the plural form but we need
02919     // the singular form. Who designed that anyway? Oh yeah, I did. :(
02920     if ($option != 'header' && $option != 'footer' && $option != 'empty') {
02921       $type = substr($option, 0, -1);
02922     }
02923     else {
02924       $type = $option;
02925     }
02926     $types = views_object_types();
02927     foreach ($storage[$option] as $id => $info) {
02928       if (!empty($types[$type]['type'])) {
02929         $handler_type = $types[$type]['type'];
02930       }
02931       else {
02932         $handler_type = $type;
02933       }
02934       $handler = views_get_handler($info['table'], $info['field'], $handler_type);
02935       if ($handler) {
02936         $handler->init($this->view, $info);
02937         $handler->unpack_translatables($translatable, array_merge($parents, array($type, $info['table'], $info['id'])));
02938       }
02939 
02940       // Prevent reference problems.
02941       unset($handler);
02942     }
02943 
02944     return $output;
02945   }
02946 
02958   function get_argument_text() {
02959     return array(
02960       'filter value not present' => t('When the filter value is <em>NOT</em> available'),
02961       'filter value present' => t('When the filter value <em>IS</em> available or a default is provided'),
02962       'description' => t("This display does not have a source for contextual filters, so no contextual filter value will be available unless you select 'Provide default'."),
02963     );
02964   }
02965 
02972   function get_pager_text() {
02973     return array(
02974       'items per page title' => t('Items to display'),
02975       'items per page description' => t('The number of items to display. Enter 0 for no limit.')
02976     );
02977   }
02978 }
02979 
02980 

Generated on Sun Feb 26 2012 12:52:51 for Views by  doxygen 1.7.1