? .bzrignore
? includes/.plugins.inc.marks
Index: includes/plugins.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/plugins.inc,v
retrieving revision 1.51
diff -u -p -r1.51 plugins.inc
--- includes/plugins.inc	3 Apr 2008 16:38:14 -0000	1.51
+++ includes/plugins.inc	3 Apr 2008 21:08:47 -0000
@@ -42,6 +42,14 @@ function views_views_plugins() {
         'use pager' => TRUE,
         'use more' => TRUE,
       ),
+      'attachment' => array(
+        'title' => t('Attachment'),
+        'help' => t('Display the view as an attachment that can be attached to other displays.'),
+        'handler' => 'views_plugin_display_attachment',
+        'use ajax' => TRUE,
+        'use pager' => TRUE,
+        'use more' => TRUE,
+      ),
     ),
     'style' => array(
       'default' => array(
@@ -163,6 +171,11 @@ class views_plugin_display extends views
   function is_default_display() { return FALSE; }
 
   /**
+   * Determine if this display may be attached to another display.
+   */
+  function is_attachment() { return FALSE; }
+          
+  /**
    * Determine if this display uses exposed filters, so the view
    * will know whether or not to build them.
    */
@@ -607,6 +620,19 @@ class views_plugin_display extends views
         'desc' => t("Change this display's !name.", array('!name' => strtolower($name))),
       );
     }
