Index: theme.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_calc/theme.inc,v
retrieving revision 1.10
diff -u -p -r1.10 theme.inc
--- theme.inc	15 Jan 2011 13:48:32 -0000	1.10
+++ theme.inc	16 Jan 2011 16:42:22 -0000
@@ -7,6 +7,7 @@
  * An array of preprocessors to fill variables for templates and helper
  * functions to make theming easier.
  */
+
 /**
  * Theme the form for the table style plugin
  */
@@ -66,7 +67,7 @@ function theme_views_calc_ui_table($form
  * Display a view as a table style.
  */
 function template_preprocess_views_calc_table(&$vars) {
-  $view     = $vars['view'];
+  $view = $vars['view'];
   if (!empty($view->views_calc_calculation)) {
     $vars['rows'] = array();
     return;
@@ -80,8 +81,6 @@ function template_preprocess_views_calc_
   // so that it can get rebuilt.
   $result   = $vars['rows'];
   $vars['rows'] = array();
-  $totals   = $view->totals;
-  $sub_totals = $view->sub_totals;
     
   $options  = $view->style_plugin->options;
   $handler  = $view->style_plugin;
@@ -99,8 +98,8 @@ function template_preprocess_views_calc_
     $query = '&' . $query;
   }
 
+  // Render the header labels.
   foreach ($columns as $field => $column) {
-    // render the header labels
     if ($field == $column && empty($fields[$field]->options['exclude'])) {
       $label = check_plain(!empty($fields[$field]) ? $fields[$field]->label() : '');
       if (empty($options['info'][$field]['sortable'])) {
@@ -133,7 +132,7 @@ function template_preprocess_views_calc_
     }
   }
 
-  // Render each field into its appropriate column.
+  // Render each field into its appropriate column. Preserve rows.
   foreach ($result as $num => $row) {
     foreach ($columns as $field => $column) {
       $field_output = $fields[$field]->theme($row);
@@ -164,68 +163,74 @@ function template_preprocess_views_calc_
   }
 
   // Add totals.
-  if($view->total_rows > $view->pager['items_per_page']) {
-    $process_available = array('sub_totals', 'totals');  
+  $vars['totals'] = array();
+  $vars['sub_totals'] = array();
+  if ($view->total_rows > $view->pager['items_per_page']
+    && $view->sub_totals) {
+    views_calc_table_total($vars, 'sub_totals', $view->sub_totals);
+  }
+  if ($view->totals) {
+    views_calc_table_total($vars, 'totals', $view->totals);
   }
-  else{
-    $process_available = array('totals');
-    $vars['sub_totals'] = array(); //if don't set, error in template
+
+  // Add classes.
+  $vars['class'] = 'views-table';
+  if (!empty($options['sticky'])) {
+    drupal_add_js('misc/tableheader.js');
+    $vars['class'] .= " sticky-enabled";
   }
-  foreach ($process_available as $process) {
-    $vars[$process] = array();
+}
+
+/**
+ * Build total var line.
+ */
+function views_calc_table_total(&$vars, $key, $totals) {
+  $view = $vars['view'];
+  $options  = $view->style_plugin->options;
+  $handler  = $view->style_plugin;
+  $fields   = &$view->field;
+  $columns  = $handler->sanitize_columns($options['columns'], $fields);
+
+    $vars[$key] = array();
     $added_label = array();
-    foreach ($columns as $field => $column) {
-      $field_alias = $fields[$field]->field_alias;
-      if ($field == $column && empty($fields[$field]->options['exclude'])) {
-        foreach ($$process as $num => $row) {
-          $type = '';
-          foreach ($row as $item) {
-            if (in_array($item, array_keys(_views_calc_calc_options()))) {
-              $type = $item;
-              break;
-            }
-          }
-          if (!empty($row->$field_alias) || (isset($row->$field_alias) && $row->$field_alias === 0)) {
-    
+
+    foreach ($view->views_calc_fields as $calc => $calc_fields) {
+      $row = $totals[$calc];
+      foreach ($columns as $field => $column) {
+        $field_alias = $fields[$field]->field_alias;
+        if ($field == $column && empty($fields[$field]->options['exclude'])) {
+          if (in_array($field, $calc_fields)
+            && isset($row->$field_alias)) {
             // COUNT is always a numeric value, no matter what kind of field it is.
-            if ($type == 'COUNT') {
-              $vars[$process][$type][$column] =  $row->$field_alias;
+            if ($calc == 'COUNT') {
+              $vars[$key][$calc][$column] =  $row->$field_alias;
             }
             // Calculations other than COUNT should run the value through the field's theme.
             // This will allow dates and numeric values to apply the right formatting to the result.
             else {
-              $vars[$process][$type][$column] =  $fields[$field]->theme($row);
+              $vars[$key][$calc][$column] =  $fields[$field]->theme($row);
             }
+          
           }
-          elseif (!empty($type)) {
+          else {
             // Add the calc type label into the first empty column.
             // Identify which is the sub total and which the grand total
             // when both are provided.
-            if (empty($added_label[$type])) {
-              if ($process == 'sub_totals') {
-                $label = t("Page !Calculation", array("!Calculation" => $type));
+            if (empty($added_label[$calc])) {
+              if ($key == 'sub_totals') {
+                $label = t("Page !Calculation", array("!Calculation" => $calc));
               }
               else {
-                $label = t("Total !Calculation", array("!Calculation" => $type));
+                $label = t("Total !Calculation", array("!Calculation" => $calc));
               }
-              $vars[$process][$type][$column] = $label;
-              $added_label[$type] = TRUE;
+              $vars[$key][$calc][$column] = $label;
+              $added_label[$calc] = TRUE;
             }
             else {
-              $vars[$process][$type][$column] = '';
+              $vars[$key][$calc][$column] = '';
             }
           }
         }
       }
     }
-  }
-
-  $vars['class'] = 'views-table';
-  if (!empty($options['sticky'])) {
-    drupal_add_js('misc/tableheader.js');
-    $vars['class'] .= " sticky-enabled";
-  }
-  
-  return;
-     
-}
\ No newline at end of file
+}
Index: views_calc.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_calc/views_calc.module,v
retrieving revision 1.14
diff -u -p -r1.14 views_calc.module
--- views_calc.module	13 Jun 2009 12:57:40 -0000	1.14
+++ views_calc.module	16 Jan 2011 16:42:22 -0000
@@ -4,6 +4,10 @@
  * This module will allow you to add calculated fields to views tables
  * and compute (SUM, COUNT, AVG, etc) columns of numeric data in a views table.
  */
+
+/**
+ * Implements hook_views_api().
+ */
 function views_calc_views_api() {
   return array(
     'api' => 2,
@@ -11,6 +15,9 @@ function views_calc_views_api() {
   );
 }
 
+/**
+ * Implements hook_theme().
+ */
 function views_calc_theme() {
   $path = drupal_get_path('module', 'views_calc');
   return array(
@@ -22,7 +29,7 @@ function views_calc_theme() {
 }
 
 /**
- * Implementation of hook_help().
+ * Implements hook_help().
  */
 function views_calc_help($section, $arg) {
   switch ($section) {
@@ -52,14 +59,20 @@ function _views_calc_operators() {
 }
 
 /**
- *  Column calculation alternatives
+ *  Column calculation alternatives.
  */
 function _views_calc_calc_options() {
-  return array('COUNT' => 'Count', 'SUM' => 'Sum', 'AVG' => 'Average', 'MIN' => 'Minimum', 'MAX' => 'Maximum');
+  return array(
+    'COUNT' => t('Count'),
+    'SUM' => t('Sum'),
+    'AVG' => t('Average'),
+    'MIN' => t('Minimum'),
+    'MAX' => t('Maximum'),
+  );
 }
 
 /**
- *  Result format options
+ *  Result format options.
  */
 function _views_calc_format_options() {
   $options = array(
@@ -76,7 +89,7 @@ function _views_calc_format_options() {
 }
 
 /**
- * Implementation of hook_perm().
+ * Implements hook_perm().
  *
  * The permission 'administer views calc' has rights to alter the SQL
  * operators that can be used in calculations.
@@ -85,12 +98,18 @@ function _views_calc_format_options() {
  * fields and set calculation columns on views.
  */
 function views_calc_perm() {
-  return array('create views calc', 'administer views calc');
+  return array(
+    'create views calc',
+    'administer views calc'
+  );
 }
 
+/**
+ * Implements hook_menu().
+ */
 function views_calc_menu() {
-
   $items = array();
+
   $items['admin/settings/views_calc'] = array(
     'title' => t('Views Calc'),
     'description' => t('Set Views Calc fields and columns.'),
@@ -140,7 +159,7 @@ function views_calc_menu() {
 }
 
 /**
- *  Implementation of hook_settings()
+ * FAPI settings_form.
  */
 function views_calc_settings_form() {
   drupal_set_title(t('Views Calc'));
@@ -158,12 +177,17 @@ function views_calc_settings_form() {
   return $form;
 }
 
+/**
+ * FAPI settings_form submit.
+ */
 function views_calc_settings_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
   variable_set('views_calc_operators', $form_values['views_calc_operators']);
 }
 
 /**
+ * FAPI fields_form.
+ *
  * Views Calc Fields tab on views list.
  */
 function views_calc_fields_form() {
@@ -269,7 +293,9 @@ function views_calc_field_form_item($i, 
 }
 
 /**
- *  Validate the views calc settings
+ * FAPI fields_form validate.
+ *
+ * Validate the views calc settings
  */
 function views_calc_fields_form_validate($form, &$form_state) {
   $form_values = $form_state['values'];
@@ -311,7 +337,9 @@ function views_calc_fields_form_validate
 }
 
 /**
- *  Save the views calc field settings
+ * FAPI fields_form submit.
+ *
+ * Save the views calc field settings
  */
 function views_calc_fields_form_submit($form, &$form_state) {
   $edit = $form_state['values'];
@@ -407,14 +435,14 @@ function _views_calc_substitutions($base
 }
 
 /**
- *  Views calc fields result object
+ * Views calc fields result object.
  */
 function _views_calc_fields() {
   return db_query("SELECT * FROM {views_calc_fields}");
 }
 
 /**
- *  An array of allowable calculation values.
+ * An array of allowable calculation values.
  */
 function _views_calc_replacements() {
   $operators     = array_filter(_views_calc_operators(), 'trim');
@@ -424,6 +452,8 @@ function _views_calc_replacements() {
 
 
 /**
+ * FAPI export_form.
+ *
  * Field export form.
  */
 function views_calc_export_form() {
@@ -449,6 +479,8 @@ function views_calc_export_form() {
 }
 
 /**
+ * FAPI import_form.
+ *
  * Field import form.
  */
 function views_calc_import_form(&$form_state, $type_name = '') {
@@ -477,7 +509,9 @@ function views_calc_import_form(&$form_s
 }
 
 /**
- *  Submit handler for import form.
+ * FAPI import_form submit.
+ *
+ * Submit handler for import form.
  */
 function views_calc_import_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
@@ -499,4 +533,4 @@ function views_calc_import_form_submit($
   $form_state = array('values' => $fields);
   drupal_execute('views_calc_fields_form', $form_state);
 
-}
\ No newline at end of file
+}
Index: views_calc_table.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_calc/views_calc_table.inc,v
retrieving revision 1.20
diff -u -p -r1.20 views_calc_table.inc
--- views_calc_table.inc	15 Jan 2011 13:00:17 -0000	1.20
+++ views_calc_table.inc	16 Jan 2011 16:42:22 -0000
@@ -12,6 +12,9 @@
  */
 class views_calc_table extends views_plugin_style_table {
  
+  /**
+   * Option definition.
+   */
   function option_definition() {
     $options = parent::option_definition();
 
@@ -73,6 +76,11 @@ class views_calc_table extends views_plu
   }
 
   /**
+   * Views Method pre_render().
+   *
+   * Build grand total and page sub total.
+   * Query calc fields using sub-view and add data.
+   *
    * TODO
    * figure out what changes are needed so Views field groups will work.
    */
@@ -89,51 +97,81 @@ class views_calc_table extends views_plu
     }
     $this->view->totals = array();
     $this->view->sub_totals = array();
+    $this->view->views_calc_fields = $this->get_calc_fields();
       
     // Subtotals and pager totals require a list of the specific
     // values to include.
     $paged = FALSE;
     if (!empty($this->view->pager) 
     && !empty($this->view->pager['use_pager']) 
-    && !empty($this->view->pager['items_per_page'])) {
+    && !empty($this->view->pager['items_per_page'])
+    && $this->view->total_rows > $this->view->pager['items_per_page']) {
       $ids = array();
       foreach ($this->view->result as $delta => $value) {
         $ids[] = $value->{$this->view->base_field};
       }
       // Add sub_total rows to the results.
+      // We need one query per aggregation because theming needs unrenamed views field alias.
       // TODO Looks like we have problems unless we
       // force a non-page display, need to keep an eye on this.
       foreach ($calc_fields as $calc => $field) {
-        if ($summary_view = views_get_view($this->view->name)) {
-          $summary_view->set_display($this->view->current_display);
-          $summary_view->set_arguments($this->view->args);
-          $summary_view->display_handler->set_option('use_pager', FALSE);
-          $summary_view->views_calc_calculation = $calc;
-          $summary_view->views_calc_ids = $ids;
-          $summary_view->views_calc_sub_total = TRUE;
-          $summary_view->is_cacheable = FALSE;
-          $summary_view->preview();
-          $this->view->sub_totals[] = array_shift($summary_view->result);
-        }
+        $this->execute_summary_view($calc, $ids);
       }
     }
     
     // Add grand totals to the results.
     foreach ($calc_fields as $calc => $field) {
-      if ($summary_view = views_get_view($this->view->name)) {
-        $summary_view->set_display($this->view->current_display);
-        $summary_view->set_arguments($this->view->args);
-        $summary_view->display_handler->set_option('use_pager', FALSE);
-        $summary_view->views_calc_calculation = $calc;
-        $summary_view->views_calc_ids = array();
-        $summary_view->views_calc_sub_total = FALSE;
-        $summary_view->is_cacheable = FALSE;
-        $summary_view->preview();
-        $this->view->totals[] = array_shift($summary_view->result);
+      $this->execute_summary_view($calc);
+    }
+  }
+
+  function execute_summary_view($calc, $ids = array()) {
+    // Load the view and check access to the given display.
+    if (!($summary_view = views_get_view($this->view->name)) || !$this->view->access($this->view->current_display)) {
+      return NULL;
+    }
+
+    // Make sure the view is completely valid.
+    $errors = $summary_view->validate();
+    if (is_array($errors)) {
+      foreach ($errors as $error) {
+        drupal_set_message($error, 'error');
+      }
+      return NULL;
+    }
+
+    // intialize summary view
+    $is_subtotal = !empty($ids);
+    $summary_view->preview = TRUE;
+    $summary_view->is_cacheable = FALSE;
+    $summary_view->views_calc_calculation = $calc;
+    $summary_view->views_calc_ids = $ids;
+    $summary_view->views_calc_sub_total = $is_subtotal;
+    $summary_view->views_calc_fields = $this->view->views_calc_fields;
+
+    // if not subtotal, get all results
+    if (!$is_subtotal) {
+      $summary_view->pager['items_per_page'] = 0;
+    }
+
+    // Execute and render the view in preview mode. Note that we only store
+    // the result if the executed view query returns any result.
+    $summary_view->pre_execute($this->view->args);
+    $summary_view->execute($this->view->current_display);
+    $summary_view->post_execute();
+    if (!empty($summary_view->result)) {
+      if ($is_subtotal) {
+        $this->view->sub_totals[$calc] = array_shift($summary_view->result);
+      }
+      else {
+        $this->view->totals[$calc] = array_shift($summary_view->result);
       }
     }
   }
 
+  /**
+   * Views Method query().
+   */
   function query() {
     parent::query();
     
@@ -142,70 +180,26 @@ class views_calc_table extends views_plu
       return;
     }
     // If there are no calc fields, do nothing.
-    if (!$calc_fields = $this->get_calc_fields()) {
+    //if (!$calc_fields = $this->get_calc_fields()) {
+    if (!$this->view->views_calc_fields) {
       return;
     }
 
-    if (!empty($this->view->views_calc_sub_total)) {
-      $this->query_sub_total();
-    }
-    else {
-      $this->query_total();
-    }
+    // Rebuild the total query.
+    $this->query_total();
   }
   
   /**
-   * 
-   */
-  function query_sub_total() {
-    // Create summary rows.
-    $calc_fields = $this->get_calc_fields();
-    $calc = $this->view->views_calc_calculation;
-    // Empty out any fields that have been added to the query,
-    // we don't need them for the summary totals.
-    $fields = $calc_fields[$calc];
-    // Clear out any sorting and grouping, it can create unexpected results
-    // when Views adds aggregation values for the sorts.
-    $this->view->query->orderby = array();
-    $this->view->query->groupby = array();
-    
-    // Empty out any fields that have been added to the query,
-    // we don't need them for the summary totals.
-    $this->view->query->fields = array();
-    foreach ($this->view->field as $field) {
-      $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field;
-      $query_alias = $field->field_alias;
-      // Bail if we have a broken handler.
-      if ($query_alias == 'unknown') {
-        continue;
-      }
-      if (in_array($field->field, $fields)) {
-        // Calculated fields.
-        $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias);
-        $this->view->query->add_table($field->table, NULL, NULL, $field->table);
-      }
-      else {
-        // Empty fields that have no calculations.
-        $this->view->query->add_field(NULL, "MAX('')", $query_alias);
-      }
-      // Add a dummy field for the groupby.
-      $this->view->query->add_field(NULL, "MAX('" . $calc . "')", "TOTAL_". $calc);
-    }
-    // TODO This won't work right with relationships, need a fix here.
-    if (!empty($this->view->views_calc_ids)) {
-      $this->view->query->add_where(NULL, $this->view->base_table . "." . $this->view->base_field . " IN (%s)", implode(',', $this->view->views_calc_ids));
-    }
-  }
-  
-  /**
-   * The grand total can be computed using GROUPBY without regard
-   * to pager values.
+   * Query grand total
+   *
+   * The grand total can be computed using GROUPBY without regard to pager values.
+   *
+   * @see query().
    */
   function query_total() {
     // Create summary rows.
-    $calc_fields = $this->get_calc_fields();
     $calc = $this->view->views_calc_calculation;
-    $fields = $calc_fields[$calc];
+    $fields = $this->view->views_calc_fields[$calc];
     
     // Empty out any fields that have been added to the query,
     // we don't need them for the summary totals.
@@ -229,14 +223,21 @@ class views_calc_table extends views_plu
       }
       else {
         // Empty fields that have no calculations.
-        $this->view->query->add_field(NULL, "MAX('')", $query_alias);
+        $this->view->query->add_field(NULL, "NULL", $query_alias);
       }
-      // Add a dummy field for the groupby.
-      $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc);
+    }
+    // TODO This won't work right with relationships, need a fix here.
+    // Limit to specific primary ids. This is for subtotals.
+    if (!empty($this->view->views_calc_ids)) {
+      $this->view->query->add_where(NULL, $this->view->base_table . "." . $this->view->base_field . " IN (%s)", implode(',', $this->view->views_calc_ids));
     }
   }
 
+  /**
+   * Get views_calc fields
+   */
   function get_calc_fields() {
+    // TODO on preview this returns the wrong list.
     $options  = $this->view->style_plugin->options;
     $handler  = $this->view->style_plugin;
     $fields   = $this->view->field;
