--- fieldtool_execute.inc.20100719	2010-07-19 11:32:39.000000000 +1000
+++ fieldtool_execute.inc	2010-07-19 13:28:04.000000000 +1000
@@ -5,10 +5,10 @@
  * Field Tool Execute
  *
  * Include file for fieldtool_execute.module.
- * The sole purpose of this file is to work around the bug described at:
- * https://drupal.org/node/260934
+ * The sole purpose of this file is to work around the bugs described at:
+ * https://drupal.org/node/260934 and http://drupal.org/node/846890
  *
- * Copyright 2009 Matthew Davidson (http://drupal.org/user/52996).
+ * Copyright 2010 Matthew Davidson (http://drupal.org/user/52996).
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@ function fieldtool_execute_execute($form
 
   // Make sure $form_state is passed around by reference.
   $args[1] = &$form_state;
-  
+
   $form = call_user_func_array('drupal_retrieve_form', $args);
   $form['#post'] = $form_state['values'];
   drupal_prepare_form($form_id, $form, $form_state);
@@ -39,7 +39,7 @@ function fieldtool_execute_execute($form
 function fieldtool_execute_process_form($form_id, &$form, &$form_state) {
   $form_state['values'] = array();
 
-  $form = form_builder($form_id, $form, $form_state);
+  $form = fieldtool_execute_form_builder($form_id, $form, $form_state);
   // Only process the form if it is programmed or the form_id coming
   // from the POST data is set and matches the current form_id.
   if ((!empty($form['#programmed'])) || (!empty($form['#post']) && (isset($form['#post']['form_id']) && ($form['#post']['form_id'] == $form_id)))) {
@@ -109,3 +109,111 @@ function fieldtool_execute_validate_form
   _form_validate($form, $form_state, $form_id);
   $validated_forms[$form_id] = TRUE;
 }
+
+
+function fieldtool_execute_form_builder($form_id, $form, &$form_state) {
+  static $complete_form, $cache;
+
+  // Initialize as unprocessed.
+  $form['#processed'] = FALSE;
+
+  // Use element defaults.
+  if ((!empty($form['#type'])) && ($info = _element_info($form['#type']))) {
+    // Overlay $info onto $form, retaining preexisting keys in $form.
+    $form += $info;
+  }
+
+  if (isset($form['#type']) && $form['#type'] == 'form') {
+    $cache = NULL;
+    $complete_form = $form;
+    if (!empty($form['#programmed'])) {
+      $form_state['submitted'] = TRUE;
+    }
+  }
+
+  if (isset($form['#input']) && $form['#input']) {
+    _form_builder_handle_input_element($form_id, $form, $form_state, $complete_form);
+  }
+  $form['#defaults_loaded'] = TRUE;
+
+  // We start off assuming all form elements are in the correct order.
+  $form['#sorted'] = TRUE;
+
+  // Recurse through all child elements.
+  $count = 0;
+  foreach (element_children($form) as $key) {
+    $form_state['storage'] = $key;
+    $form[$key]['#post'] = $form['#post'];
+    $form[$key]['#programmed'] = $form['#programmed'];
+    // Don't squash an existing tree value.
+    if (!isset($form[$key]['#tree'])) {
+      $form[$key]['#tree'] = $form['#tree'];
+    }
+
+    // Deny access to child elements if parent is denied.
+    if (isset($form['#access']) && !$form['#access']) {
+      $form[$key]['#access'] = FALSE;
+    }
+
+    // Don't squash existing parents value.
+    if (!isset($form[$key]['#parents'])) {
+      // Check to see if a tree of child elements is present. If so,
+      // continue down the tree if required.
+      $form[$key]['#parents'] = $form[$key]['#tree'] && $form['#tree'] ? array_merge($form['#parents'], array($key)) : array($key);
+      $array_parents = isset($form['#array_parents']) ? $form['#array_parents'] : array();
+      $array_parents[] = $key;
+      $form[$key]['#array_parents'] = $array_parents;
+    }
+
+    // Assign a decimal placeholder weight to preserve original array order.
+    if (!isset($form[$key]['#weight'])) {
+      $form[$key]['#weight'] = $count/1000;
+    }
+    else {
+      // If one of the child elements has a weight then we will need to sort
+      // later.
+      unset($form['#sorted']);
+    }
+    $form[$key] = fieldtool_execute_form_builder($form_id, $form[$key], $form_state);
+    $count++;
+    
+    // Highly inelegant hack to solve http://drupal.org/node/846890
+    // If submitting a node form, stop looking for submit buttons when you've found the save button.
+    if (array_key_exists('nid', $form_state['values']) && ($form_state['values']['op'] == 'Save') && ($form_state['clicked_button']['#value'] == 'Save')) {
+      break;
+    }
+  }
+
+  // The #after_build flag allows any piece of a form to be altered
+  // after normal input parsing has been completed.
+  if (isset($form['#after_build']) && !isset($form['#after_build_done'])) {
+    foreach ($form['#after_build'] as $function) {
+      $form = $function($form, $form_state);
+      $form['#after_build_done'] = TRUE;
+    }
+  }
+
+  // Now that we've processed everything, we can go back to handle the funky
+  // Internet Explorer button-click scenario.
+  _form_builder_ie_cleanup($form, $form_state);
+
+  // We shoud keep the buttons array until the IE clean up function
+  // has recognized the submit button so the form has been marked
+  // as submitted. If we already know which button was submitted,
+  // we don't need the array.
+  if (!empty($form_state['submitted'])) {
+    unset($form_state['buttons']);
+  }
+
+  // If some callback set #cache, we need to flip a static flag so later it
+  // can be found.
+  if (!empty($form['#cache'])) {
+    $cache = $form['#cache'];
+  }
+  // We are on the top form, we can copy back #cache if it's set.
+  if (isset($form['#type']) && $form['#type'] == 'form' && isset($cache)) {
+    $form['#cache'] = TRUE;
+  }
+  return $form;
+}
+
