--- workflow/workflow.module	Thu Mar 23 10:40:18 2006
+++ patches/workflow.module.patched	Thu Mar 23 09:54:48 2006
@@ -152,10 +152,12 @@
 function workflow_form_alter($form_id, &$form) {
   if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
     $node = $form['#node'];
-    $choices = workflow_field_choices($node);
-    if (count($choices) < 2) { // bail out if user has no new target state(s)
+    $state_change_required = workflow_role_requires_state_change_for_node($node);
+    $choices = workflow_field_choices($node, $state_change_required);
+    if (count($choices) < 2 && !$state_change_required) { // bail out if user has no new target state(s) and workflow does not require a state change
       return;
     }
+    //echo workflow_role_requires_state_change($node);
     ksort($choices);
     $wid = workflow_get_workflow_for_type($node->type);
     $name = check_plain(workflow_get_name($wid));
@@ -187,6 +189,41 @@
 }
 
 /**
+ * Check to see if current node requires a state change given current user role and current node state
+ *
+ * @param object $node
+ */
+function workflow_role_requires_state_change_for_node($node) {
+	global $user;
+    
+    $roles = array_keys($user->roles);
+    $current_sid = workflow_node_current_state($node);
+    if ($user->uid == $node->uid && $node->uid > 0) { // if the node author
+      $roles += array('author' => 'author');
+    }
+    if ($user->uid == 1) { // if the superuser
+      $roles = 'ALL';
+    }
+    if (!is_array($roles)) { $roles = array($roles); }
+    
+    foreach($roles as $role) {
+	  $required = db_result(db_query("SELECT COUNT(*) FROM {workflow_role_requires_state_change} WHERE sid = %d && role = '%s'", $current_sid, $role));
+	  if($required > 0) {
+	    return true;
+	  }
+	}
+	return false;
+}
+
+function workflow_check_state_change_required($sid,$rid) {
+  $required = db_result(db_query("SELECT COUNT(*) FROM {workflow_role_requires_state_change} WHERE sid = %d && role = '%s'", $sid, $rid));
+  if($required > 0) {
+    return true;
+  }
+  return false;
+}
+
+/**
  * Execute a transition (change state of a node).
  *
  * @param object $node
@@ -300,9 +337,10 @@
  * Get the states one can move to for a given node.
  *
  * @param object $node
+ * @param bool $state_change_required
  * @return array
  */
-function workflow_field_choices($node) {
+function workflow_field_choices($node, $state_change_required = '') {
   global $user;
   $wid = workflow_get_workflow_for_type($node->type);
   if (!$wid) { // no workflow for this type
@@ -319,7 +357,7 @@
   }
   $transitions = workflow_allowable_transitions($current_sid, 'to', $roles);
 
-  if ($current_sid != _workflow_creation_state($wid)) { // include current state if not (creation)
+  if ($current_sid != _workflow_creation_state($wid) && !$state_change_required) { // include current state if not (creation)
     $transitions = array($current_sid => $states[$current_sid]) + $transitions;
   }
   return $transitions;
@@ -505,10 +543,12 @@
     '#maxlength' => '254',
   );
   $form['transitions'] = workflow_transition_grid_form($wid);
+  $form['require_state_change'] = workflow_role_requires_state_change_form($wid);
   $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
   $form['wid'] = array('#type' => 'value', '#value' => $wid);
   $form['#theme'] = 'workflow_edit';
   $form['transitions']['#tree'] = true;
+  $form['require_state_change']['#tree'] = true;
 
   $output = drupal_get_form('workflow_edit', $form);
   $output .= workflow_permissions($wid);
@@ -554,6 +594,40 @@
       $rows[] = $row;
     }
     $output .= theme('table', $header, $rows);
+    
+    /* Form changes to enable require state change for role */   
+    $header = array();   
+    $header[] = array('data' => '&nbsp;');
+    
+    $rows = array();
+    foreach ($states as $state_id => $name) {
+      if ($name == '(creation)') { // don't allow require state change FROM (creation)
+        continue;
+      }
+      else {
+        $header[] = array('data' => t($name));
+      }
+    }  
+    
+    $row = array(array('data' => '&nbsp;'));
+    foreach ($states as $st_id => $st_name) {
+      if ($st_name == '(creation)') {
+        continue; // don't allow require transition FROM (creation)
+      }
+      else {
+        $cell = '';
+        foreach ($roles as $rid => $role_name) {
+          $cell .= form_render($form['require_state_change'][$st_id][$rid]);
+        }
+        $row[] = array('data' => $cell);
+      }
+    }
+    $rows[] = $row;
+
+    $output .= '<br /><br />';
+    $output .= '<h3>Require State Change for Role</h3>';
+    $output .= theme('table', $header, $rows);
+    $output .= '<br /><br />';
   } else {
     $output = 'There are no states defined for this workflow.';
   }
@@ -593,6 +667,7 @@
 function workflow_edit_submit($form_id, $form_values) {
   workflow_update_name($form_values['wid'], $form_values['wf_name']);
   workflow_update_transitions($form_values['transitions']);
+  workflow_update_required_state_changes($form_values['require_state_change']);
   drupal_set_message(t('Workflow updated.'));
   drupal_goto('admin/workflow');
 }
@@ -665,6 +740,31 @@
 }
 
 /**
+ * Update the required state changes for a role.
+ *
+ * @param array $require_state_change
+ *   Require_state_change, for example:
+ *     19 => array(
+ *       5 =>  1
+ *     )
+ *   means a node with the state 19 requires a state change for a user 
+ *   with role 5.
+ */
+function workflow_update_required_state_changes($require_state_change = array()) {
+  foreach($require_state_change as $state_id => $role_data) {
+    foreach($role_data as $role => $required) {
+      if($required == 1) {
+        //watchdog('workflow', t($state_id . ' requires a state change for role: ' . $role));
+        workflow_require_state_change_add_role($state_id, $role);
+      }
+      else {
+      	workflow_require_state_change_delete_role($state_id, $role);
+      }
+    }
+  }  
+}
+
+/**
  * Add a role to the list of those allowed for a given transition.
  * Add the transition if necessary.
  * @param int $from
@@ -706,6 +806,31 @@
 }
 
 /**
+ * 
+ * @param int $state_id
+ * @param mixed $role
+ *   Int (role ID) or string ('author').
+ */
+function workflow_require_state_change_add_role($state_id, $role) {
+  if(!workflow_check_state_change_required($state_id, $role)) {
+    db_query("INSERT INTO {workflow_role_requires_state_change} (sid, role) VALUES (%d, '%s')", $state_id, $role);
+  }
+}
+
+/**
+ * 
+ * @param int $state_id
+ * @param mixed $role
+ *   Int (role ID) or string ('author').
+ */
+function workflow_require_state_change_delete_role($state_id, $role) {
+  if(workflow_check_state_change_required($state_id, $role)) {
+    db_query("DELETE FROM {workflow_role_requires_state_change} WHERE (sid = %d && role = '%s')", $state_id, $role);
+  }
+}
+
+
+/**
  * Build the grid of transitions for defining a workflow.
  *
  * @param int $wid
@@ -746,6 +871,43 @@
   return $form;
 }
 
+
+/**
+ * Build the grid of states/roles for requiring a state change for a given role.
+ *
+ * @param int $wid
+ */
+function workflow_role_requires_state_change_form($wid) {
+
+  $result = db_query('SELECT * FROM {role} ORDER BY name');
+  $roles = array('author' => 'author');
+  while ($data = db_fetch_object($result)) {
+    $roles[$data->rid] = $data->name;
+  }
+
+  $form = array();
+  $states = workflow_get_states($wid);
+  if (!$states) {
+    $form = array('#type' => 'markup', '#value' => t('There are no states defined for this workflow.'));
+    return $form;
+  }  
+  foreach ($states as $st_id => $st_name) {
+    if ($st_name == t('(creation)')) {
+      continue; // don't allow transition TO (creation)
+    }
+    else {
+      // need to generate checkboxes for transition from $state to $nested_state
+      foreach ($roles as $r_id => $role_name) {
+        $form[$st_id][$r_id] = array(
+          '#type' => 'checkbox',
+          '#title' => $role_name,
+          '#default_value' => $r_id ? workflow_check_state_change_required($st_id, $r_id) : false);
+      }
+    }
+  }   
+  return $form;
+}
+
 /**
  * See if a transition is allowed for a given role.
  *
@@ -1144,6 +1306,7 @@
     // delete the state and any associated transitions and actions
     workflow_state_delete($data->sid);
     db_query("DELETE FROM {workflow_node} WHERE sid = %d", $data->sid);
+    db_query("DELETE FROM {workflow_role_requires_state_change} WHERE sid = %d", $data->sid);
   }
   workflow_types_delete($wid);
   db_query("DELETE FROM {workflows} WHERE wid = %d", $wid);
