# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: contributions/modules/image/contrib/image_gallery/help/descendants.html
--- contributions/modules/image/contrib/image_gallery/help/descendants.html No Base Revision
+++ contributions/modules/image/contrib/image_gallery/help/descendants.html Locally New
@@ -0,0 +1,66 @@
+A gallery's cover image is a single image from that gallery, selected according to a particular criterion. For example, the cover for each gallery might be the most recent image in that gallery.
+
+If a gallery has no descendant galleries, this is a simple procedure. However, what to do when the gallery itself contains galleries is a more complicated matter.
+
+There are three ways to handle descendant galleries when getting a cover image for a gallery.
+
+<dl>
+  <dt>Plain</dt>
+  <dd>Do not go into any descendant galleries: only consider images in the gallery itself. If the gallery itself has no images, then there will be no cover node.
+  </dd>
+
+  <dt>Flat</dt>
+  <dd>Consider the gallery itself and its descendants to a given depth as one single pool of images from which to select the cover.
+  </dd>
+
+  <dt>Recursion</dt>
+  <dd>Consider first the gallery itself, and if it is empty, consider each child gallery one at a time (in weight order). The recusion depth sets how far to go into a child gallery's own children before giving up and moving to the next child gallery. Be warned that this is potentially a time-consuming procedure!</dd>
+
+</dl>
+
+These methods are illustrated in this example.
+
+Consider the following tree of galleries: the numbers are the term IDs that make the galleries and the letters are the titles of the image nodes.
+
+<pre>
+  - 1: empty
+    - 2: empty
+      - 6: nodes G, H
+    - 3: nodes M, N
+    - 4: nodes D, E, F
+    - 5: nodes X, Y, Z
+      - 7: nodes A, B
+</pre>
+
+Suppose our sort criterion for the cover is the image node title in alphabetical order. What cover image will gallery 1 have?
+
+<dl>
+  <dt>Plain</dt>
+  <dd>Term 1 has no nodes: there is no cover image.
+  </dd>
+
+  <dt>Flat depth 0; Recursion depth 0</dt>
+  <dd>Depth 0 means we don't go into child galleries: so this is the same as plain and there is no cover image.
+  </dd>
+
+  <dt>Flat depth 1</dt>
+  <dd>We consider all nodes in the galleries 1, 2, 3, 4, 5.
+  The first node by name is D.
+  </dd>
+
+  <dt>Flat depth 2</dt>
+  <dd>We consider all nodes in the galleries 1, 2, 3, 4, 5, 6, 7.
+  The first node by name is A.
+  </dd>
+
+  <dt>Recursion depth 1</dt>
+  <dd>We find the gallery itself empty, so look in gallery 2.
+  That's empty too, so we look in gallery 3.
+  Here we find nodes, and M is the first by name: so the cover is M.</dd>
+
+  <dt>Recursion depth 2</dt>
+  <dd>We find the gallery itself empty, so look in gallery 2.
+  That's empty too, and so we go one level deeper to gallery 6.
+  Here we find nodes, and G is the first by name: so the cover is G.
+  Node A is a better fit at this depth, but we consider child galleries one by one, by weight, and we found something in gallery 6.</dd>
+</dl>
Index: contributions/modules/image/contrib/image_gallery/help/image_gallery.help.ini
--- contributions/modules/image/contrib/image_gallery/help/image_gallery.help.ini No Base Revision
+++ contributions/modules/image/contrib/image_gallery/help/image_gallery.help.ini Locally New
@@ -0,0 +1,6 @@
+;$Id $
+[descendants]
+title = "Descendant image galleries".
+file = descendants
+weight = 0
+line break = 1
Index: contributions/modules/image/contrib/image_gallery/image_gallery.css
--- contributions/modules/image/contrib/image_gallery/image_gallery.css Base (1.9)
+++ contributions/modules/image/contrib/image_gallery/image_gallery.css Locally Modified (Based On 1.9)
@@ -48,3 +48,31 @@
   background: transparent none;
   list-style: none;
 }
+
+/* for views */
+
+.view .image-gallery-nodes ul {
+  text-align:center;
+}
+.view .image-gallery-nodes ul li {
+  display:inline-block;
+  /*
+    There is no pretty way to get thumbnail sizes here.
+    This will need to be overridden for sites that set a different size.
+  */
+  width:150px;
+  height: 150px;
+  text-align:center;
+  background: none;
+}
+
+.view .image-gallery-terms li {
+  background: transparent none;
+  border : 1px #cccccc solid;
+  margin : 1em 0;
+  padding : 1em;
+}
+.image-gallery-terms .image-gallery-view-cover-thumbnail {
+  float: left;
+  margin-right: 1em;
+}
Index: contributions/modules/image/contrib/image_gallery/image_gallery.module
--- contributions/modules/image/contrib/image_gallery/image_gallery.module Base (1.31)
+++ contributions/modules/image/contrib/image_gallery/image_gallery.module Locally Modified (Based On 1.31)
@@ -374,6 +374,12 @@
     'image_gallery' => array(
       'arguments' => array('galleries' => NULL, 'images' => NULL),
     ),
+    'image_gallery_count' => array(
+      'arguments' => array('count' => 0),
+    ),
+    'image_gallery_updated' => array(
+      'arguments' => array('timestamp' => 0),
+    ),
     'image_gallery_img' => array(
       'arguments' => array('image' => NULL, 'size' => NULL),
     ),
@@ -450,6 +456,20 @@
 }
 
 /**
+ * Theme the count of gallery items on a gallery list.
+ */
+function theme_image_gallery_count($count) {
+  return "There are $count images in this gallery.";
+}
+
+/**
+ * Theme the gallery last updated time on a gallery list.
+ */
+function theme_image_gallery_updated($timestamp) {
+  return t('%date', array('%date' => format_date($timestamp))) . "\n";
+}
+
+/**
  * Returns (and possibly creates) a new vocabulary for Image galleries.
  */
 function _image_gallery_get_vid() {
@@ -467,3 +487,13 @@
 
   return $vid;
 }
