Index: content.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/Attic/content.info,v
retrieving revision 1.6
diff -u -r1.6 content.info
--- content.info	4 Jul 2007 23:46:29 -0000	1.6
+++ content.info	13 Jan 2009 21:59:28 -0000
@@ -2,4 +2,10 @@
 name = Content
 description = Allows administrators to define new content types.
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: includes/content.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/includes/Attic/content.admin.inc,v
retrieving revision 1.181.2.62
diff -u -r1.181.2.62 content.admin.inc
--- includes/content.admin.inc	10 Jan 2009 00:19:08 -0000	1.181.2.62
+++ includes/content.admin.inc	13 Jan 2009 21:59:39 -0000
@@ -138,6 +138,7 @@
   if (module_exists('fieldgroup')) {
     $groups = fieldgroup_groups($type['type']);
     $group_types = fieldgroup_types();
+    $plain_tree = _fieldgroup_plain_tree($groups);
     $group_options = _fieldgroup_groups_label($type['type']);
     // Add the ability to group under the newly created row.
     $group_options['_add_new_group'] = '_add_new_group';
@@ -185,6 +186,8 @@
 
   // Groups.
   foreach ($groups as $name => $group) {
+    $current_group_options = $plain_tree;
+    unset($current_group_options[$name]);
     $weight = $group['weight'];
     $form[$name] = array(
       'label' => array('#value' => check_plain($group['label'])),
@@ -193,17 +196,24 @@
       'configure' => array('#value' => l(t('Configure'), 'admin/content/node-type/'. $type['url_str'] .'/groups/'. $group['group_name'])),
       'remove' => array('#value' => l(t('Remove'), 'admin/content/node-type/'. $type['url_str'] .'/groups/'. $group['group_name'] .'/remove')),
       'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
-      'parent' => array('#type' => 'hidden', '#default_value' => ''),
+      'parent' => array('#type' => 'select', '#options' => $current_group_options, '#default_value' => ''),
+      'prev_parent' => array('#type' => 'hidden', '#value' => ''),
       'hidden_name' => array('#type' => 'hidden', '#default_value' => $group['group_name']),
-      '#root' => TRUE,
+      //'#root' => TRUE,
       '#row_type' => 'group',
       'group' => array('#type' => 'value', '#value' => $group),
     );
     // Adjust child fields rows.
-    foreach ($group['fields'] as $field_name => $field) {
-      $form[$field_name]['parent']['#default_value'] = $name;
-      $form[$field_name]['prev_parent']['#value'] = $name;
+    if (isset($group['fields'])) {
+      foreach ($group['fields'] as $field_name => $field) {
+        $form[$field_name]['parent']['#default_value'] = $name;
+        $form[$field_name]['prev_parent']['#value'] = $name;
+      }
     }
+    // Adjust child group rows
+    $form[$name]['parent']['#default_value'] = $group['parent_group_name'];
+    $form[$name]['prev_parent']['#value'] = $group['parent_group_name'];
+    
     $form['#group_rows'][] = $name;
     $weights[] = $weight;
   }
@@ -300,6 +310,8 @@
 
   // Additional row : add new group.
   if (module_exists('fieldgroup')) {
+    $current_group_options = $group_options;
+    unset($current_group_options[_add_new_group]);
     $weight++;
     $name = '_add_new_group';
     $form[$name] = array(
@@ -323,9 +335,10 @@
         '#value' => 'standard',
       ),
       'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
-      'parent' => array('#type' => 'hidden', '#default_value' => ''),
+      'parent' => array('#type' => 'select', '#options' => $current_group_options, '#default_value' => ''),
+      'prev_parent' => array('#type' => 'hidden', '#value' => ''),
       'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
-      '#root' => TRUE,
+      //'#root' => TRUE,
       '#add_new' => TRUE,
       '#row_type' => 'add_new_group',
     );
@@ -632,6 +645,7 @@
     $form[$name] = array(
       'human_name' => array('#value' => check_plain($group['label'])),
       'weight' => array('#type' => 'value', '#value' => $weight),
+      'parent' => array('#type' => 'value', '#value' => ''),
     );
     if ($contexts_selector == 'basic') {
       $form[$name]['label'] = array(
@@ -656,6 +670,8 @@
     foreach ($group['fields'] as $field_name => $field) {
       $form[$field_name]['parent']['#value'] = $name;
     }
+    $form[$name]['parent']['#value'] = $group['parent_group_name'];
+    $form[$name]['group']['#value']['depth'] = $group['depth'];
   }
 
   $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
@@ -1597,12 +1613,28 @@
  */
 function _content_overview_order(&$form, $field_rows, $group_rows) {
   // Put weight and parenting values into a $dummy render structure
-  // and let drupal_render figure out the corresponding row order.
   $dummy = array();
   // Group rows: account for weight.
   if (module_exists('fieldgroup')) {
+    $max_depth = 0;
     foreach ($group_rows as $name) {
-      $dummy[$name] = array('#weight' => $form[$name]['weight']['#value'], '#value' => $name .' ');
+      $depth = $form[$name]['group']['#value']['depth'];
+      if ($depth > $max_depth) {
+        $max_depth = $depth;
+      }
+      $parent = $form[$name]['parent']['#value'];
+      $pre_weight = $form[$name]['weight']['#value'];
+      if (isset($parent) && $parent != '') {
+        if ($pre_weight == 0) {
+          $pre_weight = 0.5;
+        }
+        $weight = $dummy[$parent]['#weight'] + ($pre_weight * pow(10, (-3 * $depth)));
+      }
+      else {
+        $weight = $pre_weight * pow(10, (-3 * $depth));
+      }
+      $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
+      $form[$name]['#depth'] = $depth;
     }
   }
   // Field rows : account for weight and parenting.
@@ -1610,12 +1642,40 @@
     $dummy[$name] = array('#weight' => $form[$name]['weight']['#value'], '#value' => $name .' ');
     if (module_exists('fieldgroup')) {
       if ($parent = $form[$name]['parent']['#value']) {
-        $form[$name]['#depth'] = 1;
+        $pre_weight = $form[$name]['weight']['#value'];
+        $depth = $form[$parent]['group']['#value']['depth'] + 1;
+        if (isset($parent) && $parent != '') {
+          if ($pre_weight == 0) {
+            $pre_weight = 0.5;
+          }
+          $weight = $dummy[$parent]['#weight'] + ($pre_weight * pow(10, (-3 * $depth)));
+        }
+        else {
+          $weight = $pre_weight * pow(10, (-3 * $depth));
+        }
+        $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
+        $form[$name]['#depth'] = $depth;
         $dummy[$parent][$name] = $dummy[$name];
         unset($dummy[$name]);
       }
     }
   }
+  //we have to do this at the end so as to cascade these moves bottom-up rather than use a recursive function top-down
+  if (module_exists('fieldgroup')) {
+    while ($max_depth >= 0) {
+      foreach ($group_rows as $name) {
+        if ($form[$name]['group']['#value']['depth'] == $max_depth) {
+          $parent = $form[$name]['parent']['#value'];
+          if (isset($parent) && $parent != '') {
+            $dummy[$parent][$name] = $dummy[$name];
+            unset($dummy[$name]);
+          }
+        }
+      }
+      $max_depth--;
+    }
+  }
+  //drupal_set_message('<pre>Dummy: ' .print_r($dummy, TRUE). '</pre>');
   return $dummy ? explode(' ', trim(drupal_render($dummy))) : array();
 }
 
Index: includes/content.node_form.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/includes/Attic/content.node_form.inc,v
retrieving revision 1.7.2.15
diff -u -r1.7.2.15 content.node_form.inc
--- includes/content.node_form.inc	27 Dec 2008 22:22:56 -0000	1.7.2.15
+++ includes/content.node_form.inc	13 Jan 2009 21:59:39 -0000
@@ -324,8 +324,13 @@
   drupal_alter('form', $form_element, array(), 'content_add_more_js');
 
   // Add the new element at the right place in the (original, unbuilt) form.
-  if (module_exists('fieldgroup') && ($group_name = _fieldgroup_field_get_group($type['type'], $field_name))) {
-    $form[$group_name][$field_name] = $form_element[$field_name];
+  if (module_exists('fieldgroup') && ($parents = _fieldgroup_field_get_parents($type['type'], $field_name))) {
+    $parents = array_reverse($parents);
+    $reference =& $form;
+    foreach ($parents as $index => $group_name) {
+      $reference =& $reference[$group_name];
+    }
+    $reference[$field_name] = $form_element[$field_name];
   }
   else {
     $form[$field_name] = $form_element[$field_name];
@@ -347,7 +352,18 @@
   $form = form_builder($_POST['form_id'], $form, $form_state);
 
   // Render the new output.
-  $field_form = (!empty($group_name)) ? $form[$group_name][$field_name] : $form[$field_name];
+  if (module_exists('fieldgroup') && ($parents = _fieldgroup_field_get_parents($type['type'], $field_name))) {
+    $parents = array_reverse($parents);
+    $reference =& $form;
+    foreach ($parents as $index => $group_name) {
+      $reference =& $reference[$group_name];
+    }
+    $field_form = $reference[$field_name];
+  }
+  else {
+    $field_form = $form[$field_name];
+  }
+
   // We add a div around the new content to receive the ahah effect.
   $field_form[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : '');
   $field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') .'</div>';
Index: modules/content_copy/content_copy.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/content_copy/Attic/content_copy.info,v
retrieving revision 1.6
diff -u -r1.6 content_copy.info
--- modules/content_copy/content_copy.info	23 Apr 2008 18:01:48 -0000	1.6
+++ modules/content_copy/content_copy.info	13 Jan 2009 21:59:49 -0000
@@ -3,4 +3,10 @@
 description = Enables ability to import/export field definitions.
 dependencies[] = content
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/content_copy/content_copy.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/content_copy/Attic/content_copy.module,v
retrieving revision 1.27.2.19
diff -u -r1.27.2.19 content_copy.module
--- modules/content_copy/content_copy.module	7 Nov 2008 14:37:50 -0000	1.27.2.19
+++ modules/content_copy/content_copy.module	13 Jan 2009 21:59:49 -0000
@@ -149,6 +149,7 @@
         $form[$name] = array(
           'human_name' => array('#value' => check_plain($group['label'])),
           'group_name' => array('#value' => $group['group_name']),
+          'parent_group_name' => array('#value' => $group['parent_group_name']),
           'weight' => array('#type' => 'value', '#value' => $weight),
           '#row_type' => 'group',
         );
Index: modules/content_permissions/content_permissions.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/content_permissions/Attic/content_permissions.info,v
retrieving revision 1.2
diff -u -r1.2 content_permissions.info
--- modules/content_permissions/content_permissions.info	23 Apr 2008 18:01:52 -0000	1.2
+++ modules/content_permissions/content_permissions.info	13 Jan 2009 21:59:54 -0000
@@ -3,4 +3,10 @@
 description = Set field-level permissions for CCK fields.
 package = CCK
 core = 6.x
-dependencies[] = content
\ No newline at end of file
+dependencies[] = content
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/fieldgroup/fieldgroup.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/fieldgroup/Attic/fieldgroup.info,v
retrieving revision 1.6.2.1
diff -u -r1.6.2.1 fieldgroup.info
--- modules/fieldgroup/fieldgroup.info	22 Sep 2008 18:25:21 -0000	1.6.2.1
+++ modules/fieldgroup/fieldgroup.info	13 Jan 2009 21:59:46 -0000
@@ -3,4 +3,10 @@
 description = Create display groups for CCK fields.
 dependencies[] = content
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/fieldgroup/fieldgroup.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/fieldgroup/Attic/fieldgroup.install,v
retrieving revision 1.34.2.19
diff -u -r1.34.2.19 fieldgroup.install
--- modules/fieldgroup/fieldgroup.install	26 Dec 2008 11:51:46 -0000	1.34.2.19
+++ modules/fieldgroup/fieldgroup.install	13 Jan 2009 21:59:46 -0000
@@ -52,6 +52,7 @@
       'group_type' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => 'standard'),
       'type_name'  => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
       'group_name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
+      'parent_group_name' => array('type' => 'varchar', 'length' => 32, 'not null' => FALSE, 'default' => ''),
       'label'      => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'settings'   => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE),
       'weight'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
@@ -313,4 +314,16 @@
   $ret = array();
   $ret[] = update_sql("DELETE FROM {content_group_fields} WHERE (field_name, type_name) NOT IN (SELECT field_name, type_name FROM {content_node_field_instance})");
   return $ret;
+}
+
+/**
+ * allow for nesting of fieldgroups
+ */
+function fieldgroup_update_6008() {
+  if ($abort = content_check_update('fieldgroup')) {
+    return $abort;
+  }
+  $ret = array();
+  db_add_field($ret, 'content_group', 'parent_group_name', array('type' => 'varchar', 'length' => 32, 'not null' => FALSE, 'default' => ''));
+  return $ret;
 }
\ No newline at end of file
Index: modules/fieldgroup/fieldgroup.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/fieldgroup/Attic/fieldgroup.module,v
retrieving revision 1.79.2.43
diff -u -r1.79.2.43 fieldgroup.module
--- modules/fieldgroup/fieldgroup.module	10 Jan 2009 22:47:07 -0000	1.79.2.43
+++ modules/fieldgroup/fieldgroup.module	13 Jan 2009 21:59:46 -0000
@@ -163,6 +163,7 @@
   $form['settings']['display']['label'] = array('#type' => 'value', '#value' => $group['settings']['display']['label']);
   $form['weight'] = array('#type' => 'hidden', '#default_value' => $group['weight']);
   $form['group_name'] = array('#type' => 'hidden', '#default_value' => $group_name);
+  $form['parent_group_name'] = array('#type' => 'hidden', '#default_value' => $group['parent_group_name']);
 
   $form['#content_type'] = $content_type;
 
@@ -207,7 +208,10 @@
   $form_values = $form_state['values'];
   $content_type = $form['#content_type'];
   $group_name = $form['#group_name'];
-  fieldgroup_delete($content_type['type'], $group_name);
+  $parent_group_name = db_fetch_array(db_query("SELECT parent_group_name FROM {". fieldgroup_tablename() ."} WHERE group_name = '%s' and type_name = '%s'", $group_name, $content_type['type']));
+  $result = db_query("UPDATE {". fieldgroup_tablename() ."} SET parent_group_name = '%s' WHERE parent_group_name = '%s'", $parent_group_name['parent_group_name'], $group_name);
+  $result = db_query("UPDATE {". fieldgroup_fields_tablename() ."} SET group_name = '%s' WHERE group_name = '%s'", $parent_group_name['parent_group_name'], $group_name);
+  fieldgroup_delete($content_type['type'], $group_name);  
   drupal_set_message(t('The group %group_name has been removed.', array('%group_name' => $group_name)));
   $form_state['redirect'] = 'admin/content/node-type/'. $content_type['url_str'] .'/fields';
 }
