Index: includes/admin.settings.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/includes/admin.settings.inc,v
retrieving revision 1.2
diff -u -p -r1.2 admin.settings.inc
--- includes/admin.settings.inc	4 Apr 2009 06:30:21 -0000	1.2
+++ includes/admin.settings.inc	6 Jul 2009 23:56:31 -0000
@@ -74,6 +74,22 @@ function project_issue_settings_form(&$f
     '#element_validate' => array('project_issue_validate_default_components'),
   );
 
+  $form['project_issue_add_new_component'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Add a new component to existing projects'),
+    '#default_value' => '',
+    '#required' => FALSE,
+    '#description' => t('Enter a new component, to be added to existing projects.'),
+  );
+  $form['project_issue_add_new_component_conditional'] = array(
+    '#type' => 'textfield',
+    '#title' => t('But only if they have this other component'),
+    '#default_value' => '',
+    '#required' => FALSE,
+    '#description' => t('Optionally, enter an current component name to only add the new one to projects with that component.'),
+  );
+  $form['#submit'][] = 'project_issue_admin_settings_submit';
+
   if (module_exists('mailhandler')) {
     // TODO: move this stuff to mailhandler.module ?
     $items = array(t('<none>'));
@@ -134,6 +150,114 @@ function project_issue_validate_default_
 }
 
 /**
+ * Submit handler for new component additions to project_issue_settings_form
+ */
+function project_issue_admin_settings_submit($form, &$form_state) {
+  $newcomponent = trim($form_state['values']['project_issue_add_new_component']);
+  $conditional = trim($form_state['values']['project_issue_add_new_component_conditional']);
+  unset($form_state['values']['project_issue_add_new_component'], $form_state['values']['project_issue_add_new_component_conditional']);
+  project_issue_add_new_component($newcomponent, $conditional);
+}
+
+/**
+ * Function to add new components to all existing project
+ * optionally only where existing component is already present
+ */
+function project_issue_add_new_component($new_component, $conditional = NULL) {
+  $newcomponent = $new_component;
+  $conditional = $conditional;
+  if ($newcomponent) {
+    if ($conditional) {
+      $title = t('Adding new component %component to existing projects with %conditional.', array('%component' => $newcomponent, '%conditional' => $conditional));
+    }
+    else {
+      $title = t('Adding new component %component to existing projects.', array('%component' => $newcomponent));
+    }
+    $batch = array(
+      'operations' => array(
+            array('project_issue_batch_component_add', array($newcomponent, $conditional))
+      ),
+      'finished' => 'project_issue_batch_component_add_finished',
+      'title' => $title,
+      'init_message' => $title,
+      'progress_message' => t('Updating components...'),
+      'error_message' => t('Error in adding new component to existing projects.'),
+      'file' => drupal_get_path('module', 'project_issue').'/includes/admin.settings.inc',
+    );
+    batch_set($batch);
+  }
+}
+
+/**
+ * Batch Component Add
+ */
+function project_issue_batch_component_add($newcomponent, $conditional, &$context) {
+  if (!isset($context['sandbox']['projects'])) {
+    // We need to get projects from the database which match the conditional, if any.
+    // If there is no conditional, we're adding the component to all existing projects (unless it has it already)
+    if ($conditional){
+      $result = db_query("SELECT nid FROM {project_issue_projects} WHERE components LIKE '%%%s%%'", $conditional);
+    }
+    else {
+      $result = db_query('SELECT nid FROM {project_issue_projects}');
+    }
+    while ($nid = db_fetch_array($result)) {
+      $context['sandbox']['projects'][] = $nid['nid'];
+    }
+    $context['finished'] = 0;
+    $context['sandbox']['max'] = count($context['sandbox']['projects']);
+    $context['sandbox']['progress'] = 0;
+    $context['message'] = t('Adding new component...');
+    $context['results']['updated'] = 0;
+    $context['results']['processed'] = 0;
+    // Make sure there is at least one project to update, otherwise set finished = 1 and
+    // stop processing immediately.
+    if (!$context['sandbox']['max']) {
+      $context['finished'] = 1;
+      return;
+    }
+  }
+
+  if ($context['sandbox']['projects']) {
+    $nid = array_pop($context['sandbox']['projects']);
+    $node = node_load($nid);
+    // The component list for a project is stored in a serialized array, so we have to
+    // load the array, add the value at the end (if it doesn't have it already), and save back to the database.
+    $components = unserialize(db_result(db_query('SELECT components FROM {project_issue_projects} WHERE nid = %d', $nid)));
+    if (!in_array($newcomponent, $components)) {
+      $components[] = $newcomponent;
+      db_query("UPDATE {project_issue_projects} SET components = '%s' WHERE nid = %d", serialize($components), $nid);
+      //drupal_set_message($node->title. ' updated with ' . $newcomponent);
+      $context['results']['updated']++;
+    }
+  }
+  $context['sandbox']['progress']++;
+  $context['results']['processed']++;
+  $context['message']= t('Now processing Project: @node', array('@node' => $node->title));
+
+  // Update the completion level.
+  $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+}
+
+
+/**
+* Batch Component Add 'finished' callback
+*/
+function project_issue_batch_component_add_finished($success, $results, $operations) {
+  if ($success) {
+    $message = t('@updated projects updated out of @processed processed.', array('@updated' => $results['updated'], '@processed' =>
+	$results['processed'])); 
+  }
+  else {
+    // An error occurred.
+    // $operations contains the operations that remained unprocessed.
+    $error_operation = reset($operations);
+    $message = t('An error occurred while processing with arguments: @error', array('@error' => var_export($error_operation[0], TRUE)));    
+  }
+  drupal_set_message($message);
+}
+
+/**
  * Validates that the followup user exists, and has sufficient permissions
  * to follow up on issues.
  */