+
+/**
+ * Implementation of hook_views_api().
+ */
+function image_gallery_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'image_gallery') .'/views',
+  );
+}
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery.views.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery.views.inc Base (1.1)
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery.views.inc Locally Modified (Based On 1.1)
@@ -4,5 +4,330 @@
 /**
  * @file
  * Image Gallery views integration.
+ *
+ * A gallery is made up of two views:
+ * - a view of nodes (the images)
+ * - a view of terms (the child galleries)
+ * The view of image nodes embeds the view of child gallery terms with a special
+ * image gallery display plugin.
+ * We provide the default views to make this, the display plugin, and a variety
+ * of fields and relationships for the child gallery view.
+ * The default views are:
+ * - image_gallery
+ * - image_gallery_terms
+ 
+ * There are two ways of getting the image gallery cover image:
+ * - a plain field. This allows complex code like recursion (check the gallery itself, 
+ *   if empty, check the child galleries, etc)
+ *   Plain field also allows us to grab the sort order set on the gallery images
+ *   and get the first image from that order as the front.
+ *   (combining the two options will be MONSTROUS!)
+ * - a relationship
+ *   This gets us onto the node table, so any fields can be used for the cover.
+ *   Depth is possible too -- eg,
+ *   "the newest image out of the gammery or its immediate children"
+ *   However recursion is not possible.
+ *
+ * So we have two families of handlers:
+ * - field handlers
+ * - relationship handlers
+ * Between these many ways of getting a cover image are possible. The handlers
+ * are fairly generic, and further possibilities can be obtained just by
+ * defining more fields with those handlers.
  */
 
