Index: modules/content_multigroup/views/content_multigroup.views.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/content_multigroup/views/Attic/content_multigroup.views.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 content_multigroup.views.inc
--- modules/content_multigroup/views/content_multigroup.views.inc	8 Aug 2009 18:59:46 -0000	1.1.2.1
+++ modules/content_multigroup/views/content_multigroup.views.inc	9 Aug 2009 11:14:35 -0000
@@ -6,3 +6,93 @@
  * Views integration for Content Multigroups.
  */
 
+/**
+ * Implementation of hook_views_data_alter().
+ */
+function content_multigroup_views_data_alter(&$data) {
+  // Scan all field groups in the system.
+  foreach (fieldgroup_groups() as $type_name => $groups) {
+    $type_label = node_get_types('name', $type_name);
+
+    foreach ($groups as $group_name => $group) {
+      // Let's focus on multigroups that really accept multiple values.
+      if ($group['group_type'] == 'multigroup' && !empty($group['settings']['multigroup']['multiple'])) {
+
+        // Scan all fields in this multigroup.
+        foreach (array_keys($group['fields']) as $field_name) {
+          // Load information about the field for this particular content type.
+          $field = content_fields($field_name, $type_name);
+
+          // Get the Views table alias.
+          $table_alias = content_views_tablename($field);
+
+          // Discard this field if not already exposed to Views.
+          if (isset($data[$table_alias])) {
+            $db_info = content_database_info($field);
+
+            // Build the name for this filter.
+            // The scope of field groups is the content type itself. You can
+            // have more than one group with the same name but different fields
+            // in different content types. Therefore, we need the type name and
+            // multigroup name. But we also need to allow users choose any field
+            // in the multigroup as the master field, therefore we also need the
+            // field name here.
+            $db_field = 'multigroup_'. $type_name .'_'. $group_name .'_'. $field_name;
+
+            // Build the labels for the filter.
+            $label_truncated = truncate_utf8(t($field['widget']['label']), 10, TRUE);
+            $title = t('@group_label in @type_label using @field_label (!field_name)', array(
+              '@field_label' => t($field['widget']['label']),
+              '!field_name' => $field_name,
+              '@group_label' => t($group['label']),
+              '@type_label' => $type_label,
+            ));
+            $title_short = t('@group_label in @type_label (@label-truncated)', array(
+              '@group_label' => t($group['label']),
+              '@type_label' => $type_label,
+              '@label-truncated' => $label_truncated,
+            ));
+            $help_text = t('Synchronize @group_label fields in @type_label type using @field_label as the master field.', array(
+              '@group_label' => t($group['label']),
+              '@type_label' => $type_label,
+              '@field_label' => t($field['widget']['label']),
+            ));
+
+            // Attach the new filter to the master field table.
+            $data[$table_alias][$db_field] = array(
+              'group' => t('Content multigroup'),
+              'title' => $title,
+              'title short' => $title_short,
+              'help' => $help_text,
+              'filter' => array(
+                'field' => $db_field,
+                'table' => $db_info['table'],
+                'handler' => 'content_multigroup_handler_filter',
+                'content_type_name' => $type_name,
+                'content_group_name' => $group_name,
+                'content_field_name' => $field_name,
+                'allow empty' => TRUE,
+              ),
+            );
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function content_multigroup_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'content_multigroup') . '/views/handlers',
+    ),
+    'handlers' => array(
+      'content_multigroup_handler_filter' => array(
+        'parent' => 'views_handler_filter',
+      ),
+    ),
+  );
+}
Index: modules/content_multigroup/views/handlers/content_multigroup_handler_filter.inc
===================================================================
RCS file: modules/content_multigroup/views/handlers/content_multigroup_handler_filter.inc
diff -N modules/content_multigroup/views/handlers/content_multigroup_handler_filter.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/content_multigroup/views/handlers/content_multigroup_handler_filter.inc	9 Aug 2009 11:18:07 -0000
@@ -0,0 +1,53 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Defines a content_multigroup filter object in views.
+ *
+ * This filter allows you to associate the deltas in a multigroup so that
+ * views doesn't do a cross-join across all values in multivalue fields.
+ */
+class content_multigroup_handler_filter extends views_handler_filter {
+  var $content_multigroup_fields;
+
+  function construct() {
+    parent::construct();
+
+    // Load information about the multigroup.
+    $groups = fieldgroup_groups($this->definition['content_type_name']);
+    $group = $groups[$this->definition['content_group_name']];
+
+    // Load information about all fields in the multigroup, except the master field.
+    $this->content_multigroup_fields = array();
+    foreach (array_keys($group['fields']) as $field_name) {
+      if (($field_name != $this->definition['content_field_name'])) {
+        $field = content_fields($field_name, $this->definition['content_type_name']);
+        $table_alias = content_views_tablename($field);
+        $this->content_multigroup_fields[$table_alias] = $field;
+      }
+    }
+  }
+
+  function can_expose() {
+    return FALSE;
+  }
+
+  function admin_summary() {
+    return t('+ delta');
+  }
+
+  function query() {
+    // Ensure my table joins the master field table with the node table.
+    $base_alias = $this->ensure_my_table();
+
+    // Now we want to join the master field table with all other tables
+    // related to fields in the same multigroup, but adding the delta
+    // key to the join condition. This is what allows us to keep delta
+    // values in sync for all fields in the same multigroup.
+    foreach ($this->content_multigroup_fields as $table_alias => $field) {
+      $alias = $this->query->ensure_table($table_alias, $this->relationship);
+      $this->query->table_queue[$table_alias]['join']->extra = $base_alias  .'.delta = '. $alias .'.delta';
+    }
+  }
+}
