Index: project.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.inc,v
retrieving revision 1.147
diff -u -p -r1.147 project.inc
--- project.inc	25 Nov 2009 16:38:15 -0000	1.147
+++ project.inc	22 Apr 2010 04:57:35 -0000
@@ -79,15 +79,28 @@ function project_project_form($node, $fo
       '#required' => TRUE,
     );
     $select_size = max(5, 2*count($top_level));
-    foreach ($options as $tid => $values) {
-      $form['project_taxonomy']["tid_$tid"] = array(
-        '#title' => t('!type categories', array('!type' => $top_level[$tid])),
-        '#type' => 'select',
-        '#multiple' => TRUE,
-        '#options' => $values,
-        '#default_value' => $current_options,
-        '#attributes' => array('size' => min($select_size, count($values))),
-      );
+    foreach (array_keys($top_level) as $tid) {
+      if (isset($options[$tid])) {
+        $values = $options[$tid];
+        $form['project_taxonomy']["tid_$tid"] = array(
+          '#title' => t('@type categories', array('@type' => $top_level[$tid])),
+          '#type' => 'select',
+          '#multiple' => TRUE,
+          '#options' => $values,
+          '#default_value' => $current_options,
+          '#attributes' => array('size' => min($select_size, count($values))),
+        );
+      }
+      else {
+        // provide a div for all top-level terms so that outside elements
+        // (vocabularies) can be shifted into the project taxonomy fieldset
+        // in the same paradigm as the modules sub-terms
+        $form['project_taxonomy']["tid_$tid"] = array(
+          '#type' => 'item',
+          '#value' => '',
+          '#id' => 'edit-tid-' . $tid,
+        );
+      }
     }
   }
 
@@ -255,25 +268,6 @@ function project_project_validate(&$node
       form_set_error("project][$uri", t('The %field field is not a valid URL.', array('%field' => $name)));
     }
   }