+/**
+ * Implementation of hook_views_data_alter().
+ * Add fields for image gallery (ie vocabulary terms) to the term_data table.
+ */
+function image_gallery_views_data_alter(&$data) {
+  // ----------------------------------------------------------------------
+  // Relationships for cover node.
+  //
+  // These allow any node field to be used to create the gallery cover node.
+  // The limitation, however, is that either consider the immediate gallery,
+  // or a flat pool of the gallery and descendants.
+  // Note that a bug in Views -- http://drupal.org/node/380560 -- will cause
+  // an error message when adding node fields on these relationships.
+  $data['term_data']['image_gallery_cover_latest'] = array(
+    'group' => t('Image gallery'),    
+    'relationship' => array(
+      'title' => t('Latest image'),
+      'label'  => t('Cover image, latest'),
+      'help' => t('Relate an image gallery to its most recently updated node (does not consider child galleries).'),
+      'handler' => 'image_gallery_handler_relationship_gallery_cover',
+      'base'   => 'node',
+      'field'  => 'nid',
+      'correlated field' => 'tid',
+      'subquery order' => ' gallery_cover_node.created DESC ',
+    ),
+  );
+  $data['term_data']['image_gallery_cover_oldest'] = array(
+    'group' => t('Image gallery'),
+    'relationship' => array(
+      'title' => t('Oldest image'),
+      'label'  => t('Cover image, oldest'),
+      'help' => t('Relate an image gallery to its oldest node (does not consider child galleries).'),
+      'handler' => 'image_gallery_handler_relationship_gallery_cover',
+      'base'   => 'node',
+      'field'  => 'nid',
+      'correlated field' => 'tid',
+      'subquery order' => ' gallery_cover_node.created ASC ',
+    ),
+  );
+  $data['term_data']['image_gallery_cover_node_title'] = array(
+    'group' => t('Image gallery'),
+    'relationship' => array(
+      'title' => t('First image by title'),
+      'label'  => t('Cover image, first by title'),
+      'help' => t('Relate an image gallery to its first node when sorted by title (does not consider child galleries).'),
+      'handler' => 'image_gallery_handler_relationship_gallery_cover',
+      'base'   => 'node',
+      'field'  => 'nid',
+      'correlated field' => 'tid',
+      'subquery order' => ' gallery_cover_node.title ASC ',
+    ),
+  );
+
+  // ----------------------------------------------------------------------
+  // Simple fields.
+
+  // Gallery count.
+  $data['term_data']['image_gallery_count'] = array(
+    'group' => t('Image gallery'),
+    'field' => array(
+      'title' => t('Count'),
+      'help' => t('Count of items in a gallery.'),
+      'handler' => 'image_gallery_handler_field_gallery_count',
+    ),
+  );
+  
+  // ----------------------------------------------------------------------
+  // Fields for cover image.
+  //
+  // These use a combination of code and separate queries to get a cover node.
+  // This makes them more powerful that using the relationship cover node,
+  // as we can consider child galleries recursively rather than just
+  // flattening all descendant galleries.
+  // We can also do complex things such as grab the top-most node from the
+  // gallery according to how the view for that gallery sorts them.
+  // The downside however is that without a relationship, the fields here are
+  // all you've got.
+  // To add more fields, define them on term_data and optionally add handlers.
+  // See image_gallery_handler_field_gallery_cover for more information.
+  $data['term_data']['image_gallery_latest_thumbnail'] = array(
+    'group' => t('Image gallery'),    
+    'field' => array(
+      'title' => t('Latest image'),
+      'help' => t('The most recently posted image in the gallery or its child galleries.'),
+      'handler' => 'image_gallery_handler_field_gallery_cover_thumbnail',
+      'order clause' => 'n.sticky DESC, n.created DESC',
+    ),
+  );
+  $data['term_data']['image_gallery_latest_time'] = array(
+    'group' => t('Image gallery'),    
+    'field' => array(
+      'title' => t('Last updated time'),
+      'help' => t('The time of the most recently posted image in the gallery or its child galleries.'),
+      'handler' => 'image_gallery_handler_field_gallery_cover_latest_time',
+      'order clause' => 'n.sticky DESC, n.created DESC',
+    ),
+  );
+  $data['term_data']['image_gallery_first_title'] = array(
+    'group' => t('Image gallery'),
+    'field' => array(
+      'title' => t('First image by title'),
+      'help' => t('The first posted image in the gallery or its child galleries.'),
+      'handler' => 'image_gallery_handler_field_gallery_cover_thumbnail',
+      'order clause' => 'n.sticky DESC, n.title ASC',
+    ),
+  );
+  $data['term_data']['image_gallery_oldest_thumbnail'] = array(
+    'group' => t('Image gallery'),
+    'field' => array(
+      'title' => t('Oldest image'),
+      'help' => t('The first posted image in the gallery or its child galleries.'),
+      'handler' => 'image_gallery_handler_field_gallery_cover_thumbnail',
+      'order clause' => 'n.sticky DESC, n.created ASC',
+    ),
+  );
+
+  // Add a parent term argument to the term_hierarchy table.
+  // We need this because the Views relationship won't work for top-level
+  // terms that have no parent. See http://drupal.org/node/408180 for details.
+  // Note that only basic validation should be used with this, not term ID
+  // validation, because we want to be able to pass a value of 0 to mean
+  // 'terms with no parent'.
+  $data['term_hierarchy']['image_gallery_parent'] = array(
+    'real field' => 'parent',
+    'title' => t('Parent term'),
+    'help' => t('The parent term of the term. This can produce duplicate entries if you are using a vocabulary that allows multiple parents.'),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function image_gallery_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'image_gallery') . '/views',
+    ),
+    'handlers' => array(
+      'image_gallery_handler_field_gallery_count' => array(
+        'parent' => 'views_handler_field_taxonomy',
+      ),
+      'image_gallery_handler_field_gallery_cover' => array(
+        'parent' => 'views_handler_field_taxonomy',
+     ),
+      'image_gallery_handler_field_gallery_cover_thumbnail' => array(
+        'parent' => 'image_gallery_handler_field_gallery_cover',
+     ),
+      'image_gallery_handler_field_gallery_cover_latest_time' => array(
+        'parent' => 'image_gallery_handler_field_gallery_cover',
+      ),
+      'image_gallery_handler_relationship_gallery_cover' => array(
+        'parent' => 'views_handler_relationship',
+      ),
+      'image_gallery_plugin_display_image_gallery' => array(
+         'parent' => 'views_plugin_display_page',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_views_plugins().
+ */
+function image_gallery_views_plugins() {
+  return array(
+    'display' => array(
+      'image_gallery' => array(
+        'title' => t('Gallery'),
+        'help' => t('Display the view as a gallery of images, with a URL and menu links.'),
+        'parent' => 'page',
+        'handler' => 'image_gallery_plugin_display_image_gallery',
+        'theme' => 'views_view',
+        'uses hook menu' => TRUE,
+        'use ajax' => TRUE,
+        'use pager' => TRUE,
+        'accept attachments' => TRUE,
+        'admin' => t('Page'),
+        'help topic' => 'display-page', // TODO ??
+        'path' => drupal_get_path('module', 'image_gallery') . '/views',
+      ),
+    ),
+    'style' => array(
+      'image_gallery' => array(
+        'title'  => 'Gallery',
+        'help' => t('Displays items in a fluid grid.'),
+        'parent' => 'list',
+        'handler' => 'views_plugin_style_list',
+        'theme path' => drupal_get_path('module', 'image_gallery') . '/views/theme',
+        'theme file' => 'theme.inc',
+        'theme' => 'image_gallery_view_image_gallery',
+        'uses row plugin' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'normal',
+        'help topic' => 'style-list',
+      ),
+      'image_gallery_terms' => array(
+        'title'  => 'Subgallery list',
+        'help' => t('Displays subgalleries in a formatted list.'),
+        'parent' => 'list',
+        'handler' => 'views_plugin_style_list',
+        'theme path' => drupal_get_path('module', 'image_gallery') . '/views/theme',
+        'theme file' => 'theme.inc',
+        'theme' => 'image_gallery_view_image_gallery_terms',
+        'uses row plugin' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'normal',
+        'help topic' => 'style-list',
+      ),
+    ),
+  );
+}
+
+/**
+ * Join handler for relationships that join with a subquery as the left field.
+ * To use this join, set 'left query' in the definition as a subquery to go on
+ * the left side of the JOIN condition, ie:
+ *  LEFT JOIN node node_term_data ON ([YOUR SUBQUERY HERE]) = node_term_data.nid
+ */
+class image_gallery_join_subquery extends views_join {
+  // PHP 4 doesn't call constructors of the base class automatically from a
+  // constructor of a derived class. It is your responsibility to propagate
+  // the call to constructors upstream where appropriate.
+  function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') {
+    parent::construct($table, $left_table, $left_field, $field, $extra, $type);
+
+    $this->left_query = $this->definition['left query'];
+  }
+
+  /**
+   * Build the SQL for the join this object represents.
+   */
+  function join($table, &$query) {
+    $left = $query->get_table_info($this->left_table);
+    $output = " $this->type JOIN {" . $this->table . "} $table[alias] ON ($this->left_query) = $table[alias].$this->field";
+
+    // Tack on the extra.
+    if (isset($this->extra)) {
+      if (is_array($this->extra)) {
+        $extras = array();
+        foreach ($this->extra as $info) {
+          $extra = '';
+          // Figure out the table name. Remember, only use aliases provided
+          // if at all possible.
+          $join_table = '';
+          if (!array_key_exists('table', $info)) {
+            $join_table = $table['alias'] . '.';
+          }
+          elseif (isset($info['table'])) {
+            $join_table = $info['table'] . '.';
+          }
+
+          // And now deal with the value and the operator.  Set $q to
+          // a single-quote for non-numeric values and the
+          // empty-string for numeric values, then wrap all values in $q.
+          $raw_value = $this->db_safe($info['value']);
+          $q = (empty($info['numeric']) ? "'" : '');
+
+          if (is_array($raw_value)) {
+            $operator = !empty($info['operator']) ? $info['operator'] : 'IN';
+            // Transform from IN() notation to = notation if just one value.
+            if (count($raw_value) == 1) {
+              $value = $q . array_shift($raw_value) . $q;
+              $operator = $operator == 'NOT IN' ? '!=' : '=';
+            }
+            else {
+              $value = "($q" . implode("$q, $q", $raw_value) . "$q)";
+            }
+          }
+          else {
+            $operator = !empty($info['operator']) ? $info['operator'] : '=';
+            $value = "$q$raw_value$q";
+          }
+          $extras[] = "$join_table$info[field] $operator $value";
+        }
+
+        if ($extras) {
+          if (count($extras) == 1) {
+            $output .= ' AND ' . array_shift($extras);
+          }
+          else {
+            $output .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')';
+          }
+        }
+      }
+      else if ($this->extra && is_string($this->extra)) {
+        $output .= " AND ($this->extra)";
+      }
+    }
+    return $output;
+  }
+} // class image_gallery_join_subquery
+
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery.views_default.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery.views_default.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery.views_default.inc Locally New
@@ -0,0 +1,420 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function image_gallery_views_default_views() {
+  $view = new view;
+  $view->name = 'image_gallery';
+  $view->description = 'The default gallery of image nodes from Image gallery module.';
+  $view->tag = 'image_gallery';
+  $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(
+    'image_image' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+      ),
+      'link_to_node' => 1,
+      'image_derivative' => 'thumbnail',
+      'exclude' => 0,
+      'id' => 'image_image',
+      'table' => 'node',
+      'field' => 'image_image',
+      'relationship' => 'none',
+    ),
+    'title' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+      ),
+      'link_to_node' => 1,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('sorts', array(
+    'title' => array(
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+    ),
+    'changed' => array(
+      'order' => 'DESC',
+      'granularity' => 'second',
+      'id' => 'changed',
+      'table' => 'node',
+      'field' => 'changed',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('arguments', array(
+    'null' => array(
+      'default_action' => 'default',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => '',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'none',
+      'validate_fail' => 'not found',
+      'must_not_be' => 0,
+      'id' => 'null',
+      'table' => 'views',
+      'field' => 'null',
+      'relationship' => 'none',
+      'default_options_div_prefix' => '',
+      'default_argument_user' => 0,
+      'default_argument_fixed' => 'tid',
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'image' => 0,
+        'page' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(
+        '1' => 0,
+      ),
+      'validate_argument_type' => 'tid',
+      'user_argument_type' => '',
+      'restrict_user_roles' => 0,
+      'user_roles' => array(),
+      'image_size' => array(
+        '_original' => '_original',
+        'thumbnail' => 'thumbnail',
+        'preview' => 'preview',
+      ),
+      'validate_argument_php' => '',
+    ),
+    'tid' => array(
+      'default_action' => 'empty',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => '%2',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'numeric',
+      'validate_fail' => 'not found',
+      'break_phrase' => 0,
+      'add_table' => 0,
+      'require_value' => 0,
+      'reduce_duplicates' => 0,
+      'set_breadcrumb' => 1,
+      'id' => 'tid',
+      'table' => 'term_node',
+      'field' => 'tid',
+      'relationship' => 'none',
+      'default_options_div_prefix' => '',
+      'default_argument_user' => 0,
+      'default_argument_fixed' => '',
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'image' => 0,
+        'page' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(
+        '1' => 1,
+      ),
+      'validate_argument_type' => 'tid',
+      'user_argument_type' => 'uid',
+      'restrict_user_roles' => 0,
+      'user_roles' => array(),
+      'image_size' => array(
+        '_original' => '_original',
+        'thumbnail' => 'thumbnail',
+        'preview' => 'preview',
+      ),
+      'validate_argument_php' => '',
+      'override' => array(
+        'button' => 'Override',
+      ),
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'type' => array(
+      'operator' => 'in',
+      'value' => array(
+        'image' => 'image',
+      ),
+      'group' => '0',
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'id' => 'type',
+      'table' => 'node',
+      'field' => 'type',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('title', 'Image galleries');
+  $handler->override_option('empty', 'There are no images in this gallery.');
+  $handler->override_option('empty_format', '1');
+  $handler->override_option('style_plugin', 'image_gallery');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'type' => 'ul',
+  ));
+  $handler = $view->new_display('image_gallery', 'Gallery', 'image_gallery_1');
+  $handler->override_option('path', 'image');
+  $handler->override_option('menu', array(
+    'type' => 'none',
+    'title' => '',
+    'description' => '',
+    'weight' => 0,
+    'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+    'type' => 'none',
+    'title' => '',
+    'description' => '',
+    'weight' => 0,
+  ));
+  $views[$view->name] = $view;
+
+  $view = new view;
+  $view->name = 'image_gallery_terms';
+  $view->description = 'The default list of descendant galleries from Image gallery module. Displayed within the image gallery view.';
+  $view->tag = 'image_gallery';
+  $view->view_php = '';
+  $view->base_table = 'term_data';
+  $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(
+    'image_gallery_latest_thumbnail_1' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+      ),
+      'link_to_taxonomy' => 1,
+      'depth' => 'all',
+      'descendants' => 'flat',
+      'image_derivative' => 'thumbnail',
+      'exclude' => 0,
+      'id' => 'image_gallery_latest_thumbnail_1',
+      'table' => 'term_data',
+      'field' => 'image_gallery_latest_thumbnail',
+      'relationship' => 'none',
+    ),
+    'name' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 1,
+        'text' => '<h3>[name]</h3>',
+        'make_link' => 0,
+        'path' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+      ),
+      'link_to_taxonomy' => 1,
+      'exclude' => 0,
+      'id' => 'name',
+      'table' => 'term_data',
+      'field' => 'name',
+      'relationship' => 'none',
+    ),
+    'image_gallery_count' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+      ),
+      'link_to_taxonomy' => 0,
+      'exclude' => 0,
+      'id' => 'image_gallery_count',
+      'table' => 'term_data',
+      'field' => 'image_gallery_count',
+      'relationship' => 'none',
+    ),
+    'image_gallery_latest_time' => array(
+      'label' => 'Last updated',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+      ),
+      'link_to_taxonomy' => 0,
+      'depth' => 'all',
+      'descendants' => 'flat',
+      'exclude' => 0,
+      'id' => 'image_gallery_latest_time',
+      'table' => 'term_data',
+      'field' => 'image_gallery_latest_time',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('sorts', array(
+    'weight' => array(
+      'order' => 'ASC',
+      'id' => 'weight',
+      'table' => 'term_data',
+      'field' => 'weight',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('arguments', array(
+    'image_gallery_parent' => array(
+      'default_action' => 'ignore',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => '',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'none',
+      'validate_fail' => 'not found',
+      'break_phrase' => 0,
+      'not' => 0,
+      'id' => 'image_gallery_parent',
+      'table' => 'term_hierarchy',
+      'field' => 'image_gallery_parent',
+      'relationship' => 'none',
+      'default_options_div_prefix' => '',
+      'default_argument_user' => 0,
+      'default_argument_fixed' => '',
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'image' => 0,
+        'page' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(
+        '1' => 1,
+      ),
+      'validate_argument_type' => 'tid',
+      'user_argument_type' => 'uid',
+      'restrict_user_roles' => 0,
+      'user_roles' => array(),
+      'image_size' => array(
+        '_original' => '_original',
+        'thumbnail' => 'thumbnail',
+        'preview' => 'preview',
+      ),
+      'validate_argument_php' => '',
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'vid' => array(
+      'operator' => 'in',
+      'value' => array(
+        '1' => '1',
+      ),
+      'group' => '0',
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'id' => 'vid',
+      'table' => 'term_data',
+      'field' => 'vid',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('items_per_page', 0);
+  $handler->override_option('style_plugin', 'image_gallery_terms');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'type' => 'ul',
+  ));
+  $views[$view->name] = $view;
+
+  return $views;
+}
+
+
+
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_count.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_count.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_count.inc Locally New
@@ -0,0 +1,27 @@
+<?php
+// $Id$
+
+/**
+ * Views handler for Image gallery count field. This counts all the nodes in
+ * the gallery, including descendant galleries, using taxonomy.module's
+ * taxonomy_term_count_nodes.
+ */
+class image_gallery_handler_field_gallery_count extends views_handler_field_taxonomy {  
+  /**
+   * Override query() so we don't query: fake field.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+  
+  /**
+   * Return field html.
+   */
+  function render($values) {
+    $count = taxonomy_term_count_nodes($values->tid, 'image');
+    $output = theme('image_gallery_count', $count);
+    return $this->render_link($output, $values);
+  }
+}
+
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover.inc Locally New
@@ -0,0 +1,233 @@
+<?php
+// $Id$
+
+/**
+ * Parent class for field handlers that gives us a gallery cover.
+ *
+ * This takes care of defining the descendant and depth options, getting and
+ * storing a query, and running the query to get the cover nid.
+ *
+ * There are several ways to use this class:
+ * - Define the ordering in the field definition, with an 'order clause' key.
+ *   This gets tacked onto the fairly simple node query defined in this handler.
+ * - Define your own query in the field definition with a 'basic query' key.
+ * - Subclass this handler and create your own query by overriding
+ *   get_cover_node_nid_query(). This allows some pretty complex stuff, such as
+ *   grabbing the query from another view.
+ */
+class image_gallery_handler_field_gallery_cover extends views_handler_field_taxonomy {
+  /**
+   * Constructor to provide additional fields to add.
+   */
+  function construct() {
+    parent::construct();
+
+    $this->additional_fields['tid'] = 'tid';
+  }
+
+  function init(&$view, $options) {
+    parent::init($view, $options);
+
+    // Store the image gallery vocabulary ID.
+    $this->vid = _image_gallery_get_vid();
+
+    // The name of a key that is safe to use in $values to stash our nid.
+    // This is just a dummy that should be overridden.
+    // Groups of handlers that use the same query (eg, latest image and last
+    // update time) should override this to a safe key that they can share.
+    // This avoids running the query/ies to get the cover nid multiple times for
+    // each row of the view.
+    // TODO: doesn't work and probably can't ever, because if the user adds more
+    // than one cover image, we can't reliably create a unique key here that
+    // another field can know to find.
+    /*
+    if ($this->definition['cover group']) {
+      $this->cover_stash =  $this->definition['cover group'];
+    }
+    else {
+      $this->cover_stash =  'image_gallery_cover';
+    }
+     */
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['depth'] = array('default' => 0);
+    $options['descendants'] = array('default' => 'single');
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $form['descendants'] = array(
+      '#type' => 'radios',
+      '#title' => t('Descendant handling'),
+      // Child handlers should replace this text with something more relevant
+      // to what they do.
+      '#description' => theme('advanced_help_topic', 'image_gallery', 'descendants') .
+        t('How to get data from subgalleries: either only select from this gallery itself, or consider subgalleries all together, or recurse into subgalleries if the gallery itself is empty.'),
+      '#options' => array(
+        'single'  => t('Only select from this gallery'),
+        'flat'    => t('Consider subgalleries, flattened.'),
+        'recurse' => t('Consider subgalleries, recursively. (Warning: this can produce many queries per row if your parent galleries are empty!).'),
+      ),
+      '#default_value' => $this->options['descendants'],
+    );
+
+    $form['depth'] = array(
+      '#type' => 'select',
+      '#title' => t('Depth'),
+      '#options' => array_merge(range(0, 10), array('all' => 'Unlimited')),
+      '#default_value' => $this->options['depth'],
+      '#description' => t('How deeply to go into subgalleries if one of the descendant options is selected above.'),
+    );
+  }
+
+  /**
+   * Get the cover nid for the current tid.
+   *
+   * This makes up our query from the field definition and handler functions,
+   * and then runs it according to the descendant and depth options given
+   * for the field.
+   */
+  function get_cover_node_nid($values) {
+    // The term id of the current gallery.
+    // This comes straight from the database row so should be safe for
+    // inclusion in a query.
+    $tid = $values->tid;
+
+    // Get the basic query but only once for all rows of the view.
+    // This can be set in the handler definition, or in the handler class's
+    // get_cover_node_nid_query function for more complex cases.
+    // The handler definition takes priority over the function.
+    // This is stored in the handler object so we only have to get it
+    // once for the whole view.
+    if (!isset($this->basic_query)) {
+      if (isset($this->definition['basic query'])) {
+        $this->basic_query = $this->definition['basic query'];
+      }
+      else {
+        $this->basic_query = $this->get_cover_node_nid_query();
+      }
+    }
+    
+    // If we don't have a query, return NULL now to prevent SQL errors.
+    if (is_null($this->basic_query)) {
+      return NULL;
+    }
+
+    // Add the definition's ORDER clause, if there is one.
+    if ($this->definition['order clause']) {
+      $this->basic_query = str_replace('***ORDER_CLAUSE***', $this->definition['order clause'], $this->basic_query);
+    }
+
+    // Look at the options set for this handler.
+    $depth = $this->options['depth'];
+    $descendants_method = $this->options['descendants'];
+
+    // Depth of 0 is the same as 'single'.
+    if ($depth === 0) {
+      $descendants_method = 'single';
+    }
+
+    // Add our WHERE clause.
+    switch ($descendants_method) {
+      // Plain: only consider this gallery.
+      // Recursive: only consider this gallery (we'll recurse later).
+      case 'single':
+      case 'recurse':
+        $where_clause = "tn.tid = $tid ";
+        $query = str_replace('***WHERE_CLAUSE***', $where_clause, $this->basic_query);
+        break;
+      // Flat: all descendant galleries considered for the cover query.
+      case 'flat':
+        if ($depth == 'all') {
+          $tree = taxonomy_get_tree($this->vid, $tid);
+        }
+        else {
+          $tree = taxonomy_get_tree($this->vid, $tid, -1, $depth);
+        }
+        $descendant_tids = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
+        // The values of $descendant_tids should be safe for raw inclusion in the
+        // SQL since they're all loaded from integer fields in the database.
+        $where_clause = 'tn.tid IN (' . implode(',', $descendant_tids) . ')';
+        $query = str_replace('***WHERE_CLAUSE***', $where_clause, $this->basic_query);
+        break;
+    }
+
+    // Run the query to get the cover nid.
+    if ($nid = db_result(db_query_range(db_rewrite_sql($query), '', 0, 1))) {
+      return $nid;
+    }
+
+    // We have no nid: the gallery is empty. Go into descendant galleries if the
+    // recurse option is set.
+    if ($this->options['descendants'] == 'recurse' && $this->options['depth'] > 0) {
+      $nid = $this->get_cover_node_nid_recurse($tid, 1);
+      return $nid;
+    }
+  }
+
+  /**
+   * Recursively query descendant tids until we get a cover nid.
+   *
+   * Warning! This is probably quite intensive, as it drills down the term
+   * hierarchy doing a query on each term until it finds a node -- and this is
+   * done for EVERY row of the main gallery term view!
+   *
+   * @param $tid The tid whose children we should investigate for a cover nid.
+   * @param $recurse The current recursion depth.
+   */
+  function get_cover_node_nid_recurse($tid, $recurse) {
+    $tree = taxonomy_get_tree($this->vid, $tid, -1, 1);
+    foreach ($tree as $term) {
+      $where_clause = 'tn.tid = ' . $term->tid;
+      $query = str_replace('***WHERE_CLAUSE***', $where_clause, $this->basic_query);
+      if ($nid = db_result(db_query_range(db_rewrite_sql($query), '', 0, 1))) {
+        return $nid;
+      }
+
+      // Recurse into this gallery, if we may.
+      if ($this->options['depth'] > $recurse) {
+        if ($nid = $this->get_cover_node_nid_recurse($term->tid, $recurse + 1)) {
+          return $nid;
+        }
+      }
+    }
+  }
+
+  /**
+   * The query this handler should use to gets its cover node id, unless
+   * the field definition specifies one.
+   *
+   * The return string should include a placeholder for the WHERE clause
+   * as in this basic case. This is where the tid(s) will go.
+   * The order clause should be supplied by the handler definition.
+   * Warning: this is NOT sophisticated stuff. The WHERE clause inserted into
+   * this string will expect to find a row "tn.tid" in the query.
+   */
+  function get_cover_node_nid_query() {
+    return 'SELECT n.nid from {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid ' .
+        "WHERE ***WHERE_CLAUSE*** AND n.type = 'image' AND n.status = 1 " .
+        'ORDER BY ***ORDER_CLAUSE***';
+  }
+
+  /**
+   * Override query() so we don't query: fake field.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  /**
+   * Returns field html. Just a dummy to inherit.
+   */
+  function render($values) {
+    $nid = $this->get_cover_node_nid($values);
+    return $nid;
+  }
+}
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover_latest_time.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover_latest_time.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover_latest_time.inc Locally New
@@ -0,0 +1,33 @@
+<?php
+// $Id$
+
+/**
+ * Field handler for the gallery's updated time.
+ */
+class image_gallery_handler_field_gallery_cover_latest_time extends image_gallery_handler_field_gallery_cover {
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Overwrite the descendants option so the text is relevant.
+    $form['descendants']['#description'] = theme('advanced_help_topic', 'image_gallery', 'descendants') .
+      t('Whether to only consider this gallery itself, or consider subgalleries all together, or recurse into subgalleries if the gallery itself is empty.');
+    $form['descendants']['#options'] = array(
+      'single'  => t('Only get latest time from this gallery'),
+      'flat'    => t('Consider subgalleries, flattened.'),
+      'recurse' => t('Consider subgalleries, recursively. (Warning: this can produce many queries per row if your parent galleries are empty!).'),
+    );
+  }
+  
+  /**
+   * Returns field html.
+   */
+  function render($values) {
+    $nid = $this->get_cover_node_nid($values);
+
+    $latest_node = node_load($nid);
+    if ($latest_node->changed) {
+      $output = theme('image_gallery_updated', $latest_node->changed);
+      return $this->render_link($output, $values);
+    }
+  }
+}
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover_thumbnail.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover_thumbnail.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_field_gallery_cover_thumbnail.inc Locally New
@@ -0,0 +1,64 @@
+<?php
+// $Id$
+
+/**
+ * Field handler for gallery cover node image.
+ *
+ * Displays a thumbnail of the cover image node, at the chosen derivative size.
+ * This covers basic cases where the handler definition can specify the query
+ * and the order to get the cover node.
+ */
+class image_gallery_handler_field_gallery_cover_thumbnail extends image_gallery_handler_field_gallery_cover {
+  /**
+   * Defines default values for options.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['image_derivative'] = array('default' => array(IMAGE_THUMBNAIL));
+
+    return $options;
+  }
+
+  /**
+   * Extends the field's basic options with more image specific options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Overwrite the descendants option so the text is relevant.
+    $form['descendants']['#description'] = // COMING SOON theme('advanced_help_topic', 'image_gallery', 'descendants') .
+      t('Whether to go into subgalleries when getting a cover image. Either: consider only this gallery itself, consider subgalleries all together, or recurse into subgalleries one by one if the gallery itself is empty.');
+    $form['descendants']['#options'] = array(
+      'single'  => t('Only get cover image from this gallery'),
+      'flat'    => t('Consider subgalleries, flattened.'),
+      'recurse' => t('Consider subgalleries, recursively. (Warning: this can produce many queries per row if your parent galleries are empty!).'),
+    );
+
+    foreach (image_get_sizes() as $key => $size) {
+      $sizes[$key] = $size['label'];
+    }
+    $form['image_derivative'] = array(
+      '#type' => 'select',
+      '#title' => t('Image size to show'),
+      '#options' => $sizes,
+      '#default_value' => $this->options['image_derivative'],
+      '#description' => t('Pick an image derivative to display.')
+    );
+  }
+
+  /**
+   * Returns field html.
+   */
+  function render($values) {
+    $nid = $this->get_cover_node_nid($values);
+
+    $latest_node = node_load($nid);
+    $output = image_display($latest_node, $this->options['image_derivative']);
+    $output = $this->render_link($output, $values);
+    // Wrap a common class so the thumbnail can be style no matter what field.
+    // TODO: theme function?
+    return '<div class="image-gallery-view-cover-thumbnail">' . $output . '</div>';
+  }
+}
+
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_relationship_gallery_cover.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_relationship_gallery_cover.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery_handler_relationship_gallery_cover.inc Locally New
@@ -0,0 +1,180 @@
+<?php
+// $Id$
+/*
+ * @file
+ * Handlers for image gallery cover node.
+ *
+ * NOTE: a bug in Views -- http://drupal.org/node/380560 -- will cause
+ * errors when adding node fields on this relationship.
+ */
+
+/**
+ * Relationship handler for image gallery cover node.
+ *
+ * This joins to the node table from the term_data table, giving us a node
+ * based on the given term. This is the gallery's cover node, which supplies the
+ * image shown in the list of galleries.
+ * Using this relationship allows the user to add any node fields to the view.
+ * The downside is that while we can consider descendant galleries too, there is
+ * no recursion: setting a depth of 1 means "give me the (best) image out of
+ * the gallery and its immediate children" -- the images are considered
+ * as a flat pool from which to pick.
+ *
+ * This handler uses a special join object to create the relationship join on
+ * the value returned by a subquery.
+ * For example:
+ *  "given term tid 1, find the nid of the most recent node with that term"
+ *  in other words, the most recent image in this gallery.
+ *
+ * The main part of the query is provided in this handler.
+ * To use this, you need to give the subquery sort order, and the subquery's
+ * correlated field (the field from the main views query on which to link) --
+ * this is usually just 'tid'.
+ * 
+ * Define these as follows:
+ *  'relationship' => array(
+ *    'title' => t('Latest image'),
+ *    'label'  => t('Cover image, latest'),
+ *    'help' => t('Relate an image gallery to its most recently updated node (does not consider child galleries).'),
+ *    'handler' => 'image_gallery_handler_relationship_gallery_cover',
+ *    'base'   => 'node',
+ *    'field'  => 'nid',
+ *    'correlated field' => 'tid',
+ *    'subquery order' => ' gallery_cover_node.changed DESC ',
+ *  )
+ * This example gets you a cover image that is the latest changed node.
+ *
+ * If you need a different query, subclass this handler and override the
+ * left_query() method to return your own subquery on which to join.
+ */
+class image_gallery_handler_relationship_gallery_cover extends views_handler_relationship {
+  /**
+   * Defines default values for options.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['depth'] = array('default' => array(1));
+
+    return $options;
+  }
+
+  /**
+   * Extends the field's basic options with more image specific
+   * options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $form['depth'] = array(
+      '#type' => 'weight',
+      '#title' => t('Depth'),
+      '#default_value' => $this->options['depth'],
+      '#description' => t('The depth will determine how deep to look into descendant galleries to cover nodes.' .
+         'There is no recursion: so setting the depth to 1 will choose the best fitting node out of the pool of images in the gallery and its children taken all together.' .
+         'Setting this to 0 will only consider the gallery itself.'
+       ),
+    );
+  }
+
+  /**
+   * Return the subquery to use for the left side of the relationship join clause.
+   * 
+   */
+  function left_query() {
+    $order = $this->definition['subquery order'];
+    $field = $this->definition['correlated field'];
+    $where_tid = $this->table_alias . '.' . $field;
+
+    $subquery = "\nSELECT gallery_cover_node.nid FROM " .
+      "{term_node} gallery_cover_term_node INNER JOIN {node} gallery_cover_node \n" .
+      "ON gallery_cover_term_node.nid = gallery_cover_node.nid ";
+    $where = "  WHERE gallery_cover_node.status = 1 AND " .
+      "gallery_cover_term_node.tid = $where_tid ";
+
+    // Depth: this is shamelessly ripped from views_handler_argument_term_node_tid_depth
+    if ($this->options['depth'] > 0) {
+      $subquery .= "    LEFT JOIN {term_hierarchy} th ON th.tid = gallery_cover_term_node.tid\n";
+      $last = "th";
+      foreach (range(1, abs($this->options['depth'])) as $count) {
+        $subquery .= "    LEFT JOIN {term_hierarchy} th$count ON $last.parent = th$count.tid\n";
+        $where .= "\n OR th$count.tid = $where_tid\n";
+        $last = "th$count";
+      }
+    }
+    else if ($this->options['depth'] < 0) {
+      $last = "tn";
+      foreach (range(1, abs($this->options['depth'])) as $count) {
+        $subquery .= "    LEFT JOIN {term_hierarchy} th$count ON $last.tid = th$count.parent\n";
+        $where .= "\n OR th$count.tid = $where_tid\n";
+        $last = "th$count";
+      }
+    }
+    $subquery = "$subquery $where ORDER BY $order LIMIT 1";
+
+    return $subquery;
+  }
+
+  /**
+   * Called to implement a relationship in a query.
+   */
+  function query() {
+    // Figure out what base table this relationship brings to the party.
+    $table_data = views_fetch_data($this->definition['base']);
+    $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
+
+    $this->ensure_my_table();
+
+    $def = $this->definition;
+    $def['table'] = $this->definition['base'];
+    $def['field'] = $base_field;
+    $def['left_table'] = $this->table_alias;
+    $def['left_field'] = $this->field;
+    if (!empty($this->options['required'])) {
+      $def['type'] = 'INNER';
+    }
+
+    if (!empty($this->definition['left query'])) {
+      $def['left query'] = $this->definition['left query'];
+    }
+    else {
+      $def['left query'] = $this->left_query();
+    }
+
+    if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
+      $join = new $def['join_handler'];
+    }
+    else {
+      $join = new image_gallery_join_subquery();
+    }
+
+    $join->definition = $def;
+    $join->construct();
+    $join->adjusted = TRUE;
+
+    // use a short alias for this:
+    $alias = $def['table'] . '_' . $this->table;
+
+    $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
+  }
+}
+
+/**
+ * Subclass example.
+ */
+/*
+class image_gallery_handler_relationship_gallery_cover_example extends views_handler_relationship {
+  function left_query($field) {
+    $order = $this->definition['left query order'];
+    $sub_query = 'SELECT gallery_cover_node.nid FROM ' .
+      '{term_node} gallery_cover_term_node INNER JOIN ' .
+      ' {node} gallery_cover_node ' .
+      'ON gallery_cover_term_node.nid = gallery_cover_node.nid ' .
+      'WHERE gallery_cover_node.status = 1 AND ' .
+      'gallery_cover_term_node.tid = ' . $field . ' ' .
+      ORDER BY $order .
+      'LIMIT 1';
+
+    return $sub_query;
+  }
+*/
Index: contributions/modules/image/contrib/image_gallery/views/image_gallery_plugin_display_image_gallery.inc
--- contributions/modules/image/contrib/image_gallery/views/image_gallery_plugin_display_image_gallery.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/image_gallery_plugin_display_image_gallery.inc Locally New
@@ -0,0 +1,75 @@
+<?php
+// $Id:$
+
+/**
+ * A display plugin for image galleries.
+ *
+ * This embeds the gallery terms view above the gallery view that uses it.
+ * We don't use an attachment because the two views are of different types
+ * (nodes and terms) and killing off *all* the node view options in the
+ * attachment is prohibitive (if even possible at all).
+ */
+
+/**
+ * The plugin that handles a full page.
+ *
+ * @ingroup views_display_plugins
+ */
+class image_gallery_plugin_display_image_gallery extends views_plugin_display_page {
+
+  function options_summary(&$categories, &$options) {
+    // It is very important to call the parent function here:
+    parent::options_summary($categories, $options);
+
+    // Since we're childing off the 'page' type, we'll still *call* our
+    // category 'page' but let's override it so it says feed settings.
+    $categories['page'] = array(
+      'title' => t('Gallery page settings'),
+    );
+  }
+
+  /**
+   * Embed the gallery term view above the normal rendering of this view.
+   */
+  function render() {
+    // Check the current gallery view has a tid argument.
+    if (isset($this->view->argument['tid'])) {
+      $args = $this->view->argument['tid']->value;
+
+      // No argument means we are at the top-level gallery.
+      // We need to pass an argument of 0 to the gallery terms view so it
+      // shows only the top level.
+      if (count($args) == 0) {
+        // Have to pass as string, otherwise it gets eaten by views validation.
+        $args = array(0 => '0');
+      }
+
+      $this->gallery_terms_view = views_get_view('image_gallery_terms');
+
+      // Tack THIS view onto the gallery terms view. We don't do anything with
+      // this yet, but other handlers might need it.
+      $this->gallery_terms_view->embedding_view =& $this->view;
+
+      $output = $this->gallery_terms_view->preview('default', $args);
+    }
+
+    // Render this view as normal.
+    $output .= parent::render();
+
+    return $output;
+  }
+
+  /**
+   * There are two special cases here:
+   * - An empty view might have subgalleries. If that is the case we don't show
+   * the empty text.
+   * - Force the view title when no arguments are present.
+   */
+  function render_empty() {
+    drupal_set_title(filter_xss_admin($this->view->get_title()));
+
+    if (count($this->gallery_terms_view->result) == 0) {
+      return $this->render_textarea('empty');
+    }
+  }
+}
Index: contributions/modules/image/contrib/image_gallery/views/theme/image-gallery-view-image-gallery-terms.tpl.php
--- contributions/modules/image/contrib/image_gallery/views/theme/image-gallery-view-image-gallery-terms.tpl.php No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/theme/image-gallery-view-image-gallery-terms.tpl.php Locally New
@@ -0,0 +1,21 @@
+<?php
+// $Id$
+/**
+ * @file
+ * Template for a list of gallery terms.
+ *
+ * - $title : The title of this group of rows.  May be empty.
+ * - $options['type'] will either be ul or ol.
+ * @ingroup views_templates
+ */
+?>
+<div class="item-list image-gallery-terms clear-block">
+  <?php if (!empty($title)) : ?>
+    <h3><?php print $title; ?></h3>
+  <?php endif; ?>
+  <<?php print $options['type']; ?> class="galleries">
+    <?php foreach ($rows as $id => $row): ?>
+      <li class="<?php print $classes[$id]; ?> clear-block"><?php print $row; ?></li>
+    <?php endforeach; ?>
+  </<?php print $options['type']; ?>>
+</div>
Index: contributions/modules/image/contrib/image_gallery/views/theme/image-gallery-view-image-gallery.tpl.php
--- contributions/modules/image/contrib/image_gallery/views/theme/image-gallery-view-image-gallery.tpl.php No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/theme/image-gallery-view-image-gallery.tpl.php Locally New
@@ -0,0 +1,21 @@
+<?php
+// $Id$
+/**
+ * @file
+ * Template for a list of gallery nodes.
+ *
+ * - $title : The title of this group of rows.  May be empty.
+ * - $options['type'] will either be ul or ol.
+ * @ingroup views_templates
+ */
+?>
+<div class="item-list image-gallery-nodes clear-block">
+  <?php if (!empty($title)) : ?>
+    <h3><?php print $title; ?></h3>
+  <?php endif; ?>
+  <<?php print $options['type']; ?>>
+    <?php foreach ($rows as $id => $row): ?>
+      <li class="<?php print $classes[$id]; ?>"><?php print $row; ?></li>
+    <?php endforeach; ?>
+  </<?php print $options['type']; ?>>
+</div>
Index: contributions/modules/image/contrib/image_gallery/views/theme/theme.inc
--- contributions/modules/image/contrib/image_gallery/views/theme/theme.inc No Base Revision
+++ contributions/modules/image/contrib/image_gallery/views/theme/theme.inc Locally New
@@ -0,0 +1,15 @@
+<?php
+// $Id$
+/**
+ * @file
+ *
+ * Theme preprocessors for image gallery plugins.
+ */
+
+function template_preprocess_image_gallery_view_image_gallery(&$vars) {
+  drupal_add_css(drupal_get_path('module', 'image_gallery') .'/image_gallery.css');
+}
+
+function template_preprocess_image_gallery_view_image_gallery_terms(&$vars) {
+  drupal_add_css(drupal_get_path('module', 'image_gallery') .'/image_gallery.css');
+}