@@ -224,23 +228,13 @@
       $groups_sorted = $data['groups_sorted'];
     }
     else {
-      $result = db_query("SELECT * FROM {". fieldgroup_tablename() ."} ORDER BY weight, group_name");
+      $result = db_query("SELECT * FROM {". fieldgroup_tablename() ."} ORDER BY type_name, weight");
       $groups = array();
       $groups_sorted = array();
       while ($group = db_fetch_array($result)) {
-        $group['settings'] = unserialize($group['settings']);
-        $group['fields'] = array();
-        $groups[$group['type_name']][$group['group_name']] = $group;
+        $groups[$group['type_name']] = _fieldgroup_get_tree($group['type_name']);
         $groups_sorted[$group['type_name']][] = &$groups[$group['type_name']][$group['group_name']];
       }
-      //load fields
-      $result = db_query("SELECT nfi.*, ng.group_name FROM {". fieldgroup_tablename() ."} ng ".
- "INNER JOIN {". fieldgroup_fields_tablename() ."} ngf ON ngf.type_name = ng.type_name AND ngf.group_name = ng.group_name ".
- "INNER JOIN {". content_instance_tablename() ."} nfi ON nfi.field_name = ngf.field_name AND nfi.type_name = ngf.type_name ".
- "WHERE nfi.widget_active = 1 ORDER BY nfi.weight");
-      while ($field = db_fetch_array($result)) {
-        $groups[$field['type_name']][$field['group_name']]['fields'][$field['field_name']] = $field;
-      }
       cache_set('fieldgroup_data', array('groups' => $groups, 'groups_sorted' => $groups_sorted), content_cache_tablename());
     }
   }