-
-  // Validate the project-specific sub-categories, if any...
-  if (project_use_taxonomy() && isset($node->project_type)) {
-    $tree = taxonomy_get_tree(_project_get_vid());
-    $top_level = array();
-    foreach ($tree as $i => $term) {
-      if ($term->parents[0] == 0) {
-        $top_level[$term->tid] = $term->name;
-      }
-    }
-    foreach ($top_level as $tid => $name) {
-      if ($node->project_type != $tid) {
-        $tid_field = 'tid_' . $tid;
-        if (!empty($node->$tid_field)) {
-          form_set_error($tid, t('Project type %project_type was selected, you can not use values from %invalid_type categories', array('%project_type' => $top_level[$node->project_type], '%invalid_type' => $top_level[$tid])));
-        }
-      }
-    }
-  }
 }
 
 function project_project_set_breadcrumb($node = NULL, $extra = NULL) {
@@ -381,6 +375,16 @@ function project_project_view($node, $te
 function project_project_nodeapi(&$node, $op, $arg) {
   $language = isset($node->language) ? $node->language : '';
   switch ($op) {
+    case 'presave':
+      // Remove terms from vocabularies that have associations for other project_types.
+      foreach ($node->taxonomy as $vid => $terms) {
+        $associated = variable_get('project_type_associated_tid_' . $vid, FALSE);
+        if ($associated && $associated != $node->project_type) {
+          unset($node->taxonomy[$vid]);
+        }
+      }
+      break;
+
     case 'insert':
       _project_save_taxonomy($node);
       if (module_exists('path') && variable_get('project_enable_alias', TRUE)) {
Index: project.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.install,v
retrieving revision 1.27
diff -u -p -r1.27 project.install
--- project.install	10 Aug 2009 22:50:39 -0000	1.27
+++ project.install	22 Apr 2010 04:57:35 -0000
@@ -24,6 +24,8 @@ function project_uninstall() {
   foreach ($variables as $variable) {
     variable_del($variable);
   }
+  db_query("DELETE FROM {variable} WHERE name LIKE 'project_type_associated_tid_%'");
+  cache_clear_all('variables', 'cache');
 }
 
 /**
Index: project.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.js,v
retrieving revision 1.3
diff -u -p -r1.3 project.js
--- project.js	12 Jan 2009 20:07:19 -0000	1.3
+++ project.js	22 Apr 2010 04:57:35 -0000
@@ -7,6 +7,7 @@ Drupal.behaviors.projectAuto = function 
       if (this.checked) {
         tid = this.value;
       }
+      Drupal.projectMoveElement(this.value);
     })
     .click(function () {
       Drupal.projectSetTaxonomy(this.value);
@@ -14,20 +15,25 @@ Drupal.behaviors.projectAuto = function 
   Drupal.projectSetTaxonomy(tid);
 }
 
+Drupal.projectMoveElement = function(tid) {
+  // move all elements with a class linked to this tid into the
+  // project taxonomy fieldset (similar to module sub-terms)
+  $('.related-tid-' + tid).each(function() {
+    $('#edit-tid-' + tid + '-wrapper').append($(this).parent().remove());
+  }); 
+}
+
 Drupal.projectSetTaxonomy = function (tid) {
   $('div.project-taxonomy-element select').each(function () {
-    // If this is the selector for the currently selected
-    // term, show it (in case it was previously hidden).
-    if (this.id == 'edit-tid-' + tid) {
+    // If this is the selector for the currently selected term or a
+    // related element, show it (in case it was previously hidden).
+    if (this.id == 'edit-tid-' + tid || $(this).hasClass('related-tid-' + tid)) {
       // Hide not the select but its containing div (which also contains
       // the label).
       $(this).parents('div.form-item').show();
     }
-    // Otherwise, empty it and hide it.
+    // Otherwise, hide it.
     else {
-      // In case terms were previously selected, unselect them.
-      // They are no longer valid.
-      this.selectedIndex = -1;
       $(this).parents('div.form-item').hide();
     }
   });
Index: project.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.module,v
retrieving revision 1.356
diff -u -p -r1.356 project.module
--- project.module	30 Jan 2010 02:43:23 -0000	1.356
+++ project.module	22 Apr 2010 04:57:35 -0000
@@ -310,9 +310,6 @@ function project_find_alias($query, $tab
 
 /**
  * Callback for the main settings page.
- *
- * @TODO:  This function is probably one we can delete, since there are no settings
- * to be set anymore.
  */
 function project_settings_form() {
   $form = array();
@@ -333,6 +330,25 @@ function project_settings_form() {
     variable_set('project_enable_alias', FALSE);
   }
 
+  $vocabs = taxonomy_get_vocabularies('project_project');
+  $tree = taxonomy_get_tree(_project_get_vid(), 0, -1, 1);
+  $top_level = array(t('- None -'));
+  foreach ($tree as $term) {
+    $top_level[$term->tid] = $term->name;
+  }
+  foreach ($vocabs as $vid => $vocab) {
+    // Skip freetagging vocabularies.
+    if (!$vocab->tags) {
+      $form['project_type_associated_tid_' . $vid] = array(
+        '#title' => t('Associated Project type taxonomy term for @vocab', array('@vocab' => $vocab->name)),
+        '#type' => 'select',
+        '#options' => $top_level,
+        '#default_value' => variable_get('project_type_associated_tid_' . $vid, NULL),
+        '#description' => t('If this vocabulary is specific to a project type, set the term here to allow Project to automatically show and hide the form as necessary.'),
+      );
+    }
+  }
+
   return system_settings_form($form);
 }
 
@@ -406,8 +422,11 @@ function project_term_path($term) {
  * Implementation of hook_taxonomy().
  */
 function project_taxonomy($op, $type, $array = NULL) {
-  if ($op == 'delete' && $type == 'vocabulary' && $array['vid'] == _project_get_vid())  {
-    variable_del('project_vocabulary');
+  if ($op == 'delete' && $type == 'vocabulary') {
+    if ($array['vid'] == _project_get_vid())  {
+      variable_del('project_vocabulary');
+    }
+    variable_del('project_type_associated_tid_' . $array['vid']);
   }
 }
 
@@ -568,14 +587,25 @@ function project_check_admin_access($pro
 function project_form_alter(&$form, &$form_state, $form_id) {
   switch ($form_id) {
     case 'project_project_node_form':
-      $vid = _project_get_vid();
-      if (isset($form['taxonomy'][$vid])) {
-        unset($form['taxonomy'][$vid]);
-      }
-      // If there are no children elements, we should unset the entire
-      // thing so we don't end up with an empty fieldset.
-      if (!empty($form['taxonomy']) && (!element_children($form['taxonomy']))) {
-        unset($form['taxonomy']);
+      $project_vid = _project_get_vid();
+      if (isset($form['taxonomy'][$project_vid])) {
+        unset($form['taxonomy'][$project_vid]);
+      }
+      if (!empty($form['taxonomy'])) {
+        $unhandled_vocabs = 0;
+        foreach (element_children($form['taxonomy']) as $vid) {
+          $associated_tid = variable_get('project_type_associated_tid_' . $vid, FALSE);
+          if (is_numeric($vid) && $associated_tid) {
+            $form['taxonomy'][$vid]['#attributes']['class'] = 'related-tid-' . $associated_tid;
+          }
+          else {
+            $unhandled_vocabs++;
+          }
+        }
+        if ($unhandled_vocabs <= 1) {
+          // If there is at most one unhandled vocabulary, hide the fieldset.
+          unset($form['taxonomy']['#type']);
+        }
       }
   
       // In D6, FAPI changed in such a way that completely unsetting
@@ -588,7 +618,7 @@ function project_form_alter(&$form, &$fo
       if (isset($form['buttons']['preview'])) {
         $form['buttons']['preview']['#submit'][] = 'project_project_form_preview_submit';
       }
-  
+
       // If the form has an element for specifying a URL alias, we want
       // to alter it, since we're just going to automatically override
       // the specified value.
@@ -616,7 +646,10 @@ function project_form_alter(&$form, &$fo
       $project_type_vid = _project_get_vid();
       if (isset($project_type_vid) && !empty($form['vid']['#value']) && $form['vid']['#value'] == $project_type_vid) {
         $form['#validate'][] = 'project_project_type_vocabulary_validate';
-        
+      }
+      // Do the same for any vocabularies with a helpful link.
+      if (variable_get('project_type_associated_tid_' . $form['vid']['#value'], FALSE)) {
+        $form['#validate'][] = 'project_associated_vocabulary_validate';
       }
       break;
   }
@@ -1143,6 +1176,16 @@ function project_project_type_vocabulary
 }
 
 /**
+ * Present a validation error if the user tries to make a vocabulary
+ * being used for association with a project type a free tagging vocabulary.
+ */
+function project_associated_vocabulary_validate($form, &$form_state) {
+  if (!empty($form_state['values']['tags'])) {
+    form_set_error('tags', t('The %name vocabulary is currently being associated with a project type. This is incompatible with tags. Please visit the <a href="!url">settings page</a> and change this if you wish to use freetagging on this vocabulary.', array('%name' => $form_state['values']['name'], '!url' => url('admin/project/project-settings'))));
+  }
+}
+
+/**
  * Theme a project type item.
  */
 function theme_project_type($term) {
