Index: release/project_release.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/release/project_release.module,v
retrieving revision 1.87
diff -u -p -u -p -r1.87 project_release.module
--- release/project_release.module	13 Jan 2009 00:03:09 -0000	1.87
+++ release/project_release.module	13 Jan 2009 01:33:34 -0000
@@ -2503,3 +2503,14 @@ function _project_release_taxonomy_help(
   }
   return $text;
 }
+
+/**
+ * Implementation of hook_views_api().
+ */
+function project_release_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'project_release') .'/views',
+  );
+}
+
cvs diff: Diffing release/views
Index: release/views/project_release.views.inc
===================================================================
RCS file: release/views/project_release.views.inc
diff -N release/views/project_release.views.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/project_release.views.inc	13 Jan 2009 01:33:34 -0000
@@ -0,0 +1,225 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Provide views data and handlers for project_release.module.
+ */
+
+/**
+ * Implementation of hook_views_data().
+ *
+ * Exposes all fields to the views system.
+ */
+function project_release_views_data() {
+  $data = array();
+  // ----------------------------------------------------------------
+  // project_projectss table
+
+  // Define the base group of this table. Fields that don't
+  // have a group defined will go into this field by default.
+  $data['project_release_nodes']['table']['group']  = t('Project release');
+
+  $data['project_release_nodes']['table']['join'] = array(
+    'node' => array(
+      'left_field' => 'nid',
+      'field' => 'nid',
+    ),
+
+    'project_projects' => array(
+      'type' => 'INNER',
+      'left_table' => 'project_projects',
+      'left_field' => 'nid',
+      'field' => 'pid',
+    )
+  );
+
+  // pid
+  $data['project_release_nodes']['pid'] = array(
+    'title' => t('Pid'),
+    'help' => t('The node ID of the project node a release is tied to.'),
+    'field' => array(
+      'handler' => 'views_handler_field_node',
+      'click sortable' => TRUE,
+    ),
+    // Information for accepting a pid as an argument
+    'argument' => array(
+      'handler' => 'views_handler_argument_node_nid',
+      'name field' => 'title',
+      'numeric' => TRUE,
+      'validate type' => 'nid',
+    ),
+    // Information for accepting a pid as a filter
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'relationship' => array(
+      'base' => 'node',
+      'handler' => 'views_handler_relationship',
+      'label' => t('Project node'),
+    ),
+  );
+
+  // version
+  $data['project_release_nodes']['version'] = array(
+    'title' => t('Version string'),
+    'help' => t('The full version string of a release.'),
+    'field' => array(
+      'group' => t('Project release'),
+      'handler' => 'views_handler_field_node',
+      'click sortable' => TRUE,
+     ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // tag
+  $data['project_release_nodes']['tag'] = array(
+    'title' => t('Tag'),
+    'help' => t('The tag associated with a release.'),
+    'field' => array(
+      'group' => t('Project release'),
+      'handler' => 'views_handler_field_node',
+      'click sortable' => TRUE,
+     ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // @TODO:  file_path
+  // @TODO:  file_date
+  // @TODO:  file_hash
+  // @TODO:  rebuild
+  // @TODO:  version_major
+  // @TODO:  version_minor
+  // @TODO:  version_patch
+  // @TODO:  version_extra
+
+  return $data;
+}
+
+/**
+ * Implementation of hook_views_data_alter().
+ */
+function project_release_views_data_alter(&$data) {
+  // Project release version relationship.
+  $data['node']['project_release_version'] = array(
+    'group' => t('Project release'),
+    'title' => t('Version'),
+    'help' => t('Create a relationship from a project node to a project release node.'),
+    'real field' => 'nid',
+    'relationship' => array(
+      'handler' => 'project_release_handler_relationship_project_project_release_node',
+      'base' => 'node',
+      'field' => 'nid',
+      'label' => t('release'),
+    ),
+  );
+
+  /**
+   * Special fields
+   *
+   * These fields are not not stored in the tables created by project_release
+   * and are provided as a way to provide information that would be unavailable
+   * using other fields provided by this module or by views itself.
+   */
+  // changed field
+  $data['node']['project_release_most_recent_release'] = array(
+    'group' => t('Project release'),
+    'title' => t('Most recent release changed time'),
+    'help' => t('The date the most recent project release node associated with a project was last updated.'),
+    'real field' => 'changed',
+    'field' => array(
+      'handler' => 'project_release_handler_field_most_recent_release',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'project_release_handler_sort_most_recent_release',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date', // @TODO
+    ),
+  );
+
+  // API version compatability term field.
+  // We could just use the Taxonomy: Term ID in taxonomy.views.inc except
+  // that we want to only display terms the admin has indicated as being
+  // active on the Project release module settings page.
+  $data['term_node']['project_release_api_version'] = array(
+    'group' => t('Project release'),
+    'title' => t('API compatability term'),
+    'help' => t('The project release API compatability term (version).'),
+    'field' => array(
+      'title' => t('All terms'),
+      'help' => t('Display all taxonomy terms associated with a node.'),
+      'handler' => 'views_handler_field_term_node_tid',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_term_node_tid',
+      'name table' => 'term_data',
+      'name field' => 'name',
+      'empty name field' => t('Uncategorized'),
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'field' => 'tid',
+      'handler' => 'project_release_handler_filter_project_release_api_version',
+      'hierarchy table' => 'term_hierarchy',
+      'numeric' => TRUE,
+    ),
+  );
+
+  // Project download table field
+  $data['node']['download_table'] = array(
+    'group' => t('Project release'),
+    'field' => array(
+      'title' => t('Download table'),
+      'help' => t('A project release download table for the project.'),
+      'handler' => 'project_release_handler_field_download_table',
+      'format' => 'format',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function project_release_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'project_release') .'/views/handlers',
+    ),
+    'handlers' => array(
+      'project_release_handler_field_download_table' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'project_release_handler_field_most_recent_release' => array(
+        'parent' => 'views_handler_field_date',
+      ),
+      'project_release_handler_filter_project_release_api_version' => array(
+        'parent' => 'views_handler_filter_term_node_tid',
+      ),
+      'project_release_handler_relationship_project_project_release_node' => array(
+        'parent' => 'views_handler_relationship',
+      ),
+      'project_release_handler_sort_most_recent_release' => array(
+        'parent' => 'views_handler_sort_date',
+      ),
+    ),
+  );
+}
+
Index: release/views/project_release.views_default.inc
===================================================================
RCS file: release/views/project_release.views_default.inc
diff -N release/views/project_release.views_default.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/project_release.views_default.inc	13 Jan 2009 01:33:34 -0000
@@ -0,0 +1,231 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Contains default views on behalf of the project_release module.
+ */
+
+/**
+ * Implementation of hook_default_view_views().
+ */
+function project_release_views_default_views() {
+  $view = new view;
+  $view->name = 'project_release_by_project';
+  $view->description = 'List the project release nodes associated with a particular project.';
+  $view->tag = 'project_release';
+  $view->view_php = '';
+  $view->base_table = 'node';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+    'nid' => array(
+      'id' => 'nid',
+      'table' => 'node',
+      'field' => 'nid',
+      'label' => 'Nid',
+      'relationship' => 'none',
+      'link_to_node' => 0,
+    ),
+    'title' => array(
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+      'label' => 'Title',
+      'relationship' => 'none',
+      'link_to_node' => 0,
+    ),
+    'version' => array(
+      'id' => 'version',
+      'table' => 'project_release_nodes',
+      'field' => 'version',
+      'label' => 'Version string',
+      'relationship' => 'none',
+      'link_to_node' => 1,
+    ),
+  ));
+  $handler->override_option('sorts', array(
+    'created' => array(
+      'id' => 'created',
+      'table' => 'node',
+      'field' => 'created',
+      'order' => 'DESC',
+      'granularity' => 'day',
+      'relationship' => 'none',
+    ),
+    'name' => array(
+      'id' => 'name',
+      'table' => 'term_data',
+      'field' => 'name',
+      'order' => 'DESC',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('arguments', array(
+    'pid' => array(
+      'default_action' => 'not found',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(
+        'count' => TRUE,
+        'override' => FALSE,
+        'items_per_page' => 25,
+      ),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => 'Releases for %1',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'node',
+      'validate_fail' => 'empty',
+      'break_phrase' => 0,
+      'not' => 0,
+      'id' => 'pid',
+      'table' => 'project_release_nodes',
+      'field' => 'pid',
+      'relationship' => 'none',
+      'default_argument_fixed' => '',
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'project_project' => 'project_project',
+        'project_release' => 0,
+        'book' => 0,
+        'page' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_vocabulary' => array(
+        '3' => 0,
+        '5' => 0,
+        '2' => 0,
+        '1' => 0,
+        '4' => 0,
+      ),
+      'validate_argument_type' => 'tid',
+      'validate_argument_php' => '',
+      'default_argument_user' => 0,
+      'validate_argument_node_access' => 1,
+      'validate_argument_nid_type' => 'nid',
+      'default_options_div_prefix' => '',
+      'validate_argument_project_term_vocabulary' => array(
+        '1' => 0,
+      ),
+      'validate_argument_project_term_argument_type' => 'tid',
+      'validate_argument_project_term_argument_action_top_without' => 'pass',
+      'validate_argument_project_term_argument_action_top_with' => 'pass',
+      'validate_argument_project_term_argument_action_child' => 'pass',
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'type' => array(
+      'id' => 'type',
+      'table' => 'node',
+      'field' => 'type',
+      'operator' => 'in',
+      'value' => array(
+        'project_release' => 'project_release',
+      ),
+      'group' => 0,
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'relationship' => 'none',
+      'expose_button' => array(
+        'button' => 'Expose',
+      ),
+    ),
+    'tid' => array(
+      'id' => 'tid',
+      'table' => 'term_node',
+      'field' => 'tid',
+      'operator' => 'or',
+      'value' => array(),
+      'group' => 0,
+      'exposed' => TRUE,
+      'expose' => array(
+        'operator' => '',
+        'identifier' => 'api',
+        'label' => 'API Version',
+        'optional' => 1,
+        'single' => 0,
+        'remember' => 1,
+      ),
+      'type' => 'select',
+      'vid' => '2',
+      'relationship' => 'none',
+      'expose_button' => array(
+        'button' => 'Hide',
+      ),
+      'reduce_duplicates' => 0,
+    ),
+    'status' => array(
+      'id' => 'status',
+      'table' => 'node',
+      'field' => 'status',
+      'operator' => '=',
+      'value' => 1,
+      'group' => 0,
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'relationship' => 'none',
+      'expose_button' => array(
+        'button' => 'Expose',
+      ),
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'none',
+    'role' => array(),
+    'perm' => 'access projects',
+  ));
+  $handler->override_option('empty', 'There are no published releases for this project.');
+  $handler->override_option('empty_format', '1');
+  $handler->override_option('items_per_page', 20);
+  $handler->override_option('use_pager', '1');
+  $handler->override_option('row_plugin', 'node');
+  $handler->override_option('row_options', array(
+    'teaser' => 1,
+    'links' => 1,
+  ));
+  $handler = $view->new_display('page', 'Releases for *project*', 'page');
+  $handler->override_option('path', 'node/%/release');
+  $handler->override_option('menu', array(
+    'type' => 'none',
+    'title' => 'Test title',
+    'weight' => '0',
+  ));
+  $handler->override_option('tab_options', array(
+    'type' => 'none',
+    'title' => '',
+    'weight' => 0,
+  ));
+  $handler = $view->new_display('feed', 'Feed', 'feed');
+  $handler->override_option('row_plugin', 'node_rss');
+  $handler->override_option('row_options', array(
+    'item_length' => 'default',
+  ));
+  $handler->override_option('path', 'node/%/release/feed');
+  $handler->override_option('menu', array(
+    'type' => 'none',
+    'title' => '',
+    'weight' => 0,
+  ));
+  $handler->override_option('tab_options', array(
+    'type' => 'none',
+    'title' => '',
+    'weight' => 0,
+  ));
+  $handler->override_option('displays', array(
+    'page' => 'page',
+    'default' => 0,
+  ));
+  $views[$view->name] = $view;
+
+  return $views;
+}
+
cvs diff: Diffing release/views/handlers
Index: release/views/handlers/project_release_handler_field_download_table.inc
===================================================================
RCS file: release/views/handlers/project_release_handler_field_download_table.inc
diff -N release/views/handlers/project_release_handler_field_download_table.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/handlers/project_release_handler_field_download_table.inc	13 Jan 2009 01:33:35 -0000
@@ -0,0 +1,176 @@
+<?php
+// $Id$
+
+
+/**
+ * Views field handler for the table to download releases.
+ */
+class project_release_handler_field_download_table extends views_handler_field {
+  /**
+   * Constructor; calls to base object constructor.
+   */
+  function construct() {
+    parent::construct();
+
+    $this->additional_fields = array();
+    $this->additional_fields['nid'] = 'nid';
+    $this->additional_fields['format'] = array('table' => 'node_revisions', 'field' => 'format');
+    $this->additional_fields['uid'] = 'uid';
+    $this->additional_fields['type'] = 'type';
+  }
+
+  function init(&$view, $options) {
+    parent::init($view, $options);
+
+    $this->options += array(
+      'release_type' => $this->radios_get_default($this->get_type_options('release')),
+      'table_type' => $this->radios_get_default($this->get_type_options('table')),
+      'first_column_title' => '',
+    );
+  }
+
+  /**
+   * Helper function that returns an array of possible types.
+   *
+   * @param $type
+   *   Indicates what type of options should be returned.  Possible
+   *   values are 'release' to get release types or 'table' to get
+   *   release table types.
+   * @return
+   *   An array of possible types.
+   */
+  function get_type_options($type){
+    $types = array(
+      'release' => array(
+        'default' => 'official',
+        'options' => array(
+          'official' => array(
+            'name' => t('Official'),
+            'default_title' => t('Official releases'),
+          ),
+          'snapshot' => array(
+            'name' => t('Snapshot'),
+            'default_title' => t('Snapshot releases'),
+          ),
+          'all' => array(
+            'name' => t('All'),
+            'default_title' => t('Version'),
+          ),
+        ),
+      ),
+      'table' => array(
+        'default' => 'supported',
+        'options' => array(
+          'recommended' => array(
+            'name' => t('Recommended'),
+          ),
+          'supported' => array(
+            'name' => t('Supported'),
+          ),
+          'all' => array(
+            'name' => t('All'),
+          ),
+        ),
+      ),
+    );
+    return (isset($types[$type])) ? $types[$type] : array();
+  }
+
+  /**
+   * Get the default option.
+   *
+   * @param $types
+   *   An array of types returned by $this::get_type_options().
+   * @return
+   *   A string indicating the key of $types that should be the default option.
+   */
+  function radios_get_default($types) {
+    return isset($types['default']) ? $types['default'] : '';
+  }
+
+  /**
+   * Get all possible options.
+   *
+   * @param $types
+   *   An array of types returned by $this::get_type_options().
+   * @return
+   *   An array of possible options.
+   */
+  function radios_get_options($types) {
+    $options = array();
+    foreach ($types['options'] as $key => $info) {
+      $options[$key] = $info['name'];
+    }
+    return $options;
+  }
+
+  /**
+   * Default options form that provides the label widget that all fields
+   * should have.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $form['table_type'] = array(
+      '#type' => 'radios',
+      '#prefix' => '<div class="clear-block">',
+      '#suffix' => '</div>',
+      '#title'=> t('Table type'),
+      '#options' => $this->radios_get_options($this->get_type_options('table')),
+      '#default_value'=> $this->options['table_type'],
+    );
+    $release_types = $this->get_type_options('release');
+    $form['release_type'] = array(
+      '#type' => 'radios',
+      '#prefix' => '<div class="views-left-30">',
+      '#suffix' => '</div>',
+      '#title'=> t('Release type'),
+      '#options' => $this->radios_get_options($release_types),
+      '#default_value' => $this->options['release_type'],
+    );
+    $form['first_column_title']= array(
+      '#type' => 'textfield',
+      '#prefix' => '<div class="views-left-50">',
+      '#suffix' => '</div>',
+      '#title' => t('Title of first column of table'),
+      '#max_length' => 20,
+      '#default_value' => empty($this->options['first_column_title']) ? $release_types['options'][$this->options['release_type']]['default_title'] : $this->options['first_column_title'],
+   );
+  }
+
+  /**
+   * Provide extra data to the administration form.
+   */
+  function admin_summary() {
+    $output = '';
+    $release_types = $this->radios_get_options($this->get_type_options('release'));
+    $table_types = $this->radios_get_options($this->get_type_options('table'));
+    $output .= t('@release_type releases, Table type: @table_type', array('@release_type' => $release_types[$this->options['release_type']], '@table_type' => $table_types[$this->options['table_type']]));
+    return $output;
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $node = new stdClass();
+    $node->nid = $values->{$this->aliases['nid']};
+    $node->uid = $values->{$this->aliases['uid']};
+    $node->type = $values->{$this->aliases['type']};
+    $node->format = $values->{$this->aliases['format']};
+
+    // Load a few release related fields for the project itself.
+    project_release_project_nodeapi_load($node);
+    $node->status = 1; // unpublished nodes ignore access control
+    if (empty($node->releases)) {
+      return;
+    }
+    $output = '';
+    $output .= project_release_table($node, $this->options['table_type'], $this->options['release_type'], $this->options['first_column_title']);
+
+    return $output;
+  }
+}
+
Index: release/views/handlers/project_release_handler_field_most_recent_release.inc
===================================================================
RCS file: release/views/handlers/project_release_handler_field_most_recent_release.inc
diff -N release/views/handlers/project_release_handler_field_most_recent_release.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/handlers/project_release_handler_field_most_recent_release.inc	13 Jan 2009 01:33:35 -0000
@@ -0,0 +1,28 @@
+<?php
+// $Id$
+
+
+/**
+ * Field handler for the project_release_most_recent_release field.
+ */
+class project_release_handler_field_most_recent_release extends views_handler_field_date {
+  var $field_alias = 'unknown';
+
+  /**
+   * Called to add the field to a query.
+   */
+  function query() {
+    $this->ensure_my_table();
+    // Add the field.
+    $field = !empty($this->relationship) ? $this->relationship : $this->table_alias . '.' . $this->real_field;
+    $field_alias = !empty($this->relationship) ? $this->relationship . '_max' : $this->table_alias . '_' . $this->real_field . '_max';
+    $this->field_alias = $this->query->add_field(NULL, "MAX($field)", $field_alias);
+    $this->add_additional_fields();
+
+    // Make sure that node.nid is part of the SELECT statement.
+    $node_table_alias = $this->query->ensure_table('node', $this->relationship);
+    $nid_field_alias = $this->query->add_field($node_table_alias, 'nid');
+    $this->query->add_groupby($nid_field_alias);
+  }
+}
+
Index: release/views/handlers/project_release_handler_filter_project_release_api_version.inc
===================================================================
RCS file: release/views/handlers/project_release_handler_filter_project_release_api_version.inc
diff -N release/views/handlers/project_release_handler_filter_project_release_api_version.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/handlers/project_release_handler_filter_project_release_api_version.inc	13 Jan 2009 01:33:35 -0000
@@ -0,0 +1,118 @@
+<?php
+// $Id$
+
+
+/**
+ * Views filter handler for the release's API version compatibility term.
+ *
+ * In order to be able to limit the API compatability terms that are shown in
+ * the filter to terms the administrator has marked as active on the
+ * Project release settings page, we need to have a separate handler that
+ * reimplements a few functions from the views_handler_filter_term_node_tid
+ * class.
+ */
+class project_release_handler_filter_project_release_api_version extends views_handler_filter_term_node_tid {
+  function option_definition() {
+    $options = parent::option_definition();
+
+    // We need to make sure that reduce duplicates is TRUE or otherwise
+    // the query will sometimes return unexpected results.
+    $options['reduce_duplicates'] = array('default' => TRUE);
+
+    // This filter does not support an autocomplete textfield, so make
+    // the default exposed filter widget type be a select box.
+    $options['type'] = array('default' => 'select');
+
+    // Make sure that the Project release API compatability vocabulary is
+    // the default vocabulary.
+    $options['vid'] = array('default' => _project_release_get_api_vid());
+    return $options;
+  }
+
+  /**
+   * Reduce duplicates must be TRUE or we will get unexpected results in some
+   * cases, so don't let it be disabled.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    if (isset($form['reduce_duplicates'])) {
+      unset($form['reduce_duplicates']);
+    }
+  }
+
+  function extra_options_form(&$form, &$form_state) {
+    parent::extra_options_form($form, $form_state);
+
+    // Require the widget to be a select box.
+    $form['type']['#options'] = array('select' => t('Dropdown'));
+  }
+
+  /**
+   * This code is modified from views_handler_filter_term_node_tid::value_form()
+   * to only present the API compatability terms which are marked as
+   * active on the Project release settings page.
+   */
+  function value_form(&$form, &$form_state) {
+    $vocabulary = taxonomy_vocabulary_load($this->options['vid']);
+    if (!$vocabulary) {
+      $form['markup'] = array(
+        '#prefix' => '<div class="form-item">',
+        '#suffix' => '</div>',
+        '#value' => t('An invalid vocabulary is selected. Please change it in the options.'),
+      );
+      return;
+    }
+
+    if (!empty($this->options['hierarchy'])) {
+      $tree = taxonomy_get_tree($vocabulary->vid);
+      $options = array();
+
+      if ($tree) {
+        foreach ($tree as $term) {
+          $choice = new stdClass();
+          $choice->option = array($term->tid => str_repeat('-', $term->depth) . $term->name);
+          $options[] = $choice;
+        }
+      }
+    }
+    else {
+      $options = array();
+      $terms = project_release_compatibility_list();
+      // Remove the '<All>' term that's automatically added
+      // by project_release_compatibility_list() as views
+      // will handle that on its own.
+      if (isset($terms[-1])) {
+        unset($terms[-1]);
+      }
+
+      foreach ($terms as $tid => $name) {
+        $options[$tid] = $name;
+      }
+    }
+
+    // Since we're overriding, allow the list of options to be reduced.
+    if (!empty($form_state['exposed']) && !empty($this->options['expose']['reduce'])) {
+      $options = $this->reduce_value_options($options);
+    }
+
+    $form['value'] = array(
+      '#type' => 'select',
+      '#title' => t('Select active terms from vocabulary @voc', array('@voc' => $vocabulary->name)),
+      '#multiple' => TRUE,
+      '#options' => $options,
+      '#size' => min(9, count($options)),
+    );
+
+    // Only add a description to the select box if we're building the filter
+    // options page, and not the actual exposed filter that the user sees.
+    if (empty($form_state['exposed'])) {
+      $form['value']['#description'] = t('Only terms marked as active on the !project_release_settings_link page are displayed above.', array('!project_release_settings_link' => l(t('Project release settings'), 'admin/project/project-release-settings')));
+    }
+
+    if (empty($form_state['exposed'])) {
+      // Retain the helper option
+      $this->helper->options_form($form, $form_state);
+    }
+  }
+}
+
Index: release/views/handlers/project_release_handler_relationship_project_project_release_node.inc
===================================================================
RCS file: release/views/handlers/project_release_handler_relationship_project_project_release_node.inc
diff -N release/views/handlers/project_release_handler_relationship_project_project_release_node.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/handlers/project_release_handler_relationship_project_project_release_node.inc	13 Jan 2009 01:33:35 -0000
@@ -0,0 +1,50 @@
+<?php
+// $Id$
+
+
+/**
+ * Specialized handler for relationships between projects and release nodes.
+ */
+class project_release_handler_relationship_project_project_release_node extends views_handler_relationship {
+  /**
+   * Called to implement a relationship in a query.
+   */
+  function query() {
+    // Figure out what base table this relationship brings to the party.
+    $join = new views_join();
+    $join->definition = array(
+      'table' => 'project_release_nodes',
+      'field' => 'pid',
+      'left_table' => 'node',
+      'left_field' => 'nid',
+    );
+
+    if (!empty($this->options['required'])) {
+      $join->definition['type'] = 'INNER';
+    }
+
+    $join->construct();
+
+    $this->first_join = $this->query->add_table('project_release_nodes', $this->relationship, $join);
+
+    // Then, create a relationship on that table:
+    $join = new views_join();
+    $join->definition = array(
+      'left_table' => $this->first_join,
+      'left_field' => 'nid',
+      'table' => 'node',
+      'field' => 'nid',
+    );
+
+    if (!empty($this->options['required'])) {
+      $join->definition['type'] = 'INNER';
+    }
+
+    $join->construct();
+
+    $alias = $join->definition['table'] . '_' . $join->definition['left_table'];
+
+    $this->alias = $this->query->add_relationship($alias, $join, 'node', $this->relationship);
+  }
+}
+
Index: release/views/handlers/project_release_handler_sort_most_recent_release.inc
===================================================================
RCS file: release/views/handlers/project_release_handler_sort_most_recent_release.inc
diff -N release/views/handlers/project_release_handler_sort_most_recent_release.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ release/views/handlers/project_release_handler_sort_most_recent_release.inc	13 Jan 2009 01:33:35 -0000
@@ -0,0 +1,52 @@
+<?php
+// $Id$
+
+
+/**
+ * Sort handler for the project_release_most_recent_release field.
+ */
+class project_release_handler_sort_most_recent_release extends views_handler_sort_date {
+  /**
+   * Called to add the sort to a query.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $table_alias = !empty($this->relationship) ? $this->relationship : $this->table_alias;
+    $field =  $table_alias. '.' . $this->real_field;
+    $max_field_alias = !empty($this->relationship) ? $this->relationship . '_max' : $this->table_alias . '_' . $this->real_field . '_max';
+    switch ($this->options['granularity']) {
+      case 'second':
+      default:
+        $this->query->add_orderby(NULL, "MAX($field)", $this->options['order'], $max_field_alias);
+        $position = array_search($max_field_alias, $this->query->groupby);
+        if (isset($position)) {
+          unset($this->query->groupby[$position]);
+        }
+        return;
+      case 'minute':
+        $formula = views_date_sql_format('YmdHi', "$this->table_alias.$this->real_field");
+        break;
+      case 'hour':
+        $formula = views_date_sql_format('YmdH', "$this->table_alias.$this->real_field");
+        break;
+      case 'day':
+        $formula = views_date_sql_format('Ymd', "$this->table_alias.$this->real_field");
+        break;
+      case 'month':
+        $formula = views_date_sql_format('Ym', "$this->table_alias.$this->real_field");
+        break;
+      case 'year':
+        $formula = views_date_sql_format('Y', "$this->table_alias.$this->real_field");
+        break;
+    }
+
+    // Add the field.
+    $max_field_alias = !empty($this->relationship) ? $this->relationship . '_max' : $this->table_alias . '_' . $this->real_field . '_' . $this->options['granularity'] . '_max';
+    $this->query->add_orderby(NULL, "MAX($formula)", $this->options['order'], $max_field_alias);
+    $position = array_search($max_field_alias, $this->query->groupby);
+    if (isset($position)) {
+      unset($this->query->groupby[$position]);
+    }
+  }
+}
+
