Index: includes/project_edit_issues.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue/includes/project_edit_issues.inc,v
retrieving revision 1.2
diff -u -r1.2 project_edit_issues.inc
--- includes/project_edit_issues.inc	5 May 2009 19:15:58 -0000	1.2
+++ includes/project_edit_issues.inc	27 Jul 2009 06:43:32 -0000
@@ -226,6 +226,10 @@
  * @see project_issue_project_edit_issues
  */
 function project_issue_project_edit_form_submit($form, &$form_state) {
+  // Load the original project node and components.
+  $original_node = node_load($form_state['values']['nid']);
+  $original_components = array_values($original_node->project_issue['components']);
+
   $components = array();
   if (!empty($form_state['values']['component_add']['name'])) {
     $components[trim($form_state['values']['component_add']['name'])] = $form_state['values']['component_add']['weight'];
@@ -236,13 +240,33 @@
     }
   }
   asort($components);
+
+  // Determine which components were renamed upon submit.
+  $index = 0;
+  foreach(array_keys($components) as $new_component) {
+    if ($original_components[$index] != $new_component) {
+      $renamed_components[$original_components[$index]] = $new_component;
+    }
+    $index++;
+  }
+
   $components = serialize(array_keys($components));
   $default_component = !empty($form_state['values']['default_component']) ? $form_state['values']['default_component'] : '';
+
+  // If the default component is amongst the renamed components, save the new
+  // component name instead of the old one.
+  if ($default_component && isset($renamed_components[$default_component])) {
+    $default_component = $renamed_components[$default_component];
+  }
+
   $mail_copy_filter = serialize($form_state['values']['mail_copy_filter']);
   $mail_copy_filter_state = serialize($form_state['values']['mail_copy_filter_state']);
 
   db_query("UPDATE {project_issue_projects} SET issues = %d, components = '%s',default_component = '%s', mail_digest = '%s', mail_reminder = %d, mail_copy = '%s', mail_copy_filter = '%s', mail_copy_filter_state = '%s', help = '%s' WHERE nid = %d", $form_state['values']['issues'], $components, $default_component, $form_state['values']['mail_digest'], $form_state['values']['mail_reminder'], $form_state['values']['mail_copy'], $mail_copy_filter, $mail_copy_filter_state, $form_state['values']['help'], $form_state['values']['nid']);
   db_query("UPDATE {node} SET changed = %d WHERE nid = %d", time(), $form_state['values']['nid']);
+
+  project_issue_component_rename_start_batch($original_node, $renamed_components);
+
   drupal_set_message(t('Issue settings have been saved.'));
 }
 
@@ -287,4 +311,38 @@
   db_query("UPDATE {node} SET changed = %d WHERE nid = %d", time(), $project->nid);
 }
 
+/*
+ * Set up and launch batch processing via the Batch API.
+ *
+ * @param $project
+ * @param $old_name
+ * @param $new_name
+ */
+function project_issue_component_rename_start_batch($project, $renamed_components) {
+  require_once(drupal_get_path('module', 'project_issue') . '/includes/batch.inc');
+
+  // Set up the batch operation which will update the component for each
+  // issues & comments.
+  $batch = array(
+    'finished' => 'project_issue_batch_rename_component_finished',
+    'title' => t('Updating issues & follow-ups.'),
+    'error_message' => t('An error occured while updating issues.'),
+    'file' => drupal_get_path('module', 'project_issue') . "/includes/batch.inc"
+  );
+
+  foreach ($renamed_components as $old_name => $new_name) {
+    $batch['operations'][] = array('project_issue_batch_rename_component_current_values', array($project, $old_name, $new_name));
+    $batch['operations'][] = array('project_issue_batch_rename_component_original_values', array($project, $old_name, $new_name));
+  }
+
+  batch_set($batch);
+}
+
+function project_issue_batch_rename_component_finished($success, $results, $operations) {
+  if ($success) {
+    $pid = $results['pid'];
+    drupal_set_message(t('Successfully processed !processed issues. <ul><li>Updated the current component for !issue_updated issues.</li><li>Updated the component for !comments_updated comments.</li><li>Updated the original component for !orig_updated issues.</li></ul>', array('!processed' => $results['processed'], '!issue_updated' => $results['issues_updated'], '!comments_updated' => $results['comments_updated'], '!orig_updated' => $results['orig_updated'])));
+    drupal_goto("node/$pid/edit/issues");
+  }
+}
 
Index: includes/batch.inc
===================================================================
RCS file: includes/batch.inc
diff -N includes/batch.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/batch.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,63 @@
+<?php
+
+function project_issue_batch_rename_component_current_values($project, $old_name, $new_name, &$context) {
+  $components = $project->project_issue['components'];
+  $components[array_search($old_name, $components, TRUE)] = $new_name;
+  db_query("UPDATE {project_issue_projects} SET components = '%s' WHERE nid = %d", serialize($components), $project->nid);
+
+  // Update the *current* component for all the issues in one go.
+  db_query("UPDATE {project_issues} SET component = '%s' WHERE pid = %d AND component = '%s'", $new_name, $project->nid, $old_name);
+  $context['results']['issues_updated']  = db_affected_rows();
+
+  // Update all the comments in one go
+  db_query("UPDATE {project_issue_comments} SET component = '%s' WHERE pid = %d AND component = '%s'", $new_name, $project->nid, $old_name);
+  $context['results']['comments_updated']  = db_affected_rows();
+
+  $context['finished'] = 1;
+}
+
+function project_issue_batch_rename_component_original_values($project, $old_name, $new_name, &$context) {
+  // Get the list of issues to update
+  if (!isset($context['sandbox']['issues'])) {
+    // We need to get every single issue from the database, since issues might have originally
+    // belonged to the project for which we're changing the component
+    $result = db_query('SELECT DISTINCT nid FROM {project_issues}');
+    while($nid = db_fetch_array($result)) {
+      $context['sandbox']['issues'][] = $nid['nid'];
+    }
+
+    $context['finished']                  = 0;
+    $context['sandbox']['max']            = count($context['sandbox']['issues']);
+    $context['sandbox']['progress']       = 0;
+    $conetxt['message']                   = 'Updated @current out of @total issues.';
+    $context['results']['orig_updated']   = 0;
+    $context['results']['processed']      = 0;
+    $context['results']['pid']            = $project->nid;
+
+    // Make sure there is at least one issue to update, otherwise set finished = 1 and
+    // stop processing immediately.
+    if (!$context['sandbox']['max']) {
+      $context['finished'] = 1;
+      return;
+    }
+  }
+
+  if ($context['sandbox']['issues']) {
+    $nid = array_pop($context['sandbox']['issues']);
+    // The original component for an issue is stored in a serialized array, so we have to
+    // load each of the issues, change the value, and save back to the database.
+    $original_values = unserialize(db_result(db_query('SELECT original_issue_data FROM {project_issues} WHERE nid = %d', $nid)));
+    if ($original_values->pid == $project->nid) {
+      if ($original_values->component == $old_name) {
+        $original_values->component = $new_name;
+        db_query("UPDATE {project_issues} SET original_issue_data = '%s' WHERE nid = %d", serialize($original_values), $nid);
+        $context['results']['orig_updated']++;
+      }
+    }
+  }
+  $context['sandbox']['progress']++;
+  $context['results']['processed']++;
+
+  // Update the completion level.
+  $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+}