@@ -253,6 +247,69 @@
   return $sorted ? $groups_sorted[$content_type] : $groups[$content_type];
 }
 
+/**
+ * create a tree of fieldgroups for nesting them
+ */
+function _fieldgroup_get_tree($type_name, $parent_group_name = '', $depth = -1, $max_depth = null) {
+  static $children, $parents, $groups;
+
+  $depth++;
+  // We cache trees, so it's not CPU-intensive to call get_tree() on a term
+  // and its children, too.
+  if (!isset($children[$type_name])) {
+    $children[$type_name] = array();
+
+    $s = "SELECT * FROM {". fieldgroup_tablename() ."} WHERE type_name='%s' ORDER BY weight";
+    $r = db_query($s, $type_name);
+    while ($group = db_fetch_array($r)) {
+      $children[$type_name][$group['parent_group_name']][] = $group['group_name'];
+      $parents[$type_name][$group['group_name']][] = $group['parent_group_name'];
+      $groups[$type_name][$group['group_name']] = $group;
+      $groups[$type_name][$group['group_name']]['fields'] = array();
+      $groups[$type_name][$group['group_name']]['settings'] = unserialize($group['settings']);
+    }
+    //load fields
+    $result = db_query("SELECT nfi.*, ng.group_name FROM {". fieldgroup_tablename() ."} ng ".
+        "INNER JOIN {". fieldgroup_fields_tablename() ."} ngf ON ngf.type_name = ng.type_name AND ngf.group_name = ng.group_name ".
+        "INNER JOIN {". content_instance_tablename() ."} nfi ON nfi.field_name = ngf.field_name AND nfi.type_name = ngf.type_name ".
+        "WHERE nfi.widget_active = 1 ORDER BY nfi.weight");
+    while ($field = db_fetch_array($result)) {
+      $groups[$field['type_name']][$field['group_name']]['fields'][$field['field_name']] = $field;
+    }
+  }
+
+  $max_depth = (is_null($max_depth)) ? count($children[$type_name]) : $max_depth;
+  if (isset($children[$type_name][$parent_group_name])) {
+    foreach ($children[$type_name][$parent_group_name] as $child_group_name) {
+      if ($max_depth > $depth) {
+        $group = $groups[$type_name][$child_group_name];
+        $group['depth'] = $depth;
+        $group['parents'] = $parents[$type_name][$child_group_name];
+        $tree[$group['group_name']] = $group;
+        if ($children[$type_name][$child_group_name]) {
+          $tree = array_merge($tree, _fieldgroup_get_tree($type_name, $child_group_name, $depth, $max_depth));
+        }
+      }
+    }
+  }
+  return $tree ? $tree : array();
+}
+
+/**
+ * go through a set of fieldgroups and construct a simple representation of their hierarchy
+ */
+function _fieldgroup_plain_tree($items) {
+  $rows = array();
+  $rows[''] = '<'. t('none') .'>';
+  foreach ($items as $item) {
+    $group_name = $item['group_name'];
+    $label = t($item['label']);
+    if ($group_name) {
+      $rows[$group_name] = str_repeat('--', $item['depth']) . ' ' . $label;
+    }
+  }
+  return $rows;
+}
 
 function _fieldgroup_groups_label($content_type) {
   $groups = fieldgroup_groups($content_type);
@@ -268,53 +325,148 @@
   return db_result(db_query("SELECT group_name FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $content_type, $field_name));
 }
 
+function _fieldgroup_field_get_parents($content_type, $field_name) {
+  $counter = 0;
+  $parents[$counter] = db_result(db_query("SELECT group_name FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $content_type, $field_name));
+  while ($result = db_result(db_query("SELECT parent_group_name FROM {". fieldgroup_tablename() ."} WHERE type_name = '%s' AND group_name = '%s'", $content_type, $parents[$counter]))) {
+    $counter++;
+    $parents[$counter] = $result;
+  }
+  return $parents;
+}
+
+function _fieldgroup_add_group_to_form(&$form, &$form_state, $form_id, $element, $group_name, $group, $groups) {
+  $element = array(
+    '#type' => 'fieldset',
+    '#title' => check_plain(t($group['label'])),
+    '#collapsed' => $group['settings']['form']['style'] == 'fieldset_collapsed',
+    '#collapsible' => in_array($group['settings']['form']['style'], array('fieldset_collapsed', 'fieldset_collapsible')),
+    '#weight' => $group['weight'],
+    '#depth' => $group['depth'],
+    '#group_parent' => $group['parent_group_name'],
+    '#description' => content_filter_xss(t($group['settings']['form']['description'])),
+    '#attributes' => array('class' => strtr($group['group_name'], '_', '-')),
+  );
+  $has_accessible_field = FALSE;
+  foreach ($group['fields'] as $field_name => $field) {
+    if (isset($form[$field_name])) {
+      $form[$field_name]['#weight'] = $field['weight'];
+      $element[$field_name] = $form[$field_name];
+      //Track whether this group has any accessible fields within it.
+      if (!isset($form[$field_name]['#access']) || $form[$field_name]['#access'] !== FALSE) {
+        $has_accessible_field = TRUE;
+      }
+      unset($form[$field_name]);
+    }
+  }
+  if (!empty($group['fields']) && !element_children($form[$group_name])) {
+    //hide the fieldgroup, because the fields are hidden too
+    unset($element[$group_name]);
+  }
+  
+  if (!$has_accessible_field) {
+    // Hide the fieldgroup, because the fields are inaccessible.
+    $form[$group_name]['#access'] = FALSE;
+  }
+
+  // Allow other modules to alter the form.
+  // Can't use module_invoke_all because we want
+  // to be able to use a reference to $form and $form_state.
+  foreach (module_implements('fieldgroup_form') as $module) {
+    $function = $module .'_fieldgroup_form';
+    $function($form, $form_state, $form_id, $group);
+  }
+
+  /*$parent_group_name = $group_name;
+  foreach ($groups as $group_name => $group) {
+    if ($group['parent_group_name'] == $parent_group_name) {
+      $element[$group_name] = _fieldgroup_add_group_to_form($form, $form_state, $form_id, $element[$group_name], $group_name, $group, $groups);
+    }
+  }*/
+
+  return $element;
+}
+
 /**
  * Implementation of hook_form_alter()
  */
 function fieldgroup_form_alter(&$form, $form_state, $form_id) {
   if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
-    foreach (fieldgroup_groups($form['type']['#value']) as $group_name => $group) {
-      $form[$group_name] = array(
-        '#type' => 'fieldset',
-        '#title' => check_plain(t($group['label'])),
-        '#collapsed' => $group['settings']['form']['style'] == 'fieldset_collapsed',
-        '#collapsible' => in_array($group['settings']['form']['style'], array('fieldset_collapsed', 'fieldset_collapsible')),
-        '#weight' => $group['weight'],
-        '#description' => content_filter_xss(t($group['settings']['form']['description'])),
-        '#attributes' => array('class' => strtr($group['group_name'], '_', '-')),
-      );
-
-      $has_accessible_field = FALSE;
-      foreach ($group['fields'] as $field_name => $field) {
-        if (isset($form[$field_name])) {
-          $form[$group_name][$field_name] = $form[$field_name];
-          // Track whether this group has any accessible fields within it.
-          if (!isset($form[$field_name]['#access']) || $form[$field_name]['#access'] !== FALSE) {
-            $has_accessible_field = TRUE;
-          }
-          unset($form[$field_name]);
-        }
-      }
-      if (!empty($group['fields']) && !element_children($form[$group_name])) {
-        //hide the fieldgroup, because the fields are hidden too
-        unset($form[$group_name]);
-      }
-
-      if (!$has_accessible_field) {
-        // Hide the fieldgroup, because the fields are inaccessible.
-        $form[$group_name]['#access'] = FALSE;
-      }
-
-      // Allow other modules to alter the form.
-      // Can't use module_invoke_all because we want
-      // to be able to use a reference to $form and $form_state.
-      foreach (module_implements('fieldgroup_form') as $module) {
-        $function = $module .'_fieldgroup_form';
-        $function($form, $form_state, $form_id, $group);
+    $group_rows = array();
+    $field_rows = array();
+    
+    //prepare data that will make this easier
+    $groups = fieldgroup_groups($form['type']['#value']);
+    foreach ($groups as $name => $more) {
+      $group_rows[] = $name;
+    }
+    $fields = $form['#field_info'];
+    foreach ($fields as $name => $more) {
+      $field_rows[] = $name;
+    }
+    
+    $field_check_off = $field_rows;
+    //now run through the groups and come up with new weights for display purposes
+    $max_depth = 0;
+    foreach ($group_rows as $name) {
+      $depth = $groups[$name]['depth'];
+      if ($depth > $max_depth) {
+        $max_depth = $depth;
+      }
+      $parent = $groups[$name]['parent_group_name'];
+      $pre_weight = $groups[$name]['weight'];
+      if (isset($parent) && $parent != '') {
+        if ($pre_weight == 0) {
+          $pre_weight = 0.5;
+        }
+        $weight = $groups[$parent]['weight'] + ($pre_weight * pow(10, (-3 * $depth)));
+      }
+      else {
+        $weight = $pre_weight * pow(10, (-3 * $depth));
+      }
+      $groups[$name]['weight'] = $weight;
+      //run through the fields and come up with new weights for display purposes
+      foreach ($groups[$name]['fields'] as $name2 => $elements) {
+        $pre_weight2 = $groups[$name]['fields'][$name2]['weight'];
+        $depth2 = $groups[$name]['depth'] + 1;
+        if ($pre_weight2 == 0) {
+          $pre_weight2 = 0.5;
+        }
+        $weight2 = $groups[$name]['weight'] + ($pre_weight2 * pow(10, (-3 * $depth2)));        
+        $groups[$name]['fields'][$name2]['weight'] = $weight2;
+        $groups[$name]['fields'][$name2]['depth'] = $depth2;
+        if (in_array($name2, $field_check_off)) {
+          $index = array_search($name2, $field_check_off);
+          unset($field_check_off[$index]);
+        }
       }
-
     }
-
+    //cover the top level fields that aren't in fieldgroups
+    foreach ($field_check_off as $name) {
+      $depth = 0;
+      $pre_weight = $form[$name]['#weight'];
+      $weight = $pre_weight * pow(10, (-3 * $depth));
+      $form[$name]['#weight'] = $weight;
+      $form[$name]['#depth'] = $depth;
+    }
+    
+    //now that we have the order of things as we want them, let's create the fieldsets for the fieldgroups
+    foreach ($groups as $group_name => $group) {
+      $form[$group_name] = _fieldgroup_add_group_to_form($form, $form_state, $form_id, $form[$group_name], $group_name, $group, $groups);
+    }
+    //reorder the groups from the inside-out in order to avoid a recursive function
+    while ($max_depth >= 0) {
+      foreach ($group_rows as $name) {
+        if ($form[$name]['#depth'] == $max_depth) {
+          $parent = $form[$name]['#group_parent'];
+          if (isset($parent) && $parent != '') {
+            $form[$parent][$name] = $form[$name];
+            unset($form[$name]);
+          }
+        }
+      }
+      $max_depth--;
+    }
   }
   // The group is only added here so it will appear in the export
   // when using Content Copy.
@@ -438,6 +590,10 @@
   // Parse incoming rows.
   $add_field_rows = array('_add_new_field', '_add_existing_field');
   $field_rows = array_merge($form['#fields'], $add_field_rows);
+  $add_group_rows = array($new_group_name);
+  $group_rows = array_merge($form['#groups'], $add_group_rows);
+  
+  
   foreach ($form_values as $key => $values) {
     // If 'field' row: update field parenting.
     if (in_array($key, $field_rows)) {
@@ -461,15 +617,18 @@
       // TODO: check the parent group does exist ?
       fieldgroup_update_fields(array('field_name' => $key, 'group' => $parent, 'type_name' => $type_name));
     }
-
-    // If 'group' row:  update groups weights
+  }
+  
+  foreach ($form_state['values'] as $key => $values) {
+    // If 'group' row:  update groups weights and parent
     // (possible newly created group has already been taken care of).
-    elseif (in_array($key, $form['#groups'])) {
-      db_query("UPDATE {". fieldgroup_tablename() ."} SET weight = %d WHERE type_name = '%s' AND group_name = '%s'",
-        $values['weight'], $type_name, $key);
+    if (in_array($key, $group_rows)) {
+      $parent = ($values['parent'] == '_add_new_group' && isset($new_group_name)) ? $new_group_name : $values['parent'];
+      $weight = $values['weight'];
+      db_query("UPDATE {". fieldgroup_tablename() ."} SET weight = %d, parent_group_name = '%s' WHERE type_name = '%s' AND group_name = '%s'", $weight, $parent, $type_name, $key);
     }
   }
-
+  
   cache_clear_all('fieldgroup_data', content_cache_tablename());
 }
 
@@ -525,8 +684,68 @@
         else {
           $context = $node->build_mode;
         }
-
-        foreach (fieldgroup_groups($node->type) as $group_name => $group) {
+        
+        //prepare data that will make this easier
+        $group_rows = array();
+        $field_rows = array();
+        $groups = fieldgroup_groups($node->type);
+        foreach ($groups as $name => $more) {
+          $group_rows[] = $name;
+        }
+        $fields = $node->content;
+        foreach ($fields as $name => $more) {
+          if (strstr($fields, 'field_')) {
+            $field_rows[] = $name;
+          }
+        }        
+        $field_check_off = $field_rows;
+        
+        //now run through the groups and come up with new weights for display purposes
+        $max_depth = 0;
+        foreach ($group_rows as $name) {
+          $depth = $groups[$name]['depth'];
+          if ($depth > $max_depth) {
+            $max_depth = $depth;
+          }
+          $parent = $groups[$name]['parent_group_name'];
+          $pre_weight = $groups[$name]['weight'];
+          if (isset($parent) && $parent != '') {
+            if ($pre_weight == 0) {
+              $pre_weight = 0.5;
+            }
+            $weight = $groups[$parent]['weight'] + ($pre_weight * pow(10, (-3 * $depth)));
+          }
+          else {
+            $weight = $pre_weight * pow(10, (-3 * $depth));
+          }
+          $groups[$name]['weight'] = $weight;
+          //run through the fields and come up with new weights for display purposes
+          foreach ($groups[$name]['fields'] as $name2 => $elements) {
+            $pre_weight2 = $groups[$name]['fields'][$name2]['weight'];
+            $depth2 = $groups[$name]['depth'] + 1;
+            if ($pre_weight2 == 0) {
+              $pre_weight2 = 0.5;
+            }
+            $weight2 = $groups[$name]['weight'] + ($pre_weight2 * pow(10, (-3 * $depth2)));        
+            $groups[$name]['fields'][$name2]['weight'] = $weight2;
+            $groups[$name]['fields'][$name2]['depth'] = $depth2;
+            if (in_array($name2, $field_check_off)) {
+              $index = array_search($name2, $field_check_off);
+              unset($field_check_off[$index]);
+            }
+          }
+        }
+        
+        //cover the top level fields that aren't in fieldgroups
+        foreach ($field_check_off as $name) {
+          $depth = 0;
+          $pre_weight = $node->content[$name]['#weight'];
+          $weight = $pre_weight * pow(10, (-3 * $depth));
+          $node->content[$name]['#weight'] = $weight;
+          $node->content[$name]['#depth'] = $depth;
+        }
+        
+        foreach ($groups as $group_name => $group) {
           // Do not include group labels when indexing content.
           if ($context == NODE_BUILD_SEARCH_INDEX) {
             $group['settings']['display']['label'] = 'hidden';
@@ -583,14 +802,29 @@
           $wrapper = array(
             'group' => $element,
             '#weight' => $group['weight'],
+            '#depth' => $group['depth'],
             '#post_render' => array('fieldgroup_wrapper_post_render'),
             '#group_name' => $group_name,
             '#type_name' => $node->type,
             '#context' => $context,
+            '#group_parent' => $group['parent_group_name'],
           );
 
           $node->content[$group_name] = $wrapper;
         }
+        //reorder the groups from the inside-out in order to avoid a recursive function
+        while ($max_depth >= 0) {
+          foreach ($group_rows as $name) {
+            if ($node->content[$name]['#depth'] == $max_depth) {
+              $parent = $node->content[$name]['#group_parent'];
+              if (isset($parent) && $parent != '') {
+                $node->content[$parent]['group'][$name] = $node->content[$name];
+                unset($node->content[$name]);
+              }
+            }
+          }
+          $max_depth--;
+        }
       }
       break;
   }
@@ -612,7 +846,7 @@
   return $content;
 }
 
-/*
+/**
  * Get the group name for a field.
  * If the field isn't in a group, FALSE will be returned.
  * @return The name of the group, or FALSE.
@@ -684,15 +918,15 @@
 
   if (!isset($groups[$group['group_name']])) {
     // Accept group name from programmed submissions if valid.
-    db_query("INSERT INTO {". fieldgroup_tablename() ."} (group_type, type_name, group_name, label, settings, weight)".
-      " VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $group['group_type'], $type_name, $group['group_name'], $group['label'], serialize($group['settings']), $group['weight']);
+    db_query("INSERT INTO {". fieldgroup_tablename() ."} (parent_group_name, group_type, type_name, group_name, label, settings, weight)".
+      " VALUES ('%s','%s', '%s', '%s', '%s', '%s', %d)", $group['parent_group_name'], $group['group_type'], $type_name, $group['group_name'], $group['label'], serialize($group['settings']), $group['weight']);
     cache_clear_all('fieldgroup_data', content_cache_tablename());
     return SAVED_NEW;
   }
   else {
-    db_query("UPDATE {". fieldgroup_tablename() ."} SET group_type = '%s', label = '%s', settings = '%s', weight = %d ".
-             "WHERE type_name = '%s' AND group_name = '%s'",
-             $group['group_type'], $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group['group_name']);
+    db_query("UPDATE {". fieldgroup_tablename() ."} SET parent_group_name =  '%s', group_type = '%s', label = '%s', settings = '%s', weight = %d ".
+        "WHERE type_name = '%s' AND group_name = '%s'",
+        $group['parent_group_name'], $group['group_type'], $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group['group_name']);
     cache_clear_all('fieldgroup_data', content_cache_tablename());
     return SAVED_UPDATED;
   }
@@ -762,6 +996,7 @@
 function fieldgroup_preprocess_fieldgroup_simple(&$vars) {
   $element = $vars['element'];
 
+  $vars['parent_group_name'] = $element['#parent_group_name'];
   $vars['group_name'] = $element['#group_name'];
   $vars['group_name_css'] = strtr($element['#group_name'], '_', '-');
   $vars['label'] = isset($element['#title']) ? $element['#title'] : '';;
Index: modules/nodereference/nodereference.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/nodereference/Attic/nodereference.info,v
retrieving revision 1.8
diff -u -r1.8 nodereference.info
--- modules/nodereference/nodereference.info	23 Apr 2008 18:02:07 -0000	1.8
+++ modules/nodereference/nodereference.info	13 Jan 2009 21:59:51 -0000
@@ -5,4 +5,10 @@
 dependencies[] = text
 dependencies[] = optionwidgets
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/number/number.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/number/Attic/number.info,v
retrieving revision 1.7
diff -u -r1.7 number.info
--- modules/number/number.info	23 Apr 2008 18:02:16 -0000	1.7
+++ modules/number/number.info	13 Jan 2009 21:59:56 -0000
@@ -3,4 +3,10 @@
 description = Defines numeric field types.
 dependencies[] = content
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/optionwidgets/optionwidgets.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/optionwidgets/Attic/optionwidgets.info,v
retrieving revision 1.7
diff -u -r1.7 optionwidgets.info
--- modules/optionwidgets/optionwidgets.info	23 Apr 2008 18:02:24 -0000	1.7
+++ modules/optionwidgets/optionwidgets.info	13 Jan 2009 21:59:44 -0000
@@ -3,4 +3,10 @@
 description = Defines selection, check box and radio button widgets for text and numeric fields.
 dependencies[] = content
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/text/text.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/text/Attic/text.info,v
retrieving revision 1.9
diff -u -r1.9 text.info
--- modules/text/text.info	23 Apr 2008 18:02:31 -0000	1.9
+++ modules/text/text.info	13 Jan 2009 21:59:53 -0000
@@ -3,4 +3,10 @@
 description = Defines simple text field types.
 dependencies[] = content
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: modules/userreference/userreference.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/userreference/Attic/userreference.info,v
retrieving revision 1.8
diff -u -r1.8 userreference.info
--- modules/userreference/userreference.info	23 Apr 2008 18:02:38 -0000	1.8
+++ modules/userreference/userreference.info	13 Jan 2009 21:59:59 -0000
@@ -5,4 +5,10 @@
 dependencies[] = text
 dependencies[] = optionwidgets
 package = CCK
-core = 6.x
\ No newline at end of file
+core = 6.x
+; Information added by drupal.org packaging script on 2009-01-11
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "cck"
+datestamp = "1231632161"
+
Index: theme/theme.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/theme/Attic/theme.inc,v
retrieving revision 1.1.2.12
diff -u -r1.1.2.12 theme.inc
--- theme/theme.inc	28 Oct 2008 22:12:09 -0000	1.1.2.12
+++ theme/theme.inc	13 Jan 2009 21:59:36 -0000
@@ -28,10 +28,11 @@
       $add_rows[] = $key;
     }
   }
+  $parent_list = array();
+  $parent_list['top'] = 'top';
   while ($order) {
     $key = reset($order);
     $element = &$form[$key];
-
     // Only display the 'Add' separator if the 'add' rows are still
     // at the end of the table.
     if (!isset($added_separator)) {
@@ -46,9 +47,17 @@
     }
 
     $row = new stdClass();
-
     // Add target classes for the tabledrag behavior.
-    $element['weight']['#attributes']['class'] = 'field-weight';
+    if ($element['#row_type'] == 'group') {
+      $parent_list[$element['group_name']['#value']] = strtr($element['group_name']['#value'], '_', '-');
+    }
+    if (empty($element['parent']['#value']) || !isset($element['parent']['#value'])) {
+      $element['weight']['#attributes']['class'] = 'field-weight field-weight-' . 'top';
+    }
+    else {
+      $element['weight']['#attributes']['class'] = 'field-weight field-weight-' . strtr($element['parent']['#value'], '_', '-');
+    }
+
     $element['parent']['#attributes']['class'] = 'group-parent';
     $element['hidden_name']['#attributes']['class'] = 'field-name';
     // Add target classes for the update selects behavior.
@@ -82,10 +91,15 @@
   $vars['submit'] = drupal_render($form);
 
   // Add tabledrag behavior.
-//  drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', FALSE, 1);
-  drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', TRUE, 1);
-//  drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight', NULL, NULL, FALSE);
-  drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight');
+  foreach ($parent_list as $name => $parent) {
+    //drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', FALSE, 10);
+    drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', TRUE, 10);
+    //drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight', 'field-weight-' . $parent, NULL, FALSE);
+    drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight', 'field-weight-' . $parent, NULL, TRUE);
+  }
+  
+  // Override methods in Drupal core tabledrag.js.
+  drupal_add_js(drupal_get_path('module', 'fieldgroup') .'/fieldgroup.tabledrag.js');
 
   // Add settings for the update selects behavior.
   $js_fields = array();