+    
+    $attachment = $this->get_option('attachment');
+    if (!$attachment) {
+      $attachment = t('None');
+    }
+
+    $options['attachment'] = array(
+      'category' => 'basic',
+      'title' => t('Attachment'),
+      'value' => $attachment,
+      'desc' => t('Attach another display to this one.'),
+    );
+
   }
 
   /**
@@ -803,6 +829,23 @@ class views_plugin_display extends views
 
         $form['empty_format'] = filter_form($this->get_option('empty_format'), NULL, array('empty_format'));
         break;
+      case 'attachment':
+        $form['#title'] .= t('Attach another view to this one');
+        $options = array();
+        foreach ($this->view->display as $id => $display) {
+          if ($id != $this->display->id && $display->handler->is_attachment()) {
+            $options[$id] = $display->display_title;
+          }
+        }
+        $form['attachment'] = array(
+          '#type' => 'select',
+          '#options' => array(0 => t('None')) + $options,
+          '#default_value' => 0, // no attachment by default
+        );
+        if (empty($options)) {
+          $form['attachment']['#description'] = t('There are no attachment displays available.');
+        }
+        break;
       case 'style_plugin':
         $form['#title'] .= t('How should this view be styled');
         $form['style_plugin'] =  array(
@@ -862,6 +905,9 @@ class views_plugin_display extends views
    */
   function options_validate($form, &$form_state) {
     switch ($form_state['section']) {
+      case 'attachment':
+        // TODO: make sure we aren't somehow attaching a display to itself.
+        break;
       case 'style_options':
         $style = TRUE;
       case 'row_options':
@@ -909,6 +955,9 @@ class views_plugin_display extends views
       case 'distinct':
         $this->set_option($section, $form_state['values'][$section]);
         break;
+      case 'attachment':
+        $this->set_option($section, $form_state['values'][$section]);
+        break;
       case 'row_plugin':
         // This if prevents resetting options to default if they don't change
         // the plugin.
@@ -1592,7 +1641,7 @@ class views_plugin_display_block extends
   }
 
   /**
-   * Provide the summary for page options in the views UI.
+   * Provide the summary for block options in the views UI.
    *
    * This output is returned as an array.
    */
@@ -1676,6 +1725,111 @@ class views_plugin_display_block extends
 }
 
 /**
+ * The plugin that handles an attachment display.
+ */
+class views_plugin_display_attachment extends views_plugin_display {
+  /**
+   * Execute the attachment view.
+   */
+  function options(&$display) {
+    parent::options(&$display);
+    $display->display_options['attachment_position'] = 'before';
+    $display->display_options['inherit_arguments'] = TRUE;
+  }
+
+  function execute() {
+    return $this->view->render();
+  }
+
+  /**
+   * This display may be attached to other displays.
+   */
+  function is_attachment() {
+    return TRUE;
+  }
+
+  /**
+   * Provide the summary for attachment options in the views UI.
+   *
+   * This output is returned as an array.
+   */
+  function options_summary(&$categories, &$options) {
+    // It is very important to call the parent function here:
+    parent::options_summary($categories, $options);
+
+    $categories['attachment'] = array(
+      'title' => t('Attachment settings'),
+    );
+
+    $options['inherit_arguments'] = array(
+      'category' => 'attachment',
+      'title' => t('Inherit arguments'),
+      'value' => $this->get_option('inherit_arguments') ? t('Yes') : t('No'),
+    );
+
+    $options['attachment_position'] = array(
+      'category' => 'attachment',
+      'title' => t('Position'),
+      'value' => ($this->get_option('attachment_position') == 'before') ? t('Before') : t('After'),
+    );
+  }
+
+  /**
+   * Provide the default form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    // It is very important to call the parent function here:
+    parent::options_form($form, $form_state);
+
+    switch ($form_state['section']) {
+      case 'inherit_arguments':
+        $form['#title'] .= t('Inherit arguments');
+        $form['inherit_arguments'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Inherit'),
+          '#description' => t('Should this display inherit its arguments from the parent display to which it is attached?'),
+          '#default_value' => $this->get_option('inherit_arguments'),
+        );
+        break;
+      case 'attachment_position':
+        $form['#title'] .= t('Position');
+        $form['attachment_position'] = array(
+          '#type' => 'radios',
+          '#description' => t('Attach before or after the parent display?'),
+          '#options' => array(
+            'before' => t('Before'),
+            'after' => t('After'),
+          ),
+          '#default_value' => $this->get_option('attachment_position'),
+        );
+        break;
+    }
+  }
+
+  /**
+   * Perform any necessary changes to the form values prior to storage.
+   * There is no need for this function to actually store the data.
+   */
+  function options_submit($form, &$form_state) {
+    // It is very important to call the parent function here:
+    parent::options_submit($form, $form_state);
+    switch ($form_state['section']) {
+      case 'inherit_arguments':
+        $this->set_option('inherit_arguments', $form_state['values']['inherit_arguments']);
+        break;
+      case 'attachment_position':
+        $this->set_option('attachment_position', $form_state['values']['attachment_position']);
+        break;
+    }
+  }
+
+  /**
+   * Attachment views do not use exposed widgets.
+   */
+  function uses_exposed() { return FALSE; }
+}
+
+/**
  * @}
  */
 
Index: includes/view.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/view.inc,v
retrieving revision 1.64
diff -u -p -r1.64 view.inc
--- includes/view.inc	3 Apr 2008 17:19:19 -0000	1.64
+++ includes/view.inc	3 Apr 2008 21:08:48 -0000
@@ -639,7 +639,28 @@ class view extends views_db_object {
     $this->display_handler->pre_execute();
 
     // Execute the view
-    return $this->display_handler->execute();
+    $display_output = $this->display_handler->execute();
+
+    // Execute the attachment, if any
+    $attachment = $this->display_handler->get_option('attachment');
+    if ($attachment) {
+      $attached_view = views_get_view($this->name);
+      $attachment_handler = &$this->display[$attachment]->handler;
+      if (!$attachment_handler->get_option('inherit_arguments')) {
+        $args = array();
+      }
+      $attachment_output = $attached_view->execute_display($attachment, $args);
+      switch ($attachment_handler->get_option('attachment_position')) {
+        case 'before':
+          $display_output = $attachment_output . $display_output;
+          break;
+        case 'after':
+          $display_output .= $attachment_output;
+          break;
+      }
+    }
+
+    return $display_output;
   }
 
   /**
