ソースを参照

Merge branch '7.x-2.x' into entities

Stephen Ficklin 9 年 前
コミット
981c0ca6f4
100 ファイル変更3154 行追加1746 行削除
  1. 43 1
      tripal_analysis/api/tripal_analysis.api.inc
  2. 18 6
      tripal_analysis/includes/tripal_analysis.chado_node.inc
  3. 1 1
      tripal_analysis/tripal_analysis.info
  4. 1 4
      tripal_analysis/tripal_analysis.install
  5. 9 1
      tripal_analysis/tripal_analysis.views_default.inc
  6. 163 0
      tripal_bulk_loader/api/tripal_bulk_loader.api.templates.inc
  7. 47 17
      tripal_bulk_loader/includes/tripal_bulk_loader.admin.templates.inc
  8. 15 5
      tripal_bulk_loader/includes/tripal_bulk_loader.loader.inc
  9. 1 1
      tripal_bulk_loader/tripal_bulk_loader.info
  10. 32 0
      tripal_contact/api/tripal_contact.api.inc
  11. 5 7
      tripal_contact/includes/tripal_contact.chado_node.inc
  12. 1 1
      tripal_contact/tripal_contact.info
  13. 1 4
      tripal_contact/tripal_contact.install
  14. 7 0
      tripal_contact/tripal_contact.module
  15. 9 1
      tripal_contact/tripal_contact.views_default.inc
  16. 8 3
      tripal_core/api/tripal_core.chado_general.api.inc
  17. 386 169
      tripal_core/api/tripal_core.chado_nodes.api.inc
  18. 28 14
      tripal_core/api/tripal_core.chado_nodes.relationships.api.inc
  19. 5 10
      tripal_core/api/tripal_core.chado_nodes.title_and_path.inc
  20. 6 5
      tripal_core/api/tripal_core.chado_query.api.inc
  21. 53 0
      tripal_core/api/tripal_core.d3js.api.inc
  22. 25 8
      tripal_core/api/tripal_core.files.api.inc
  23. 6 1
      tripal_core/api/tripal_core.jobs.api.inc
  24. 2 1
      tripal_core/api/tripal_core.mviews.api.inc
  25. 19 13
      tripal_core/includes/tripal_core.extensions.inc
  26. 11 4
      tripal_core/includes/tripal_core.jobs.inc
  27. 1 0
      tripal_core/includes/tripal_core.mviews.inc
  28. 60 23
      tripal_core/tripal_core.drush.inc
  29. 2 2
      tripal_core/tripal_core.info
  30. 2 12
      tripal_core/tripal_core.install
  31. 19 1
      tripal_core/tripal_core.module
  32. 3 7
      tripal_cv/includes/tripal_cv.obo_loader.inc
  33. 1 1
      tripal_cv/tripal_cv.info
  34. 0 3
      tripal_cv/tripal_cv.install
  35. 354 348
      tripal_cv/tripal_cv.views_default.inc
  36. 1 1
      tripal_db/tripal_db.info
  37. 0 3
      tripal_db/tripal_db.install
  38. 8 2
      tripal_db/tripal_db.views_default.inc
  39. 3 4
      tripal_example/includes/tripal_example.chado_node.inc
  40. 1 1
      tripal_example/tripal_example.info
  41. 0 9
      tripal_example/tripal_example.install
  42. 11 5
      tripal_example/tripal_example.module
  43. 0 53
      tripal_feature/api/tripal_feature.schema.api.inc
  44. 20 1
      tripal_feature/includes/tripal_feature.admin.inc
  45. 2 4
      tripal_feature/includes/tripal_feature.chado_node.inc
  46. 67 109
      tripal_feature/includes/tripal_feature.delete.inc
  47. 71 72
      tripal_feature/includes/tripal_feature.fasta_loader.inc
  48. 267 138
      tripal_feature/includes/tripal_feature.gff_loader.inc
  49. 26 5
      tripal_feature/theme/css/tripal_feature.css
  50. 243 0
      tripal_feature/theme/js/tripalFeature.adminChart.js
  51. 28 0
      tripal_feature/theme/templates/tripal_feature_bar_chart_type_organism_summary.tpl.php
  52. 93 26
      tripal_feature/theme/templates/tripal_feature_relationships.tpl.php
  53. 106 121
      tripal_feature/theme/templates/tripal_organism_feature_browser.tpl.php
  54. 121 8
      tripal_feature/theme/tripal_feature.theme.inc
  55. 1 1
      tripal_feature/tripal_feature.info
  56. 140 35
      tripal_feature/tripal_feature.install
  57. 42 33
      tripal_feature/tripal_feature.module
  58. 10 14
      tripal_feature/tripal_feature.views_default.inc
  59. 8 6
      tripal_featuremap/includes/tripal_featuremap.chado_node.inc
  60. 1 1
      tripal_featuremap/tripal_featuremap.info
  61. 0 2
      tripal_featuremap/tripal_featuremap.install
  62. 9 6
      tripal_featuremap/tripal_featuremap.views_default.inc
  63. 1 1
      tripal_genetic/tripal_genetic.info
  64. 9 2
      tripal_genetic/tripal_genetic.views_default.inc
  65. 3 4
      tripal_library/includes/tripal_library.chado_node.inc
  66. 1 1
      tripal_library/tripal_library.info
  67. 0 3
      tripal_library/tripal_library.install
  68. 9 6
      tripal_library/tripal_library.views_default.inc
  69. 1 1
      tripal_natural_diversity/tripal_natural_diversity.info
  70. 0 3
      tripal_natural_diversity/tripal_natural_diversity.install
  71. 36 16
      tripal_natural_diversity/tripal_natural_diversity.views_default.inc
  72. 38 2
      tripal_organism/api/tripal_organism.api.inc
  73. 3 4
      tripal_organism/includes/tripal_organism.chado_node.inc
  74. 1 1
      tripal_organism/tripal_organism.info
  75. 0 7
      tripal_organism/tripal_organism.install
  76. 27 22
      tripal_organism/tripal_organism.module
  77. 4 2
      tripal_organism/tripal_organism.views_default.inc
  78. 1 1
      tripal_phenotype/tripal_phenotype.info
  79. 9 2
      tripal_phenotype/tripal_phenotype.views_default.inc
  80. 3 4
      tripal_project/includes/tripal_project.chado_node.inc
  81. 1 1
      tripal_project/tripal_project.info
  82. 0 3
      tripal_project/tripal_project.install
  83. 9 1
      tripal_project/tripal_project.views_default.inc
  84. 14 13
      tripal_pub/api/tripal_pub.api.inc
  85. 31 24
      tripal_pub/includes/tripal_pub.chado_node.inc
  86. 48 29
      tripal_pub/includes/tripal_pub.pub_citation.inc
  87. 153 0
      tripal_pub/theme/templates/pub_types/default.inc
  88. 27 187
      tripal_pub/theme/templates/tripal_pub_base.tpl.php
  89. 8 3
      tripal_pub/tripal_pub.drush.inc
  90. 1 1
      tripal_pub/tripal_pub.info
  91. 0 3
      tripal_pub/tripal_pub.install
  92. 5 7
      tripal_pub/tripal_pub.module
  93. 9 13
      tripal_pub/tripal_pub.views_default.inc
  94. 21 10
      tripal_stock/includes/tripal_stock.chado_node.inc
  95. 1 1
      tripal_stock/tripal_stock.info
  96. 0 3
      tripal_stock/tripal_stock.install
  97. 9 9
      tripal_stock/tripal_stock.views_default.inc
  98. 0 1
      tripal_views/api/tripal_views.api.inc
  99. 25 1
      tripal_views/includes/tripal_views_integration.inc
  100. 23 20
      tripal_views/includes/tripal_views_integration_UI.inc

+ 43 - 1
tripal_analysis/api/tripal_analysis.api.inc

@@ -108,7 +108,7 @@ function tripal_get_analysis($identifier, $options) {
     $property = $identifiers['property'];
     $property = $identifiers['property'];
     unset($identifiers['property']);
     unset($identifiers['property']);
     $analysis = chado_get_record_with_property(
     $analysis = chado_get_record_with_property(
-      array('table' => 'analysis', 'base_records' => $identifiers), 
+      array('table' => 'analysis', 'base_records' => $identifiers),
       array('type_name' => $property)
       array('type_name' => $property)
     );
     );
   }
   }
@@ -154,4 +154,46 @@ function tripal_get_analysis($identifier, $options) {
   else {
   else {
     return $analysis;
     return $analysis;
   }
   }
+}
+/**
+ * Returns a list of analyses that are currently synced with Drupal to use in select lists
+ *
+ * @param $syncd_only
+ *   Whether or not to return all chado analyses or just those sync'd with drupal. Defaults
+ *   to TRUE (only sync'd analyses)
+ * @return
+ *   An array of analyses sync'd with Drupal where each value is the analysis scientific
+ *   name and the keys are analysis_id's
+ *
+ * @ingroup tripal_analysis_api
+ */
+function tripal_get_analysis_select_options($syncd_only = TRUE) {
+  $analysis_list = array();
+  $analysis_list[] = 'Select an analysis';
+
+  if ($syncd_only) {
+    $sql = "
+      SELECT *
+      FROM public.chado_analysis CA
+        INNER JOIN {analysis} A ON A.analysis_id = CO.analysis_id
+      ORDER BY A.name
+    ";
+    $orgs = chado_query($sql);
+
+    // iterate through the analyses and build an array of those that are synced
+    foreach ($analyses as $analysis) {
+      $analysis_list[$analysis->analysis_id] = $analysis->name;
+    }
+  }
+  else {
+    // use this SQL statement for getting the analyses
+    $csql =  "SELECT * FROM {analysis} ORDER BY name";
+    $analyses = chado_query($csql);
+
+    // iterate through the analyses and build an array of those that are synced
+    foreach ($analyses as $analysis) {
+      $analysis_list[$analysis->analysis_id] = $analysis->name;
+    }
+  }
+  return $analysis_list;
 }
 }

+ 18 - 6
tripal_analysis/includes/tripal_analysis.chado_node.inc

@@ -8,6 +8,7 @@
 
 
 /**
 /**
  * Implements hook_node_info().
  * Implements hook_node_info().
+ *
  * Provide information to drupal about the node types that we're creating
  * Provide information to drupal about the node types that we're creating
  * in this module
  * in this module
  *
  *
@@ -38,6 +39,18 @@ function tripal_analysis_node_info() {
   return $nodes;
   return $nodes;
 }
 }
 
 
+/**
+ * Implements hook_chado_node_sync_form()
+ */
+function chado_analysis_chado_node_sync_form($form, &$form_state) {
+  if (array_key_exists('sync', $form) and array_key_exists('ids', $form['sync'])) {
+    $form['sync']['ids']['#prefix'] .= t('Please note that if analyses exist
+      that were created by other Tripal modules (e.g. Tripal Analysis Blast)
+      then you should sync those using that module\'s sync interface. Otherwise
+      they may not have all of the proper functionality.');
+  }
+  return $form;
+}
 /**
 /**
  * Implements hook_form().
  * Implements hook_form().
  * When editing or creating a new node of type 'chado_analysis' we need
  * When editing or creating a new node of type 'chado_analysis' we need
@@ -218,7 +231,7 @@ function chado_analysis_form($node, &$form_state) {
     ),
     ),
   );
   );
   $form['description']= array(
   $form['description']= array(
-    '#type' => 'textarea',
+    '#type' => 'text_format',
     '#rows' => 15,
     '#rows' => 15,
     '#title' => t('Materials & Methods (Description and/or Program Settings)'),
     '#title' => t('Materials & Methods (Description and/or Program Settings)'),
     '#required' => FALSE,
     '#required' => FALSE,
@@ -306,7 +319,6 @@ function tripal_analysis_validate($node, $form, &$form_state) {
 
 
   // remove surrounding white-space on submitted values
   // remove surrounding white-space on submitted values
   $node->analysisname = trim($node->analysisname);
   $node->analysisname = trim($node->analysisname);
-  $node->description = trim($node->description);
   $node->program = trim($node->program);
   $node->program = trim($node->program);
   $node->programversion = trim($node->programversion);
   $node->programversion = trim($node->programversion);
   $node->algorithm = trim($node->algorithm);
   $node->algorithm = trim($node->algorithm);
@@ -395,13 +407,13 @@ function tripal_analysis_validate($node, $form, &$form_state) {
 function chado_analysis_insert($node) {
 function chado_analysis_insert($node) {
 
 
   $node->analysisname = trim($node->analysisname);
   $node->analysisname = trim($node->analysisname);
-  $node->description = trim($node->description);
   $node->program = trim($node->program);
   $node->program = trim($node->program);
   $node->programversion = trim($node->programversion);
   $node->programversion = trim($node->programversion);
   $node->algorithm = trim($node->algorithm);
   $node->algorithm = trim($node->algorithm);
   $node->sourcename = trim($node->sourcename);
   $node->sourcename = trim($node->sourcename);
   $node->sourceversion = trim($node->sourceversion);
   $node->sourceversion = trim($node->sourceversion);
   $node->sourceuri = trim($node->sourceuri);
   $node->sourceuri = trim($node->sourceuri);
+  $node->description  = trim($node->description['value']);
 
 
   // if there is an analysis_id in the $node object then this must be a sync so
   // if there is an analysis_id in the $node object then this must be a sync so
   // we can skip adding the analysis as it is already there, although
   // we can skip adding the analysis as it is already there, although
@@ -415,7 +427,7 @@ function chado_analysis_insert($node) {
     $year  = $time['year'];
     $year  = $time['year'];
     $timestamp = $month . '/' . $day . '/' . $year;
     $timestamp = $month . '/' . $day . '/' . $year;
 
 
-    // insert and then get the newly inserted analysis record
+    // Insert and then get the newly inserted analysis record
     $values = array(
     $values = array(
       'name'           => $node->analysisname,
       'name'           => $node->analysisname,
       'description'    => $node->description,
       'description'    => $node->description,
@@ -501,13 +513,13 @@ function chado_analysis_delete($node) {
  */
  */
 function chado_analysis_update($node) {
 function chado_analysis_update($node) {
   $node->analysisname = trim($node->analysisname);
   $node->analysisname = trim($node->analysisname);
-  $node->description = trim($node->description);
   $node->program = trim($node->program);
   $node->program = trim($node->program);
   $node->programversion = trim($node->programversion);
   $node->programversion = trim($node->programversion);
   $node->algorithm = trim($node->algorithm);
   $node->algorithm = trim($node->algorithm);
   $node->sourcename = trim($node->sourcename);
   $node->sourcename = trim($node->sourcename);
   $node->sourceversion = trim($node->sourceversion);
   $node->sourceversion = trim($node->sourceversion);
   $node->sourceuri = trim($node->sourceuri);
   $node->sourceuri = trim($node->sourceuri);
+  $node->description  = trim($node->description['value']);
 
 
   // Create a timestamp so we can insert it into the chado database
   // Create a timestamp so we can insert it into the chado database
   $time = $node->timeexecuted;
   $time = $node->timeexecuted;
@@ -793,5 +805,5 @@ function chado_analysis_chado_node_default_title_format() {
  * Designates a default URL format for analysis nodes.
  * Designates a default URL format for analysis nodes.
  */
  */
 function chado_analysis_chado_node_default_url_format() {
 function chado_analysis_chado_node_default_url_format() {
-  return '/analysis/[analysis.program]/[analysis.programversion]/[analysis.sourcename]';
+  return '/analysis/[analysis.analysis_id]';
 }
 }

+ 1 - 1
tripal_analysis/tripal_analysis.info

@@ -3,7 +3,7 @@ description = Supports the companalyses tables of Chado by providing pages for v
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 configure = admin/tripal/chado/tripal_analysis/configuration
 configure = admin/tripal/chado/tripal_analysis/configuration
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core

+ 1 - 4
tripal_analysis/tripal_analysis.install

@@ -50,9 +50,6 @@ function tripal_analysis_requirements($phase) {
  */
  */
 function tripal_analysis_install() {
 function tripal_analysis_install() {
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_analysis');
-
   // we may need the analysisfeatureprop table if it doesn't already exist
   // we may need the analysisfeatureprop table if it doesn't already exist
   tripal_analysis_create_analysisfeatureprop();
   tripal_analysis_create_analysisfeatureprop();
 
 
@@ -125,7 +122,7 @@ function tripal_analysis_add_cvs() {
 function tripal_analysis_add_cvterms() {
 function tripal_analysis_add_cvterms() {
 
 
   tripal_insert_cv(
   tripal_insert_cv(
-    'tripal_analysis', 
+    'tripal_analysis',
     'Terms used for managing analyses in Tripal'
     'Terms used for managing analyses in Tripal'
   );
   );
 
 

+ 9 - 1
tripal_analysis/tripal_analysis.views_default.inc

@@ -93,7 +93,10 @@ function tripal_analysis_defaultvalue_admin_analysis() {
   $handler->display->display_options['access']['perm'] = 'access chado_analysis content';
   $handler->display->display_options['access']['perm'] = 'access chado_analysis content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of analyses that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of analyses or to find a specific analysis.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -214,6 +217,11 @@ function tripal_analysis_defaultvalue_admin_analysis() {
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
+  /* Sort criterion: Chado Analysis: Analysis Id */
+  $handler->display->display_options['sorts']['analysis_id']['id'] = 'analysis_id';
+  $handler->display->display_options['sorts']['analysis_id']['table'] = 'analysis';
+  $handler->display->display_options['sorts']['analysis_id']['field'] = 'analysis_id';
+  $handler->display->display_options['sorts']['analysis_id']['order'] = 'DESC';
   /* Filter criterion: Chado Analysis: Name */
   /* Filter criterion: Chado Analysis: Name */
   $handler->display->display_options['filters']['name']['id'] = 'name';
   $handler->display->display_options['filters']['name']['id'] = 'name';
   $handler->display->display_options['filters']['name']['table'] = 'analysis';
   $handler->display->display_options['filters']['name']['table'] = 'analysis';

+ 163 - 0
tripal_bulk_loader/api/tripal_bulk_loader.api.templates.inc

@@ -14,6 +14,169 @@
  * @}
  * @}
  */
  */
 
 
+/**
+ * Validates an $options array for insert or update of a bulk loader record.
+ *
+ * @param $val_type
+ *   The type of validation. Can be either 'insert' or 'update'.
+ * @param $options
+ *   An array of key/value pairs containing the following keys:
+ *     'template_name':   The name of the template.
+ *     'template_array':  The JSON array representing the template.
+ *   Optional:
+ *     'strict':          If set then only JSON formatted templates are allowed.
+ * @param $errors
+ *   An empty array where validation error messages will be set. The keys
+ *   of the array will be name of the field from the options array and the
+ *   value is the error message.
+ * @param $warnings
+ *   An empty array where validation warning messagges will be set. The
+ *   warnings should not stop an insert or an update but should be provided
+ *   to the user as information by a drupal_set_message() if appropriate. The
+ *   keys of the array will be name of the field from the options array and the
+ *   value is the error message.
+ *
+ * @return
+ *   If validation failes then FALSE is returned.  Any options that do not pass
+ *   validation checks will be added in the $errors array with the key being
+ *   the option and the value being the error message.  If validation
+ *   is successful then TRUE is returned.
+ *
+ */
+function tripal_validate_bulk_loader_template($val_type, &$options, &$errors, &$warnings = array()) {
+  $template_array = trim($options['template_array']);
+  $template_name = trim($options['template_name']);
+  $strict = array_key_exists('strict', $options)  ? $options['strict'] : FALSE;
+
+  // Make sure the template array is one of the supported types
+  // DEPRECATED: A stringified version of the array (causes security issues)
+  if (preg_match('/^array/', $template_array)) {
+    if ($strict) {
+      $errors['template_array'] = t('Invalid template array. Please provide
+        a JSON formatted array');
+      return FALSE;
+    }
+    else {
+      $warnings['template_array'] = t('Please note that import of
+        bulk loader templates as PHP arrays as a stringified array is deprecated
+        and will be removed in future versions of Tripal. Export and import
+        format will be JSON.');
+    }
+  }
+  // DEPRECATED: A serialized PHP array
+  elseif (preg_match('/^a:/', $template_array)) {
+    if ($strict) {
+      $errors['template_array'] = t('Invalid template array. Please provide
+        a JSON formatted array');
+      return FALSE;
+    }
+    else {
+      $warnings['template_array'] = t('Please note that import of
+        bulk loader templates as PHP serialized arrays is deprecated and will
+        be removed in future versions of Tripal. Export and import format will
+        be JSON.');
+    }
+  }
+  // JSON FORMAT
+  elseif (json_decode($template_array)) {
+    // This is correct!
+  }
+  else {
+    $errors['template_array'] = t('The template array must be in
+      JSON format (although PHP strigified arrays and PHP serialized
+      arrays are temporarily supported for backwards compatibility).');
+    return FALSE;
+  }
+
+  // Make sure the template name is unique
+  $name_exists = db_select('tripal_bulk_loader_template', 'tblt')
+    ->fields('tblt', array('template_id'))
+    ->condition('name', $template_name)
+    ->execute()
+    ->fetchField();
+  if ($name_exists) {
+    $errors['template_name'] = t('The template name already exists. Please
+      choose another name.');
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Inserts a bulk loader template record.
+ *
+ * This function validates the options passed prior to insertion of the record,
+ *
+ * @param $options
+ *   An array of key/value pairs containing the following keys:
+ *     'template_name':   The name of the template.
+ *     'template_array':  The JSON array representing the template.
+ *   Optional:
+ *     'strict':          If set then only JSON formatted templates are allowed.
+ * @param $errors
+ *   An empty array where validation error messages will be set. The keys
+ *   of the array will be name of the field from the options array and the
+ *   value is the error message.
+ * @param $warnings
+ *   An empty array where validation warning messagges will be set. The
+ *   warnings should not stop an insert or an update but should be provided
+ *   to the user as information by a drupal_set_message() if appropriate. The
+ *   keys of the array will be name of the field from the options array and the
+ *   value is the error message.
+ * @return
+ *   TRUE for success and FALSE for failure.
+ */
+function tripal_insert_bulk_loader_template($options, &$errors, &$warnings) {
+
+  $success = tripal_validate_bulk_loader_template('insert', $options, $errors, $warnings);
+  if (!$success) {
+    foreach ($errors as $field => $message) {
+      tripal_report_error('tripal_bulkldr', TRIPAL_ERROR, $message);
+    }
+    return FALSE;
+  }
+
+  // Insert the bulk loader template.
+  $template_array = trim($options['template_array']);
+  $template_name = trim($options['template_name']);
+
+  // Previous version of Tripal would export the template as a PHP array.
+  // This has security implications and is deprecated. This support should
+  // be reomved in future versions of Tripal, but to support transfers of
+  // templates between v1.1 and v2.x sites we support it.
+  if (preg_match('/^array/', $template_array)) {
+    $tarray = array();
+    eval("\$tarray = $template_array;");
+    $template_array = serialize($tarray);
+  }
+  // For a brief period, the bulk loader templates were exported as a PHP
+  // serialized array. We have moved to exporting in JSON as JSON is more
+  // user friendly. But we must support the serialized PHP array for
+  // backwards compatibility of v2.0-rc1 sites and v2.x sites.
+  elseif (preg_match('/^a:/', $template_array)) {
+    // do nothing it's in PHP serialized format
+  }
+  // The typical format is JSON
+  elseif (json_decode($template_array)) {
+    $template_array = serialize(json_decode($template_array, TRUE));
+  }
+  else {
+    $errors['template_array'] = t('Unrecognized array type.');
+    return FALSE;
+  }
+
+  $record = array(
+    'name' => $template_name,
+    'template_array' => $template_array,
+    'created' => time(),
+    'changed' => time()
+  );
+  if (!drupal_write_record('tripal_bulk_loader_template', $record)) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
 /**
 /**
  * Meant to be called from a form_validate function to ensure a newly added bulk loader record
  * Meant to be called from a form_validate function to ensure a newly added bulk loader record
  * name is unique and not empty.
  * name is unique and not empty.

+ 47 - 17
tripal_bulk_loader/includes/tripal_bulk_loader.admin.templates.inc

@@ -692,7 +692,7 @@ function tripal_bulk_loader_import_template_form($form, &$form_state) {
   $breadcrumb[] = l('Templates', 'admin/tripal/loaders/bulk/templates');
   $breadcrumb[] = l('Templates', 'admin/tripal/loaders/bulk/templates');
   drupal_set_breadcrumb($breadcrumb);
   drupal_set_breadcrumb($breadcrumb);
 
 
-  $form['new_template_name'] = array(
+  $form['template_name'] = array(
     '#type' => 'textfield',
     '#type' => 'textfield',
     '#title' => 'Template Name',
     '#title' => 'Template Name',
     '#weight' => 1,
     '#weight' => 1,
@@ -716,6 +716,35 @@ function tripal_bulk_loader_import_template_form($form, &$form_state) {
   return $form;
   return $form;
 }
 }
 
 
+/**
+ * Validates the import template form
+ */
+function tripal_bulk_loader_import_template_form_validate($form, &$form_state) {
+
+  $options = array(
+    'template_name' => trim($form_state['values']['template_name']),
+    'template_array' => trim($form_state['values']['template_array'])
+  );
+  $errors = array();
+  $warnings = array();
+
+  // Use the API function to Validate the submission.
+  tripal_validate_bulk_loader_template('insert', $options, $errors, $warnings);
+
+  // Now set form errors if any errors were detected.
+  if (count($errors) > 0) {
+    foreach($errors as $field => $message) {
+      form_set_error($field, $message);
+    }
+  }
+  // Add any warnings if any were detected
+  if (count($warnings) > 0) {
+    foreach($warnings as $field => $message) {
+      drupal_set_message($message, 'warning');
+    }
+  }
+}
+
 /**
 /**
  * Import Template Form Submit
  * Import Template Form Submit
  *
  *
@@ -727,21 +756,22 @@ function tripal_bulk_loader_import_template_form($form, &$form_state) {
  * @ingroup tripal_bulk_loader
  * @ingroup tripal_bulk_loader
  */
  */
 function tripal_bulk_loader_import_template_form_submit($form, &$form_state) {
 function tripal_bulk_loader_import_template_form_submit($form, &$form_state) {
-
-  $record = array(
-    'name' => $form_state['values']['new_template_name'],
-    'template_array' => $form_state['values']['template_array'],
-    'created' => time(),
-    'changed' => time()
+  $options = array(
+    'template_name' => trim($form_state['values']['template_name']),
+    'template_array' => trim($form_state['values']['template_array'])
   );
   );
-  $result = drupal_write_record('tripal_bulk_loader_template', $record);
-  if ($result) {
-    drupal_set_message(t('Successfully imported Tripal Bulk Loader Template.'));
-  }
-
-  $form_state['rebuild'] = FALSE;
-  $form_state['redirect'] = 'admin/tripal/loaders/bulk/templates';
+  $errors = array();
+  $warnings = array();
 
 
+  // Use the API function to insert a bulk loader.
+  if (tripal_insert_bulk_loader_template($options, $errors, $warnings)) {
+    drupal_set_message(t('Successfully imported Tripal bulk loader template.'));
+    $form_state['rebuild'] = FALSE;
+    $form_state['redirect'] = 'admin/tripal/loaders/bulk/templates';
+  }
+  else {
+    drupal_set_message(t('Unable to import Tripal bulk loader template.'), 'error');
+  }
 }
 }
 
 
 /**
 /**
@@ -777,7 +807,7 @@ function tripal_bulk_loader_export_template_form($form, &$form_state) {
   if ($template_id > 0) {
   if ($template_id > 0) {
     $result = db_select('tripal_bulk_loader_template','t')
     $result = db_select('tripal_bulk_loader_template','t')
       ->fields('t')
       ->fields('t')
-      ->condition('t.template_id',$template_id)
+      ->condition('t.template_id', $template_id)
       ->execute();
       ->execute();
     $template = $result->fetchObject();
     $template = $result->fetchObject();
     $form_state['storage']['template_array'] = $template->template_array;
     $form_state['storage']['template_array'] = $template->template_array;
@@ -792,8 +822,8 @@ function tripal_bulk_loader_export_template_form($form, &$form_state) {
   $form['template_array'] = array(
   $form['template_array'] = array(
     '#type' => 'textarea',
     '#type' => 'textarea',
     '#title' => 'Export',
     '#title' => 'Export',
-    '#default_value' => $form_state['storage']['template_array'],
-    '#description' => t('Use this serialized array for import.'),
+    '#default_value' => json_encode(unserialize($template->template_array)),
+    '#description' => t('Use this JSON array for import of this bulk loader template into another Tripal site.'),
     '#rows' => 30,
     '#rows' => 30,
     '#weight' => 5,
     '#weight' => 5,
 
 

+ 15 - 5
tripal_bulk_loader/includes/tripal_bulk_loader.loader.inc

@@ -150,7 +150,17 @@ function tripal_bulk_loader_load_data($nid, $job_id) {
   $node = node_load($nid);
   $node = node_load($nid);
   print "Template: " . $node->template->name . " (" . $node->template_id . ")\n";
   print "Template: " . $node->template->name . " (" . $node->template_id . ")\n";
 
 
-  $total_lines = trim(`wc --lines < $node->file`);
+  // Determine the total number of lines in the file.
+  $total_lines = 0;
+  $handle = fopen($node->file, "r");
+  while(!feof($handle)){
+    $line = fgets($handle);
+    $total_lines++;
+  }
+  fclose($handle);
+
+  // Correct for files with a single line and no enter character.
+  $total_lines = ($total_lines == 0) ? 1 : $total_lines;
   print "File: " . $node->file . " (" . $total_lines . " lines)\n";
   print "File: " . $node->file . " (" . $total_lines . " lines)\n";
 
 
   //print "\nClearing all prepared statements from previous runs of this loader...\n";
   //print "\nClearing all prepared statements from previous runs of this loader...\n";
@@ -577,7 +587,7 @@ function process_data_array_for_line($priority, &$data, &$default_data, $addt) {
   // skip optional fields
   // skip optional fields
   if ($skip_optional) {
   if ($skip_optional) {
     // SPF -- Commented out the following line.  This state is intentional due
     // SPF -- Commented out the following line.  This state is intentional due
-    // to the loader setup and and is not an error.  If informational it 
+    // to the loader setup and and is not an error.  If informational it
     // prints too much to the terminal.
     // prints too much to the terminal.
     // tripal_bulk_loader_throw_error('Skipping an optional record (%record)',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
     // tripal_bulk_loader_throw_error('Skipping an optional record (%record)',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
     return $no_errors;
     return $no_errors;
@@ -586,7 +596,7 @@ function process_data_array_for_line($priority, &$data, &$default_data, $addt) {
   // check if it is already inserted
   // check if it is already inserted
   if (array_key_exists('inserted', $table_data) and $table_data['inserted']) {
   if (array_key_exists('inserted', $table_data) and $table_data['inserted']) {
     // SPF -- Commented out the following line.  This state is intentional due
     // SPF -- Commented out the following line.  This state is intentional due
-    // to the loader setup and and is not an error.  If informational it 
+    // to the loader setup and and is not an error.  If informational it
     // prints too much to the terminal.
     // prints too much to the terminal.
     // tripal_bulk_loader_throw_error('Skipping %record since it is already inserted',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
     // tripal_bulk_loader_throw_error('Skipping %record since it is already inserted',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
     return $no_errors;
     return $no_errors;
@@ -597,7 +607,7 @@ function process_data_array_for_line($priority, &$data, &$default_data, $addt) {
   if (array_key_exists('selected', $table_data) and $table_data['selected']) {
   if (array_key_exists('selected', $table_data) and $table_data['selected']) {
     $data[$priority]['values_array'] = $default_data[$priority]['values_array'];
     $data[$priority]['values_array'] = $default_data[$priority]['values_array'];
     // SPF -- Commented out the following line.  This state is intentional due
     // SPF -- Commented out the following line.  This state is intentional due
-    // to the loader setup and and is not an error.  If informational it 
+    // to the loader setup and and is not an error.  If informational it
     // prints too much to the terminal.
     // prints too much to the terminal.
     // tripal_bulk_loader_throw_error('%record was already selected thus we are just returning the values previously selected.',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
     // tripal_bulk_loader_throw_error('%record was already selected thus we are just returning the values previously selected.',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
     return $no_errors;
     return $no_errors;
@@ -651,7 +661,7 @@ function process_data_array_for_line($priority, &$data, &$default_data, $addt) {
       // return if this is a select_if_duplicate
       // return if this is a select_if_duplicate
       if ($table_data['select_if_duplicate'] == 1) {
       if ($table_data['select_if_duplicate'] == 1) {
         // SPF -- Commented out the following line.  This state is intentional due
         // SPF -- Commented out the following line.  This state is intentional due
-        // to the loader setup and and is not an error.  If informational it 
+        // to the loader setup and and is not an error.  If informational it
         // prints too much to the terminal.
         // prints too much to the terminal.
         // tripal_bulk_loader_throw_error('Simply returning values for %record since it was already inserted',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
         // tripal_bulk_loader_throw_error('Simply returning values for %record since it was already inserted',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
         return $no_errors;
         return $no_errors;

+ 1 - 1
tripal_bulk_loader/tripal_bulk_loader.info

@@ -3,7 +3,7 @@ description = Supports the construction of templates for customizable uploading
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 32 - 0
tripal_contact/api/tripal_contact.api.inc

@@ -110,3 +110,35 @@ function tripal_insert_contact($values) {
   }
   }
   return $contact;
   return $contact;
 }
 }
+
+
+/**
+ * This function is intended to be used in autocomplete forms for contacts.
+ *
+ * @param $text
+ *   The string to search for
+ *
+ * @return
+ *   A json array of terms that begin with the provided string
+ *
+ * @ingroup tripal_organism_api
+ */
+function tripal_autocomplete_contact($text) {
+  $matches = array();
+
+  $sql = "SELECT * FROM {contact} WHERE lower(name) like lower(:name) ";
+  $args = array();
+  $args[':name'] = $text . '%';
+  $sql .= "ORDER BY name ";
+  $sql .= "LIMIT 25 OFFSET 0 ";
+  $results = chado_query($sql, $args);
+  $items = array();
+  foreach ($results as $contact) {
+    // Don't include the null contact
+    if ($contact->name == 'null') {
+      continue;
+    }
+    $items[$contact->name] = $contact->name;
+  }
+  drupal_json_output($items);
+}

+ 5 - 7
tripal_contact/includes/tripal_contact.chado_node.inc

@@ -171,7 +171,7 @@ function chado_contact_form(&$node, $form_state) {
   );
   );
 
 
   $form['description']= array(
   $form['description']= array(
-    '#type'          => 'textarea',
+    '#type'          => 'text_format',
     '#title'         => t('Contact Description'),
     '#title'         => t('Contact Description'),
     '#description'   => t('A brief description of the contact'),
     '#description'   => t('A brief description of the contact'),
     '#required'      => TRUE,
     '#required'      => TRUE,
@@ -262,8 +262,6 @@ function chado_contact_validate($node, $form, &$form_state) {
 
 
   // remove surrounding white-space on submitted values
   // remove surrounding white-space on submitted values
   $node->contactname = property_exists($node, 'contactname') ? trim($node->contactname) : '';
   $node->contactname = property_exists($node, 'contactname') ? trim($node->contactname) : '';
-  $node->description = property_exists($node, 'description') ? trim($node->description) : '';
-
 
 
   // Validating for an update
   // Validating for an update
   if (!is_null($node->nid)) {
   if (!is_null($node->nid)) {
@@ -374,8 +372,8 @@ function chado_contact_insert($node) {
   // we do need to proceed with insertion into the chado/drupal linking table.
   // we do need to proceed with insertion into the chado/drupal linking table.
   if (!property_exists($node, 'contact_id')) {
   if (!property_exists($node, 'contact_id')) {
     // remove surrounding white-space on submitted values
     // remove surrounding white-space on submitted values
-    $node->contactname    = trim($node->contactname);
-    $node->description    = trim($node->description);
+    $node->contactname = trim($node->contactname);
+    $node->description = trim($node->description['value']);
 
 
 
 
     // insert and then get the newly inserted contact record
     // insert and then get the newly inserted contact record
@@ -451,8 +449,8 @@ function chado_contact_insert($node) {
  */
  */
 function chado_contact_update($node) {
 function chado_contact_update($node) {
   // remove surrounding white-space on submitted values
   // remove surrounding white-space on submitted values
-  $node->contactname          = trim($node->contactname);
-  $node->description    = trim($node->description);
+  $node->contactname = trim($node->contactname);
+  $node->description = trim($node->description['value']);
 
 
   $contact_id = chado_get_id_from_nid('contact', $node->nid) ;
   $contact_id = chado_get_id_from_nid('contact', $node->nid) ;
 
 

+ 1 - 1
tripal_contact/tripal_contact.info

@@ -3,7 +3,7 @@ description = Supports the contact tables of Chado by providing pages for viewin
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 1 - 4
tripal_contact/tripal_contact.install

@@ -51,9 +51,6 @@ function tripal_contact_requirements($phase) {
  */
  */
 function tripal_contact_install() {
 function tripal_contact_install() {
 
 
-  // Create the module's data directory.
-  tripal_create_files_dir('tripal_contact');
-
   // Add the contactprop table to Chado.
   // Add the contactprop table to Chado.
   tripal_contact_add_custom_tables();
   tripal_contact_add_custom_tables();
 
 
@@ -406,7 +403,7 @@ function tripal_contact_update_7202() {
     db_delete('tripal_cv_obo')
     db_delete('tripal_cv_obo')
       ->condition('name', 'Tripal Contacts')
       ->condition('name', 'Tripal Contacts')
       ->execute();
       ->execute();
-    
+
     // Add in the updated path.
     // Add in the updated path.
     $obo_path = '{tripal_contact}/files/tcontact.obo';
     $obo_path = '{tripal_contact}/files/tcontact.obo';
     $obo_id = tripal_insert_obo('Tripal Contacts', $obo_path);
     $obo_id = tripal_insert_obo('Tripal Contacts', $obo_path);

+ 7 - 0
tripal_contact/tripal_contact.module

@@ -101,6 +101,13 @@ function tripal_contact_menu() {
     'file path' => drupal_get_path('module', 'tripal_core'),
     'file path' => drupal_get_path('module', 'tripal_core'),
     'weight' => 3
     'weight' => 3
   );
   );
+
+  $items['admin/tripal/chado/tripal_contact/contact/auto_name/%'] = array(
+    'page callback' => 'tripal_autocomplete_contact',
+    'page arguments' => array(6),
+    'access arguments' => array('administer tripal contact'),
+    'type' => MENU_CALLBACK,
+  );
   return $items;
   return $items;
 }
 }
 
 

+ 9 - 1
tripal_contact/tripal_contact.views_default.inc

@@ -96,7 +96,10 @@ function tripal_contact_defaultview_admin_contacts() {
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of contacts that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of contacts or to find a specific contact.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -205,6 +208,11 @@ function tripal_contact_defaultview_admin_contacts() {
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]  [delete_node]';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]  [delete_node]';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
+  /* Sort criterion: Chado Analysis: Contact Id */
+  $handler->display->display_options['sorts']['contact_id']['id'] = 'contact_id';
+  $handler->display->display_options['sorts']['contact_id']['table'] = 'contact';
+  $handler->display->display_options['sorts']['contact_id']['field'] = 'contact_id';
+  $handler->display->display_options['sorts']['contact_id']['order'] = 'DESC';
   /* Filter criterion: Chado Contact: Type Id */
   /* Filter criterion: Chado Contact: Type Id */
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['table'] = 'contact';
   $handler->display->display_options['filters']['type_id']['table'] = 'contact';

+ 8 - 3
tripal_core/api/tripal_core.chado_general.api.inc

@@ -283,8 +283,13 @@ function chado_insert_property($record, $property, $options = array()) {
 
 
   // First see if the property is already assigned to the record. I
   // First see if the property is already assigned to the record. I
   $props = chado_get_property($record, $property);
   $props = chado_get_property($record, $property);
-  if (!is_array($props) and $props) {
-    $props = array($props);
+  if (!is_array($props)) {
+    if ($props) {
+      $props = array($props);
+    }
+    else {
+      $props = array();
+    }
   }
   }
   if (count($props) > 0) {
   if (count($props) > 0) {
     // The property is already assigned, so, see if we should update it.
     // The property is already assigned, so, see if we should update it.
@@ -401,7 +406,7 @@ function chado_insert_property($record, $property, $options = array()) {
  *
  *
  * @ingroup tripal_chado_api
  * @ingroup tripal_chado_api
  */
  */
-function chado_update_property($record, $property, $options) {
+function chado_update_property($record, $property, $options = array()) {
 
 
   $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
   $base_table  = array_key_exists('table', $record) ? $record['table'] : '';
   $base_id     = array_key_exists('id', $record) ? $record['id'] : '';
   $base_id     = array_key_exists('id', $record) ? $record['id'] : '';

+ 386 - 169
tripal_core/api/tripal_core.chado_nodes.api.inc

@@ -133,36 +133,36 @@ function chado_node_get_base_table($content_type, $module = FALSE) {
 
 
 }
 }
 
 
-/** 
+/**
  * @section
  * @section
  * Common Functionality for Properties, Dbxrefs and relationships chado node API
  * Common Functionality for Properties, Dbxrefs and relationships chado node API
  */
  */
 
 
 /**
 /**
  * Validate the Triggering element from a node form.
  * Validate the Triggering element from a node form.
- * 
+ *
  * We are going to inspect the post to determine what PHP knows is the triggering
  * We are going to inspect the post to determine what PHP knows is the triggering
  * element and if it doesn't agree with Drupal then we are actually going to
  * element and if it doesn't agree with Drupal then we are actually going to
  * change it in Drupal.
  * change it in Drupal.
- * 
+ *
  * This fixes an obscure bug triggered when a property is added and then
  * This fixes an obscure bug triggered when a property is added and then
  * a relationship removed, Drupal thinks the first property remove button was
  * a relationship removed, Drupal thinks the first property remove button was
  * clicked and instead removes a property (not a relationship) and renders the new
  * clicked and instead removes a property (not a relationship) and renders the new
  * property table in the relationship table page space.
  * property table in the relationship table page space.
- * 
+ *
  * NOTE: Many Drupal issues state that this problem is solved if the #name
  * NOTE: Many Drupal issues state that this problem is solved if the #name
  * of the button is unique (which it is in our case) but we are still experiencing
  * of the button is unique (which it is in our case) but we are still experiencing
  * incorrectly determined triggering elements so we need to handle it ourselves.
  * incorrectly determined triggering elements so we need to handle it ourselves.
  */
  */
 function chado_validate_node_form_triggering_element($form, &$form_state) {
 function chado_validate_node_form_triggering_element($form, &$form_state) {
-  
+
   // We are going to inspect the post to determine what PHP knows is the triggering
   // We are going to inspect the post to determine what PHP knows is the triggering
   // element and if it doesn't agree with Drupal then we are actually going to
   // element and if it doesn't agree with Drupal then we are actually going to
   // change it in Drupal.
   // change it in Drupal.
   if ($_POST['_triggering_element_name'] != $form_state['triggering_element']['#name']) {
   if ($_POST['_triggering_element_name'] != $form_state['triggering_element']['#name']) {
     $form_state['triggering_element']['#name'] = $_POST['_triggering_element_name'];
     $form_state['triggering_element']['#name'] = $_POST['_triggering_element_name'];
   }
   }
-  
+
 }
 }
 
 
 /**
 /**
@@ -221,7 +221,7 @@ function chado_add_node_form_subtables_add_button_submit($form, &$form_state) {
         break;
         break;
     }
     }
   }
   }
-  
+
   // This is needed to ensure the form builder function is called for the node
   // This is needed to ensure the form builder function is called for the node
   // form in order for any of these changes to be seen.
   // form in order for any of these changes to be seen.
   $form_state['rebuild'] = TRUE;
   $form_state['rebuild'] = TRUE;
@@ -230,28 +230,28 @@ function chado_add_node_form_subtables_add_button_submit($form, &$form_state) {
 /**
 /**
  * Validate Removing Subtables entries from the node forms.
  * Validate Removing Subtables entries from the node forms.
  * Supported subtables: Properties, Relationships, Additional DBxrefs.
  * Supported subtables: Properties, Relationships, Additional DBxrefs.
- * 
+ *
  * Since Removing isn't associated with any user input the only thing we
  * Since Removing isn't associated with any user input the only thing we
  * need to validate is that Drupal has determined the triggering element correctly.
  * need to validate is that Drupal has determined the triggering element correctly.
  * That said, we will call each subtables associated validate function just incase
  * That said, we will call each subtables associated validate function just incase
  * there is some case-specific validation we do not know of or have not anticipated.
  * there is some case-specific validation we do not know of or have not anticipated.
- * 
+ *
  * @param array $form
  * @param array $form
  * @param array $form_state
  * @param array $form_state
  */
  */
 function chado_add_node_form_subtables_remove_button_validate($form, &$form_state) {
 function chado_add_node_form_subtables_remove_button_validate($form, &$form_state) {
- 
+
   // We need to validate the trigerring element since Drupal has known
   // We need to validate the trigerring element since Drupal has known
   // issues determining this correctly when there are multiple buttons
   // issues determining this correctly when there are multiple buttons
   // with the same label.
   // with the same label.
   chado_validate_node_form_triggering_element($form, $form_state);
   chado_validate_node_form_triggering_element($form, $form_state);
-  
+
   // Based on triggering element call the correct validation function
   // Based on triggering element call the correct validation function
   // ASUMPTION #1: each of the buttons must have property, dbxref or relationship
   // ASUMPTION #1: each of the buttons must have property, dbxref or relationship
   // as the first part of the #name to uniquely identify the subsection.
   // as the first part of the #name to uniquely identify the subsection.
   if (preg_match('/^([a-z]+).*/', $form_state['triggering_element']['#name'], $matches)) {
   if (preg_match('/^([a-z]+).*/', $form_state['triggering_element']['#name'], $matches)) {
     $subsection = $matches[1];
     $subsection = $matches[1];
-    
+
       switch($subsection) {
       switch($subsection) {
       case 'properties':
       case 'properties':
         chado_add_node_form_properties_remove_button_validate($form, $form_state);
         chado_add_node_form_properties_remove_button_validate($form, $form_state);
@@ -306,18 +306,18 @@ function chado_add_node_form_subtables_remove_button_submit($form, &$form_state)
  * @ingroup tripal_core
  * @ingroup tripal_core
  */
  */
 function chado_add_node_form_subtable_ajax_update($form, &$form_state) {
 function chado_add_node_form_subtable_ajax_update($form, &$form_state) {
-  
+
   // We need to validate the trigerring element since Drupal has known
   // We need to validate the trigerring element since Drupal has known
   // issues determining this correctly when there are multiple buttons
   // issues determining this correctly when there are multiple buttons
   // with the same label.
   // with the same label.
   chado_validate_node_form_triggering_element($form, $form_state);
   chado_validate_node_form_triggering_element($form, $form_state);
-  
+
   // Based on triggering element render the correct part of the form.
   // Based on triggering element render the correct part of the form.
   // ASUMPTION: each of the buttons must have property, dbxref or relationship
   // ASUMPTION: each of the buttons must have property, dbxref or relationship
   // as the first part of the #name to uniquely identify the subsection.
   // as the first part of the #name to uniquely identify the subsection.
   if (preg_match('/^([a-z]+).*/', $form_state['triggering_element']['#name'], $matches)) {
   if (preg_match('/^([a-z]+).*/', $form_state['triggering_element']['#name'], $matches)) {
     $subsection = $matches[1];
     $subsection = $matches[1];
-    
+
     switch($subsection) {
     switch($subsection) {
       case 'properties':
       case 'properties':
         return $form['properties']['property_table'];
         return $form['properties']['property_table'];
@@ -352,7 +352,7 @@ function chado_add_node_form_subtable_ajax_update($form, &$form_state) {
     $module_name = 'tripal_example';
     $module_name = 'tripal_example';
 
 
     // the base specified in hook_node_info
     // the base specified in hook_node_info
-    $linking_table = 'chado_example';
+    $node_type = 'chado_example';
 
 
     // This menu item will be a tab on the admin/tripal/chado/tripal_example page
     // This menu item will be a tab on the admin/tripal/chado/tripal_example page
     // that is not selected by default
     // that is not selected by default
@@ -360,7 +360,7 @@ function chado_add_node_form_subtable_ajax_update($form, &$form_state) {
       'title' => ' Sync',
       'title' => ' Sync',
       'description' => 'Sync examples from Chado with Drupal',
       'description' => 'Sync examples from Chado with Drupal',
       'page callback' => 'drupal_get_form',
       'page callback' => 'drupal_get_form',
-      'page arguments' => array('chado_node_sync_form', $module_name, $linking_table),
+      'page arguments' => array('chado_node_sync_form', $module_name, $node_type),
       'access arguments' => array('administer tripal examples'),
       'access arguments' => array('administer tripal examples'),
       'type' => MENU_LOCAL_TASK,
       'type' => MENU_LOCAL_TASK,
       'weight' => 0
       'weight' => 0
@@ -380,8 +380,12 @@ function chado_add_node_form_subtable_ajax_update($form, &$form_state) {
 
 
         // this is what differs from the regular Drupal-documented hook_node_info()
         // this is what differs from the regular Drupal-documented hook_node_info()
         'chado_node_api' => array(
         'chado_node_api' => array(
-          'base_table' => 'example',            // the name of the chado base table
-          'hook_prefix' => 'chado_example',     // usually the name of the node type
+          'base_table' => 'example',            // The name of the chado base table
+          'hook_prefix' => 'chado_example',     // Usually the name of the node type
+          'linking_table' => 'chado_example',   // Specifies the linking table used
+                                                // to map records to Drupal nodes.
+                                                // if 'linking_table' is not specified
+                                                // it defaults to the node_type name.
           'record_type_title' => array(
           'record_type_title' => array(
             'singular' => t('Example'),         // Singular human-readable title
             'singular' => t('Example'),         // Singular human-readable title
             'plural' => t('Examples')           // Plural human-readable title
             'plural' => t('Examples')           // Plural human-readable title
@@ -414,9 +418,18 @@ function chado_node_sync_form($form, &$form_state) {
 
 
   if (isset($form_state['build_info']['args'][0])) {
   if (isset($form_state['build_info']['args'][0])) {
     $module = $form_state['build_info']['args'][0];
     $module = $form_state['build_info']['args'][0];
-    $linking_table = $form_state['build_info']['args'][1];
+    $node_type = $form_state['build_info']['args'][1];
     $node_info = call_user_func($module . '_node_info');
     $node_info = call_user_func($module . '_node_info');
-    $args = $node_info[$linking_table]['chado_node_api'];
+
+    // If a linking table is set in the node_info array then use that,
+    // otherwise ues the node_type as the linking table.
+    if (array_key_exists('linking_table', $node_info[$node_type]['chado_node_api'])) {
+      $linking_table = $node_info[$node_type]['chado_node_api']['linking_table'];
+    }
+    else {
+      $linking_table = 'chado_' . $node_info[$node_type]['chado_node_api']['base_table'];
+    }
+    $args = $node_info[$node_type]['chado_node_api'];
     $form_state['chado_node_api'] = $args;
     $form_state['chado_node_api'] = $args;
   }
   }
 
 
@@ -425,6 +438,11 @@ function chado_node_sync_form($form, &$form_state) {
     '#value' => $linking_table
     '#value' => $linking_table
   );
   );
 
 
+  $form['node_type'] = array(
+    '#type' => 'hidden',
+    '#value' => $node_type
+  );
+
   // define the fieldsets
   // define the fieldsets
   $form['sync'] = array(
   $form['sync'] = array(
     '#type' => 'fieldset',
     '#type' => 'fieldset',
@@ -498,20 +516,67 @@ function chado_node_sync_form($form, &$form_state) {
     if (array_key_exists('primary key', $table_info) and count($table_info['primary key']) == 1) {
     if (array_key_exists('primary key', $table_info) and count($table_info['primary key']) == 1) {
       $pkey = $table_info['primary key'][0];
       $pkey = $table_info['primary key'][0];
       $columns  = $args['sync_filters']['checkboxes'];
       $columns  = $args['sync_filters']['checkboxes'];
-      $select_cols = implode("|| ' ' ||", $columns);
-
-      // get non-synced records
-      $sql = "
-        SELECT BT.$pkey as id, $select_cols as value
-        FROM {" . $base_table . "} BT
-          LEFT JOIN public.$linking_table LT ON LT.$pkey = BT.$pkey
-        WHERE LT.$pkey IS NULL
-        ORDER BY value ASC
-      ";
-      $results = chado_query($sql);
+      $select_cols = '';
+      foreach ($columns as $column) {
+        $select_cols .= $base_table . '.' . $column . "|| ' ' ||";
+      }
+      // Remove trailing || ' ' ||
+      $select_cols = substr($select_cols, 0, -9);
+      $base_table_id  = $base_table . '_id';
+
+      $select = array($base_table . '.' . $pkey, $select_cols . ' as value');
+      $joins = array();
+      $where_clauses = array();
+      $where_args = array();
+
+      // Allow module to update the query.
+      $hook_query_alter = $node_type . '_chado_node_sync_select_query';
+      if (function_exists($hook_query_alter)) {
+        $update = call_user_func($hook_query_alter, array(
+          'select' => $select,
+          'joins' => $joins,
+          'where_clauses' => $where_clauses,
+          'where_args' => $where_args,
+        ));
+        // Now add in any new changes
+        if ($update and is_array($update)) {
+          $select = $update['select'];
+          $joins = $update['joins'];
+          $where_clauses = $update['where_clauses'];
+          $where_args = $update['where_args'];
+        }
+      }
+
+      // Build Query, we do a left join on the chado_xxxx table in the Drupal schema
+      // so that if no criteria are specified we only get those items that have not
+      // yet been synced.
+      $query = "SELECT " . implode(', ', $select) . ' ' .
+               'FROM {' . $base_table . '} ' . $base_table . ' ' . implode(' ', $joins) . ' '.
+               "  LEFT JOIN public.$linking_table CT ON CT.$base_table_id = $base_table.$base_table_id " .
+               "WHERE CT.$base_table_id IS NULL";
+
+      // extend the where clause if needed
+      $where = '';
+      $sql_args = array();
+      foreach ($where_clauses as $category => $items) {
+        $where .= ' AND (';
+        foreach ($items as $item) {
+          $where .= $item . ' OR ';
+        }
+        $where = substr($where, 0, -4); // remove the trailing 'OR'
+        $where .= ') ';
+        $sql_args = array_merge($sql_args, $where_args[$category]);
+      }
+
+      if ($where) {
+        $query .= $where;
+      }
+      $query .= " ORDER BY $base_table." . implode(", $base_table.", $columns);
+      $results = chado_query($query, $sql_args);
+
       $values = array();
       $values = array();
       foreach ($results as $result) {
       foreach ($results as $result) {
-        $values[$result->id] = $result->value;
+        $values[$result->$pkey] = $result->value;
       }
       }
       if (count($values) > 0) {
       if (count($values) > 0) {
         $form['sync']['ids'] = array(
         $form['sync']['ids'] = array(
@@ -520,7 +585,7 @@ function chado_node_sync_form($form, &$form_state) {
           '#options'       => $values,
           '#options'       => $values,
           '#default_value' => (isset($form_state['values']['ids'])) ? $form_state['values']['ids'] : array(),
           '#default_value' => (isset($form_state['values']['ids'])) ? $form_state['values']['ids'] : array(),
           '#suffix'        => '</div><br>',
           '#suffix'        => '</div><br>',
-          '#prefix'       => t("The following  %title_plural have not been synced. Check those to be synced or leave all unchecked to sync them all.",
+          '#prefix'        => t("The following  %title_plural have not been synced. Check those to be synced or leave all unchecked to sync them all.",
               array(
               array(
                 '%title_singular' => strtolower($args['record_type_title']['singular']),
                 '%title_singular' => strtolower($args['record_type_title']['singular']),
                 '%title_plural'   => strtolower($args['record_type_title']['plural'])
                 '%title_plural'   => strtolower($args['record_type_title']['plural'])
@@ -561,7 +626,13 @@ function chado_node_sync_form($form, &$form_state) {
         "\"orphaned\".  This can occur if a node in Drupal is " .
         "\"orphaned\".  This can occur if a node in Drupal is " .
         "deleted but the corresponding chado records is not and/or vice " .
         "deleted but the corresponding chado records is not and/or vice " .
         "versa. Click the button below to resolve these discrepancies.</p>"),
         "versa. Click the button below to resolve these discrepancies.</p>"),
-    '#weight' => 1,
+    '#weight' => -10,
+  );
+  $form['cleanup']['cleanup_batch_size'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Batch Size'),
+      '#description' => t('The number of records to analyze together in a batch. If you are having memory issues you might want to decrease this number.'),
+      '#default_value' => variable_get('chado_node_api_cleanup_batch_size', 25000),
   );
   );
   $form['cleanup']['button'] = array(
   $form['cleanup']['button'] = array(
     '#type' => 'submit',
     '#type' => 'submit',
@@ -578,6 +649,26 @@ function chado_node_sync_form($form, &$form_state) {
   return $form;
   return $form;
 }
 }
 
 
+/**
+ * Generic Sync Form Validate
+ *
+ * @ingroup tripal_core
+ */
+function chado_node_sync_form_validate($form, &$form_state) {
+
+  if (empty($form_state['values']['cleanup_batch_size'])) {
+    $form_state['values']['cleanup_batch_size'] = 25000;
+    drupal_set_message('You entered a Batch Size of 0 for Cleaning-up orphaned nodes. Since this is not valid, we reset it to the default of 25,000.', 'warning');
+  }
+  elseif (!is_numeric($form_state['values']['cleanup_batch_size'])) {
+    form_set_error('cleanup_batch_size', 'The batch size must be a postitive whole number.');
+  }
+  else {
+    // Round the value just to make sure.
+    $form_state['values']['cleanup_batch_size'] = abs(round($form_state['values']['cleanup_batch_size']));
+  }
+}
+
 /**
 /**
  * Generic Sync Form Submit
  * Generic Sync Form Submit
  *
  *
@@ -593,6 +684,7 @@ function chado_node_sync_form_submit($form, $form_state) {
     $module = $form_state['chado_node_api']['hook_prefix'];
     $module = $form_state['chado_node_api']['hook_prefix'];
     $base_table = $form_state['chado_node_api']['base_table'];
     $base_table = $form_state['chado_node_api']['base_table'];
     $linking_table = $form_state['values']['linking_table'];
     $linking_table = $form_state['values']['linking_table'];
+    $node_type = $form_state['values']['node_type'];
 
 
     // Allow each module to hijack the submit if needed
     // Allow each module to hijack the submit if needed
     $hook_form_hijack_submit = $args['hook_prefix'] . '_chado_node_sync_form_submit';
     $hook_form_hijack_submit = $args['hook_prefix'] . '_chado_node_sync_form_submit';
@@ -639,7 +731,8 @@ function chado_node_sync_form_submit($form, $form_state) {
       'organism_id' => $organism_id,
       'organism_id' => $organism_id,
       'types' => $types,
       'types' => $types,
       'ids' => $ids,
       'ids' => $ids,
-      'inking_table' => $linking_table
+      'linking_table' => $linking_table,
+      'node_type' => $node_type
     );
     );
 
 
     $title = "Sync " . $args['record_type_title']['plural'];
     $title = "Sync " . $args['record_type_title']['plural'];
@@ -648,7 +741,10 @@ function chado_node_sync_form_submit($form, $form_state) {
   if (preg_match('/^Clean up orphaned/', $form_state['values']['op'])) {
   if (preg_match('/^Clean up orphaned/', $form_state['values']['op'])) {
     $module = $form_state['chado_node_api']['hook_prefix'];
     $module = $form_state['chado_node_api']['hook_prefix'];
     $base_table = $form_state['chado_node_api']['base_table'];
     $base_table = $form_state['chado_node_api']['base_table'];
-    $job_args = array($base_table);
+    $linking_table = $form_state['values']['linking_table'];
+    $node_type = $form_state['values']['node_type'];
+    $job_args = array($base_table, $form_state['values']['cleanup_batch_size'], $linking_table, $node_type);
+    variable_set('chado_node_api_cleanup_batch_size', $form_state['values']['cleanup_batch_size']);
     tripal_add_job($form_state['values']['op'], $module, 'chado_cleanup_orphaned_nodes', $job_args, $user->uid);
     tripal_add_job($form_state['values']['op'], $module, 'chado_cleanup_orphaned_nodes', $job_args, $user->uid);
   }
   }
 }
 }
@@ -676,14 +772,20 @@ function chado_node_sync_form_submit($form, $form_state) {
  *   are named as 'chado_' . $base_table.  But if for some reason the
  *   are named as 'chado_' . $base_table.  But if for some reason the
  *   linking table is not named in this way then it can be provided by this
  *   linking table is not named in this way then it can be provided by this
  *   argument.
  *   argument.
+ * @param $node_type
+ *   Optional: Tripal maintains "linking" tables in the Drupal schema
+ *   to link Drupal nodes with Chado records. By default, Tripal expects that
+ *   the node_type and linking table are named the same. However, if this
+ *   is not the case, you can provide the node type name here.
  * @param $job_id
  * @param $job_id
  *   Optional. Used by the Trpial Jobs system when running this function
  *   Optional. Used by the Trpial Jobs system when running this function
  *   as a job. It is not needed othewise.
  *   as a job. It is not needed othewise.
  *
  *
  * @ingroup tripal_chado_node_api
  * @ingroup tripal_chado_node_api
  */
  */
-function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id = FALSE,
-    $types = array(), $ids = array(), $linking_table = FALSE, $job_id = NULL) {
+function chado_node_sync_records($base_table, $max_sync = FALSE,
+    $organism_id = FALSE, $types = array(), $ids = array(),
+    $linking_table = FALSE, $node_type = FALSE, $job_id = NULL) {
 
 
   global $user;
   global $user;
   $base_table_id = $base_table . '_id';
   $base_table_id = $base_table . '_id';
@@ -691,6 +793,9 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
   if (!$linking_table) {
   if (!$linking_table) {
     $linking_table = 'chado_' . $base_table;
     $linking_table = 'chado_' . $base_table;
   }
   }
+  if (!$node_type) {
+    $node_type = 'chado_' . $base_table;
+  }
 
 
   print "\nSync'ing $base_table records.  ";
   print "\nSync'ing $base_table records.  ";
 
 
@@ -735,7 +840,7 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
   }
   }
 
 
   // Allow module to add to query
   // Allow module to add to query
-  $hook_query_alter = $linking_table . '_chado_node_sync_select_query';
+  $hook_query_alter = $node_type . '_chado_node_sync_select_query';
   if (function_exists($hook_query_alter)) {
   if (function_exists($hook_query_alter)) {
     $update = call_user_func($hook_query_alter, array(
     $update = call_user_func($hook_query_alter, array(
       'select' => $select,
       'select' => $select,
@@ -811,31 +916,25 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
   try {
   try {
     $percent = 0;
     $percent = 0;
     foreach ($results as $record) {
     foreach ($results as $record) {
-
-      //print "\nLoading $base_table " . ($i + 1) . " of $count ($base_table_id=" . $record->{$base_table_id} . ")...";
-
-      // update the job status every 1% features
+      // Update the job status every 1% features.
       if ($job_id and $i % $interval == 0) {
       if ($job_id and $i % $interval == 0) {
         $percent = sprintf("%.2f", (($i + 1) / $count) * 100);
         $percent = sprintf("%.2f", (($i + 1) / $count) * 100);
         print "Syncing $base_table " . ($i + 1) . " of $count (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\r";
         print "Syncing $base_table " . ($i + 1) . " of $count (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\r";
         tripal_set_job_progress($job_id, intval(($i/$count)*100));
         tripal_set_job_progress($job_id, intval(($i/$count)*100));
       }
       }
 
 
-      // Check if it is in the chado linking table (ie: check to see if it is already linked to a node)
+      // Check if the record is already in the chado linking table
+      // (ie: check to see if it is already linked to a node).
       $result = db_select($linking_table, 'lnk')
       $result = db_select($linking_table, 'lnk')
         ->fields('lnk',array('nid'))
         ->fields('lnk',array('nid'))
         ->condition($base_table_id, $record->{$base_table_id}, '=')
         ->condition($base_table_id, $record->{$base_table_id}, '=')
         ->execute()
         ->execute()
         ->fetchObject();
         ->fetchObject();
 
 
-      if (!empty($result)) {
-        //print " Previously Sync'd";
-      }
-      else {
-
-        // Create generic new node
+      if (empty($result)) {
+        // Create generic new node.
         $new_node = new stdClass();
         $new_node = new stdClass();
-        $new_node->type = $linking_table;
+        $new_node->type = $node_type;
         $new_node->uid = $user->uid;
         $new_node->uid = $user->uid;
         $new_node->{$base_table_id} = $record->{$base_table_id};
         $new_node->{$base_table_id} = $record->{$base_table_id};
         $new_node->$base_table = $record;
         $new_node->$base_table = $record;
@@ -843,7 +942,7 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
 
 
         // TODO: should we get rid of this hook and use hook_node_presave() instead?
         // TODO: should we get rid of this hook and use hook_node_presave() instead?
         // allow base module to set additional fields as needed
         // allow base module to set additional fields as needed
-        $hook_create_new_node = $linking_table . '_chado_node_sync_create_new_node';
+        $hook_create_new_node = $node_type . '_chado_node_sync_create_new_node';
         if (function_exists($hook_create_new_node)) {
         if (function_exists($hook_create_new_node)) {
           $new_node = call_user_func($hook_create_new_node, $new_node, $record);
           $new_node = call_user_func($hook_create_new_node, $new_node, $record);
         }
         }
@@ -855,11 +954,12 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
 
 
         if (!form_get_errors()) {
         if (!form_get_errors()) {
           $node = node_submit($new_node);
           $node = node_submit($new_node);
+          // If there are memory leaks on the node_save it is probably
+          // caused by the hook_node_insert() function.
           node_save($node);
           node_save($node);
-          //print " Node Created (nid=".$node->nid.")";
         }
         }
         else {
         else {
-          watchdog('trp-fsync', "Failed to insert $base_table: %title", array('%title' => $new_node->title), WATCHDOG_ERROR);
+          throw new Exception(t("Failed to insert $base_table: %title", array('%title' => $new_node->title)));
         }
         }
       }
       }
       $i++;
       $i++;
@@ -875,6 +975,81 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
   }
   }
 }
 }
 
 
+/**
+ * This function is a wrapper for the chado_cleanup_orphaned_nodes function.
+ * It breaks up the work of chado_cleanup_orphaned_nodes into smaller pieces
+ * that are more managable for servers that may  have low php memory settings.
+ *
+ * @param $table
+ *   The name of the table that corresonds to the node type we want to clean up.
+ * @param $nentries
+ *   Optional. The number of entries to parse at one time (ie: the batch size).
+ *   Set to zero if no limit is needed.
+ * @param $linking_table
+ *   Optional. The name of the linking table that maps Drupal nodes to Chado
+ *   records. This is only required if the linking table name is not of the
+ *   form: chado_[table] where [table] is the value provided to the $table
+ *   argument.
+ * @param $node_type
+ *   Optional. The name of the node type for the records.  This is only
+ *   required if the node type is not of the form: chado_[table] where
+ *   [table] is the value provided to the $table.
+ * @param $job_id
+ *   Optional. This should be the job id from the Tripal jobs system. Typically,
+ *   only the Tripal jobs system will use the argument.
+ *
+ * @ingroup tripal_chado_node_api
+ */
+function chado_cleanup_orphaned_nodes($table, $nentries = 25000, $linking_table = NULL, $node_type = NULL, $job_id = NULL) {
+  // The max number of records either as nodes or linked records.
+  $count = 0;
+  // Will hold the number of nodes of this type.
+  $ncount = 0;
+  // Will hold the number of linked records.
+  $clcount = 0;
+
+  if (!$node_type) {
+    $node_type = 'chado_' . $table;
+  }
+  if (!$linking_table) {
+    $linking_table = 'chado_' . $table;
+  }
+  // Find the number nodes of type chado_$table and find the number of entries
+  // in chado_$table; keep the larger of the two numbers.
+  $dsql = "SELECT COUNT(*) FROM {node} WHERE type = :node_type";
+  $ndat = db_query($dsql, array(':node_type' => $node_type));
+  $temp = $ndat->fetchObject();
+  $ncount = $temp->count;
+  $clsql= "SELECT COUNT(*) FROM {" . $linking_table . "}";
+  $cdat = db_query($clsql);
+  $clcount = $cdat->fetchObject();
+  if ($ncount < $clcount) {
+    $count = $clcount;
+  }
+  else {
+    $count = $ncount;
+  }
+
+  $transaction = db_transaction();
+  print "\nNOTE: This operation is performed using a database transaction. \n" .
+    "If it fails or is terminated prematurely then the entire set of \n" .
+    "changes is rolled back and will not be found in the database\n\n";
+  try {
+    $m = ceil($count / $nentries);
+    for ($i = 0; $i < $m; $i++) {
+      $offset = ($nentries * $i);
+      chado_cleanup_orphaned_nodes_part($table, $job_id, $nentries, $offset, $linking_table, $node_type);
+    }
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    print "\n"; // make sure we start errors on new line
+    watchdog_exception('trp-fsync', $e);
+    print "FAILED: Rolling back database changes...\n";
+  }
+  return '';
+}
+
 /**
 /**
  * This function will delete Drupal nodes for any sync'ed table (e.g.
  * This function will delete Drupal nodes for any sync'ed table (e.g.
  * feature, organism, analysis, stock, library) if the chado record has been
  * feature, organism, analysis, stock, library) if the chado record has been
@@ -888,103 +1063,133 @@ function chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id =
  *
  *
  * @ingroup tripal_chado_node_api
  * @ingroup tripal_chado_node_api
  */
  */
-function chado_cleanup_orphaned_nodes($table, $job_id = NULL) {
-  $count = 0;
+function chado_cleanup_orphaned_nodes_part($table, $job_id = NULL, $nentries,
+    $offset, $linking_table, $node_type) {
 
 
-  // build the SQL statments needed to check if nodes point to valid analyses
-  $dsql = "SELECT * FROM {node} WHERE type = 'chado_" . $table . "' order by nid";
-  $nsql = "SELECT * FROM {node} WHERE nid = :nid";
-  $csql = "SELECT * FROM {chado_" . $table . "} WHERE nid = :nid ";
-  $clsql= "SELECT * FROM {chado_" . $table . "}";
-  $lsql = "SELECT * FROM {" . $table . "} where " . $table . "_id = :" . $table . "_id ";
-
-  // load into nodes array
-  print "Getting nodes\n";
-  $nodes = array();
-  $res = db_query($dsql);
-  foreach ($res as $node) {
-    $nodes[$count] = $node;
-    $count++;
-  }
+  $count = 0;
 
 
-  // load the chado_$table into an array
-  print "Getting chado_$table\n";
+  // Retrieve all of the entries in the linker table for a given node type
+  // and place into an array.
+  print "Verifying $linking_table records...\n";
   $cnodes = array();
   $cnodes = array();
-  $res = db_query($clsql);
+  $clsql= "
+    SELECT *
+    FROM {" . $linking_table . "} LT
+      INNER JOIN {node} N ON N.nid = LT.nid
+    WHERE N.type = :node_type
+    ORDER BY LT.nid LIMIT $nentries OFFSET $offset";
+  $res = db_query($clsql, array(':node_type' => $node_type));
   foreach ($res as $node) {
   foreach ($res as $node) {
     $cnodes[$count] = $node;
     $cnodes[$count] = $node;
     $count++;
     $count++;
   }
   }
-  $interval = intval($count * 0.01);
-  if ($interval < 1) {
-    $interval = 1;
-  }
 
 
-  // iterate through all of the chado_$table entries and remove those
-  // that don't have a node or don't have a $table record in chado.libary
-  print "Verifying all chado_$table Entries\n";
+  // Iterate through all of the $linking_table entries and remove those
+  // that don't have a node or don't have a $table record.
   $deleted = 0;
   $deleted = 0;
-  foreach ($cnodes as $nid) {
-
-    // update the job status every 1% analyses
-    if ($job_id and $i % $interval == 0) {
-      tripal_set_job_progress($job_id, intval(($i / $count) * 100));
+  if ($count > 0) {
+    $i = 0;
+    $interval = intval($count * 0.01);
+    if ($interval < 1) {
+      $interval = 1;
     }
     }
+    foreach ($cnodes as $nid) {
+      // Update the job status every 1% analyses
+      if ($job_id and $i % $interval == 0) {
+        $percent = sprintf("%.2f", ($i / $count) * 100);
+        tripal_set_job_progress($job_id, intval($percent));
+        print "Percent complete: $percent%. Memory: " . number_format(memory_get_usage()) . " bytes.\r";
+      }
 
 
-    // see if the node exits, if not remove the entry from the chado_$table table
-    $results = db_query($nsql, array(':nid' => $nid->nid));
-    $node = $results->fetchObject();
-    if (!$node) {
-      $deleted++;
-      db_query("DELETE FROM {chado_" . $table . "} WHERE nid = :nid", array(':nid' => $nid->nid));
-      $message = "chado_$table missing node.... DELETING: $nid->nid";
-      watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
-    }
+      // See if the node exits, if not remove the entry from linking table table.
+      $nsql = "SELECT * FROM {node} WHERE nid = :nid";
+      $results = db_query($nsql, array(':nid' => $nid->nid));
+      $node = $results->fetchObject();
+      if (!$node) {
+        $deleted++;
+        db_query("DELETE FROM {" . $linking_table . "} WHERE nid = :nid", array(':nid' => $nid->nid));
+        //print "$linking_table missing node.... DELETING: $nid->nid\n";
+      }
 
 
-    // see if the record in chado exist, if not remove the entry from the chado_$table
-    $table_id = $table . "_id";
-    $results = chado_query($lsql, array(":" . $table . "_id" => $nid->$table_id));
-    $record = $results->fetchObject();
-    if (!$record) {
-      $deleted++;
-      $sql = "DELETE FROM {chado_" . $table . "} WHERE " . $table . "_id = :" . $table . "_id";
-      db_query($sql, array(":" . $table . "_id" => $nid->$table_id));
-      $message = "chado_$table missing $table.... DELETING entry.";
-      watchdog('tripal_core', $message, array(), WATCHDOG_NOTICE);
+      // Does record in chado exists, if not remove entry from $linking_table.
+      $table_id = $table . "_id";
+      $lsql = "SELECT * FROM {" . $table . "} where " . $table . "_id = :" . $table . "_id";
+      $results = chado_query($lsql, array(":" . $table . "_id" => $nid->$table_id));
+      $record = $results->fetchObject();
+      if (!$record) {
+        $deleted++;
+        $sql = "DELETE FROM {" . $linking_table . "} WHERE " . $table . "_id = :" . $table . "_id";
+        db_query($sql, array(":" . $table . "_id" => $nid->$table_id));
+        //print "$linking_table missing $table.... DELETING entry.\n";
+      }
+      $i++;
     }
     }
-    $i++;
+    $percent = sprintf("%.2f", ($i / $count) * 100);
+    tripal_set_job_progress($job_id, intval($percent));
+    print "Percent complete: $percent%. Memory: " . number_format(memory_get_usage()) . " bytes.\r";
+  }
+  print "\nDeleted $deleted record(s) from $linking_table missing either a node or chado entry.\n";
+
+  // Build the SQL statements needed to check if nodes point to valid record.
+  print "Verifying nodes...\n";
+  $dsql = "
+    SELECT *
+    FROM {node}
+    WHERE type = :node_type
+    ORDER BY nid
+    LIMIT $nentries OFFSET $offset
+  ";
+
+  $dsql_args = array(':node_type' => $node_type);
+  $nodes = array();
+  $res = db_query($dsql, $dsql_args);
+  $count = 0;
+  foreach ($res as $node) {
+    $nodes[$count] = $node;
+    $count++;
   }
   }
-  print "\t$deleted chado_$table entries missing either a node or chado entry.\n";
 
 
-  // iterate through all of the nodes and delete those that don't
-  // have a corresponding entry in chado_$table
+  // Iterate through all of the nodes and delete those that don't
+  // have a corresponding entry in the linking table.
   $deleted = 0;
   $deleted = 0;
-  foreach ($nodes as $node) {
-
-    // update the job status every 1% libraries
-    if ($job_id and $i % $interval == 0) {
-      tripal_set_job_progress($job_id, intval(($i / $count) * 100));
+  if ($count > 0) {
+    $i = 0;
+    $interval = intval($count * 0.01);
+    if ($interval < 1) {
+      $interval = 1;
     }
     }
-
-    // check to see if the node has a corresponding entry
-    // in the chado_$table table. If not then delete the node.
-    $results = db_query($csql, array(":nid" => $node->nid));
-    $link = $results->fetchObject();
-    if (!$link) {
-      if (node_access('delete', $node)) {
-        $deleted++;
-        $message = "Node missing in chado_$table table.... DELETING node $node->nid";
-        watchdog("tripal_core", $message, array(), WATCHDOG_NOTICE);
-        node_delete($node->nid);
-      }
-      else {
-        $message = "Node missing in chado_$table table.... but cannot delete due to improper permissions (node $node->nid)";
-        watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
+    foreach ($nodes as $node) {
+      // update the job status every 1%
+      if ($job_id and $i % $interval == 0) {
+        $percent = sprintf("%.2f", ($i / $count) * 100);
+        tripal_set_job_progress($job_id, intval($percent));
+        print "Percent complete: $percent%. Memory: " . number_format(memory_get_usage()) . " bytes.\r";
       }
       }
+
+      // check to see if the node has a corresponding entry
+      // in the $linking_table table. If not then delete the node.
+       $csql = "SELECT * FROM {" . $linking_table . "} WHERE nid = :nid ";
+       $results = db_query($csql, array(':nid' => $node->nid));
+       $link = $results->fetchObject();
+       if (!$link) {
+         // Checking node_access creates a memory leak. Commenting out for now
+         // assuming that this code can only be run by a site administrator
+         // anyway.
+//         if (node_access('delete', $node)) {
+           $deleted++;
+           node_delete($node->nid);
+//         }
+//         else {
+//           print "\nNode missing in $linking_table table.... but cannot delete due to improper permissions (node $node->nid)\n";
+//         }
+       }
+      $i++;
     }
     }
-    $i++;
+    $percent = sprintf("%.2f", ($i / $count) * 100);
+    tripal_set_job_progress($job_id, intval($percent));
+    print "Percent complete: $percent%. Memory: " . number_format(memory_get_usage()) . " bytes.\r";
+    print "\nDeleted $deleted node(s) that did not have corresponding $linking_table entries.\n";
   }
   }
-  print "\t$deleted nodes did not have corresponding chado_$table entries.\n";
 
 
   return '';
   return '';
 }
 }
@@ -992,8 +1197,8 @@ function chado_cleanup_orphaned_nodes($table, $job_id = NULL) {
 /**
 /**
  * Create New Node
  * Create New Node
  *
  *
- * Note: For your own module, replace hook in the function name with the machine-name of
- * your chado node type (ie: chado_feature).
+ * Note: For your own module, replace hook in the function name with the
+ * machine-name of your chado node type (ie: chado_feature).
  *
  *
  * @param $new_node:
  * @param $new_node:
  *   a basic new node object
  *   a basic new node object
@@ -1001,51 +1206,53 @@ function chado_cleanup_orphaned_nodes($table, $job_id = NULL) {
  *   the record object from chado specifying the biological data for this node
  *   the record object from chado specifying the biological data for this node
  *
  *
  * @return
  * @return
- *   A node object containing all the fields necessary to create a new node during sync
+ *   A node object containing all the fields necessary to create a new node
+ *   during sync
  *
  *
  * @ingroup tripal_chado_node_api
  * @ingroup tripal_chado_node_api
  */
  */
 function hook_chado_node_sync_create_new_node($new_node, $record) {
 function hook_chado_node_sync_create_new_node($new_node, $record) {
 
 
-  // Add relevant chado details to the new node object
-  // This really only needs to be the fields from the node used during node creation
-  // including values used to generate the title, etc.
-  // All additional chado data will be added via nodetype_load when the node is later used
+  // Add relevant chado details to the new node object. This really only
+  // needs to be the fields from the node used during node creation
+  // including values used to generate the title, etc. All additional chado
+  // data will be added via nodetype_load when the node is later used
   $new_node->uniquename = $record->uniquename;
   $new_node->uniquename = $record->uniquename;
 
 
   return $new_node;
   return $new_node;
 }
 }
 
 
 /**
 /**
- * Alter the sync form (optional)
+ * Alter the Chado node sync form.
  *
  *
- * This might be necessary if you need additional filtering options for choosing which
- * chado records to sync or even if you just want to further customize the help text
- * provided by the form.
+ * This might be necessary if you need additional filtering options for
+ * choosing which chado records to sync or even if you just want to further
+ * customize the help text provided by the form.
  *
  *
- * Note: For your own module, replace hook in the function name with the machine-name of
- * your chado node type (ie: chado_feature).
+ * Note: For your own module, replace hook in the function name with the
+ * machine-name of your chado node type (ie: chado_feature).
  *
  *
  * @ingroup tripal_chado_node_api
  * @ingroup tripal_chado_node_api
  */
  */
 function hook_chado_node_sync_form($form, &$form_state) {
 function hook_chado_node_sync_form($form, &$form_state) {
 
 
-  // Change or add to the form array as needed
-  // Any changes should be made in accordance with the Drupal Form API
+  // Change or add to the form array as needed.
+  // Any changes should be made in accordance with the Drupal Form API.
 
 
   return $form;
   return $form;
 }
 }
 
 
 /**
 /**
- * Bypass chado node api sync form submit (optional). Allows you to use this function
- * as your own submit.
+ * Bypass chado node api sync form submit.
+ *
+ * Allows you to use this function as your own submit.
  *
  *
- * This might be necessary if you want to add additional arguements to the tripal job or
- * to call your own sync'ing function if the generic chado_node_sync_records() is not
- * sufficient.
+ * This might be necessary if you want to add additional arguements to the
+ * tripal job or to call your own sync'ing function if the generic
+ * chado_node_sync_records() is not sufficient.
  *
  *
- * Note: For your own module, replace hook in the function name with the machine-name of
- * your chado node type (ie: chado_feature).
+ * Note: For your own module, replace hook in the function name with the
+ * machine-name of your chado node type (ie: chado_feature).
  *
  *
  * @ingroup tripal_chado_node_api
  * @ingroup tripal_chado_node_api
  */
  */
@@ -1054,19 +1261,28 @@ function hook_chado_node_sync_form_submit ($form, $form_state) {
   global $user;
   global $user;
 
 
   $job_args = array(
   $job_args = array(
-    $base_table,      // the base chado table (ie: feature)
-    $max_sync,        // the maximum number of records to sync or FALSE for sync all that match
-    $organism_id,     // the organism_id to restrict records to or FALSE if not to restrict by organism_id
-    $types            // A string with the cvterm.name of the types to restrict to separated by |||
+    // The base chado table (ie: feature).
+    $base_table,
+    // The maximum number of records to sync or FALSE for sync all that match.
+    $max_sync,
+    // The organism_id to restrict records to or FALSE if not to restrict by organism_id.
+    $organism_id,
+    // A string with the cvterm.name of the types to restrict to separated by |||
+    $types
   );
   );
 
 
   // You should register a tripal job
   // You should register a tripal job
   tripal_add_job(
   tripal_add_job(
-    $title,                                   // the title of the job -be descriptive
-    $module,                                  // the name of your module
-    'chado_node_sync_records',    // the chado node api sync function
-    $job_args,                                // an array with the arguments to pass to the above function
-    $user->uid                                // the user who submitted the job
+    // The title of the job -be descriptive.
+    $title,
+    // The name of your module.
+    $module,
+    // The chado node api sync function.
+    'chado_node_sync_records',
+    // An array with the arguments to pass to the above function.
+    $job_args,
+    // The user who submitted the job.
+    $user->uid
   );
   );
 
 
 }
 }
@@ -1075,13 +1291,14 @@ function hook_chado_node_sync_form_submit ($form, $form_state) {
 /**
 /**
  * Alter the query that retrieves records to be sync'd (optional)
  * Alter the query that retrieves records to be sync'd (optional)
  *
  *
- * This might be necessary if you need fields from other chado tables to create your node
- * or if your chado node type only supports a subset of a given table (ie: a germplasm node
- * type might only support node creation for cerain types of stock records in which case
- * you would need to filter the results to only those types).
+ * This might be necessary if you need fields from other chado tables to
+ * create your node or if your chado node type only supports a subset of a
+ * given table (ie: a germplasm node type might only support node creation for
+ * cerain types of stock records in which case you would need to filter the
+ * results to only those types).
  *
  *
- * Note: For your own module, replace hook in the function name with the machine-name of
- * your chado node type (ie: chado_feature).
+ * Note: For your own module, replace hook in the function name with the
+ * machine-name of your chado node type (ie: chado_feature).
  *
  *
  * @param $query
  * @param $query
  *   An array containing the following:
  *   An array containing the following:

+ 28 - 14
tripal_core/api/tripal_core.chado_nodes.relationships.api.inc

@@ -300,14 +300,14 @@ function chado_add_node_form_relationships(&$form, &$form_state, $details) {
     ),
     ),
   );
   );
 
 
-  $instructions = 'Relationships should be read like a sentence ([subject] [type] 
-    [object]) in order to determine their direction and thus their meaning. When 
-    adding a relationship, it is easiest to first select the type of relationship you would 
+  $instructions = 'Relationships should be read like a sentence ([subject] [type]
+    [object]) in order to determine their direction and thus their meaning. When
+    adding a relationship, it is easiest to first select the type of relationship you would
     like to enter and then select whether the current %nodetype is the subject
     like to enter and then select whether the current %nodetype is the subject
-    or object (based on which "sentence" makes sense). Finally enter the other 
-    %nodetype in the remaining text box (making sure to select from the 
-    autocomplete drop-down) before clicking "Add". To remove incorrect relationships, click the 
-    "Remove" button. Note: you cannot edit previously added relationships 
+    or object (based on which "sentence" makes sense). Finally enter the other
+    %nodetype in the remaining text box (making sure to select from the
+    autocomplete drop-down) before clicking "Add". To remove incorrect relationships, click the
+    "Remove" button. Note: you cannot edit previously added relationships
     but instead need to remove and re-add them.';
     but instead need to remove and re-add them.';
   $form['relationships']['descrip'] = array(
   $form['relationships']['descrip'] = array(
     '#type' => 'item',
     '#type' => 'item',
@@ -321,7 +321,8 @@ function chado_add_node_form_relationships(&$form, &$form_state, $details) {
     '#tree' => TRUE,
     '#tree' => TRUE,
     '#prefix' => '<div id="tripal-generic-edit-relationships-table">',
     '#prefix' => '<div id="tripal-generic-edit-relationships-table">',
     '#suffix' => '</div>',
     '#suffix' => '</div>',
-    '#theme' => 'chado_node_relationships_form_table'
+    '#theme' => 'chado_node_relationships_form_table',
+    '#weight' => 5
   );
   );
 
 
   // Add defaults into form_state to be used elsewhere
   // Add defaults into form_state to be used elsewhere
@@ -420,13 +421,24 @@ function chado_add_node_form_relationships(&$form, &$form_state, $details) {
     if (array_key_exists($relationship->type_id, $type_options)) {
     if (array_key_exists($relationship->type_id, $type_options)) {
       $num_relationships++;
       $num_relationships++;
 
 
+      $type_class = str_replace(array(' ','_'), '-', $relationship->type_name);
+      $current_class = 'current-unknown';
+      if ($details['base_key_value']) {
+        if ($relationship->object_id == $details['base_key_value']) {
+          $current_class = 'current-object';
+        }
+        elseif ($relationship->subject_id == $details['base_key_value']) {
+          $current_class = 'current-subject';
+        }
+      }
+
       $form['relationships']['relationship_table'][$relationship->type_id]['#type'] = 'markup';
       $form['relationships']['relationship_table'][$relationship->type_id]['#type'] = 'markup';
       $form['relationships']['relationship_table'][$relationship->type_id]['#type'] = '';
       $form['relationships']['relationship_table'][$relationship->type_id]['#type'] = '';
 
 
       $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#type'] = 'markup';
       $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#type'] = 'markup';
       $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#value'] = '';
       $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#value'] = '';
       $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#attributes'] = array(
       $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#attributes'] = array(
-        'class' => array('relationship', 'saved')
+        'class' => array('relationship', 'saved', $type_class, $current_class)
       );
       );
 
 
       // Determine whether this relationship is unsaved or not.
       // Determine whether this relationship is unsaved or not.
@@ -434,7 +446,7 @@ function chado_add_node_form_relationships(&$form, &$form_state, $details) {
       // saved yet we will have entered a TEMP###.
       // saved yet we will have entered a TEMP###.
       if (preg_match('/^TEMP/', $relationship->relationship_id)) {
       if (preg_match('/^TEMP/', $relationship->relationship_id)) {
         $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#attributes'] = array(
         $form['relationships']['relationship_table'][$relationship->type_id][$relationship->relationship_id]['#attributes'] = array(
-          'class' => array('relationship', 'unsaved')
+          'class' => array('relationship', 'unsaved', $type_class, $current_class)
         );
         );
       }
       }
 
 
@@ -577,7 +589,8 @@ function chado_add_node_form_relationships(&$form, &$form_state, $details) {
 
 
   $form['relationships']['admin_message'] = array(
   $form['relationships']['admin_message'] = array(
     '#type' => 'markup',
     '#type' => 'markup',
-    '#markup' => $tripal_message
+    '#markup' => $tripal_message,
+    '#weight' => 10
   );
   );
 }
 }
 
 
@@ -590,7 +603,7 @@ function chado_add_node_form_relationships(&$form, &$form_state, $details) {
 function chado_add_node_form_relationships_add_button_validate($form, &$form_state) {
 function chado_add_node_form_relationships_add_button_validate($form, &$form_state) {
 
 
   $details = unserialize($form_state['values']['relationship_table']['details']);
   $details = unserialize($form_state['values']['relationship_table']['details']);
-  
+
   // First deal with autocomplete fields.
   // First deal with autocomplete fields.
   // Extract the base_id assuming '(###) NAME FIELD'.
   // Extract the base_id assuming '(###) NAME FIELD'.
   if (!empty($form_state['values']['relationship_table']['new']['subject_name'])) {
   if (!empty($form_state['values']['relationship_table']['new']['subject_name'])) {
@@ -630,8 +643,9 @@ function chado_add_node_form_relationships_add_button_validate($form, &$form_sta
     AND $form_state['values']['relationship_table']['new']['object_is_current']) {
     AND $form_state['values']['relationship_table']['new']['object_is_current']) {
 
 
     form_set_error('relationship_table][new][object_is_current', 'Only one member of the relationship may be
     form_set_error('relationship_table][new][object_is_current', 'Only one member of the relationship may be
-      the current '.$details['nodetype'].'. This is specified by checking the "Current '.$details['nodetype'].'"
-      checkbox for either the subject or object.');
+      the current '.$details['nodetype'].' in order to avoid a circular relationship. If you really meant to
+      add a circular relationship then check the "Current '.$details['nodetype'].'" for one side of the
+      relationship and enter the current stock name via the autocomplete for the other side of the relationship.');
   }
   }
   // If it was determined current via checkbox, we need to ensure the name
   // If it was determined current via checkbox, we need to ensure the name
   // provided actually matches the current node.
   // provided actually matches the current node.

+ 5 - 10
tripal_core/api/tripal_core.chado_nodes.title_and_path.inc

@@ -546,14 +546,9 @@ function chado_get_node_url($node) {
           $url = str_replace($token, $value, $url);
           $url = str_replace($token, $value, $url);
         }
         }
         else {
         else {
-          tripal_report_error(
-            'chado_node_api',
-            TRIPAL_ERROR,
-            'Unable to replace %token. The value in the node should be a string but is instead: %value',
-            array(
-              '%token' => $token,
-              '%value' => print_r($value, TRUE)
-            )
+          tripal_report_error('chado_node_api',TRIPAL_ERROR,
+            'Unable to replace %token. The value in the node should be a string but is instead: \'%value\'',
+            array('%token' => $token, '%value' => print_r($value, TRUE))
           );
           );
         }
         }
       }
       }
@@ -1332,7 +1327,7 @@ function chado_get_token_value($token_info, $node) {
       else {
       else {
         tripal_report_error('chado_node_api', TRIPAL_WARNING,
         tripal_report_error('chado_node_api', TRIPAL_WARNING,
           'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
           'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
-          'to access %index for the following: %var.',
+          'to access \'%index\' for the following: \'%var\'.',
           array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
           array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
         );
         );
         return '';
         return '';
@@ -1346,7 +1341,7 @@ function chado_get_token_value($token_info, $node) {
     else {
     else {
       tripal_report_error('chado_node_api', TRIPAL_WARNING,
       tripal_report_error('chado_node_api', TRIPAL_WARNING,
         'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
         'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
-        'to access %index for the following: %var.',
+        'to access \'%index\' for the following: \'%var\'.',
         array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
         array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
       );
       );
       return '';
       return '';

+ 6 - 5
tripal_core/api/tripal_core.chado_query.api.inc

@@ -1153,8 +1153,9 @@ function chado_select_record($table, $columns, $values, $options = NULL) {
         else {
         else {
           tripal_report_error('tripal_core', TRIPAL_ERROR,
           tripal_report_error('tripal_core', TRIPAL_ERROR,
             'chado_select_record: There is no value for %field thus we cannot ' .
             'chado_select_record: There is no value for %field thus we cannot ' .
-            ' check if this record for table, %table, is unique.',
-            array('%field' => $field, '%table' => $table), array('print' => $print_errors));
+            'check if this record for table, %table, is unique. %values',
+            array('%field' => $field, '%table' => $table, '%values' => print_r($values, TRUE)),
+            array('print' => $print_errors));
           return FALSE;
           return FALSE;
         }
         }
       }
       }
@@ -1263,8 +1264,8 @@ function chado_select_record($table, $columns, $values, $options = NULL) {
           // Ensure that there were results returned.
           // Ensure that there were results returned.
           elseif (count($results)==0) {
           elseif (count($results)==0) {
             tripal_report_error('tripal_core', TRIPAL_ERROR,
             tripal_report_error('tripal_core', TRIPAL_ERROR,
-              'chado_select_record: the foreign key definition for %field
-              returned no results where the definition supplied was %value',
+              'chado_select_record: the foreign key definition for \'%field\' '.
+              'returned no results where the definition supplied was %value',
               array('%field' => $field, '%value' => print_r($value, TRUE))
               array('%field' => $field, '%value' => print_r($value, TRUE))
             );
             );
             return array();
             return array();
@@ -1499,7 +1500,7 @@ function chado_query($sql, $args = array()) {
     // the featureloc table has some indexes that use function that call other functions
     // the featureloc table has some indexes that use function that call other functions
     // and those calls do not reference a schema, therefore, any tables with featureloc
     // and those calls do not reference a schema, therefore, any tables with featureloc
     // must automaticaly have the chado schema set as active to find
     // must automaticaly have the chado schema set as active to find
-    if (preg_match('/chado.featureloc/i', $sql)) {
+    if (preg_match('/chado.featureloc/i', $sql) or preg_match('/chado.feature/i', $sql)) {
       $previous_db = chado_set_active('chado') ;
       $previous_db = chado_set_active('chado') ;
       $results = db_query($sql, $args);
       $results = db_query($sql, $args);
       chado_set_active($previous_db);
       chado_set_active($previous_db);

+ 53 - 0
tripal_core/api/tripal_core.d3js.api.inc

@@ -0,0 +1,53 @@
+<?php
+/**
+ *
+ */
+
+/**
+ * Implements hook_libraries_info().
+ */
+function tripal_core_libraries_info() {
+  $libraries = array();
+  $libraries['d3'] = array(
+    'name' => 'D3.js',
+    'vendor url' => 'http://d3js.org/',
+    'download url' => 'https://github.com/mbostock/d3',
+    'version arguments' => array(
+      'file' => 'd3.js',
+      'pattern' => '/\s*version: "(\d+\.\d+\.\d+)"/',
+    ),
+    'files' => array(
+      'js' => array(
+        'd3.min.js',
+      ),
+    ),
+  );
+
+  return $libraries;
+}
+
+/**
+ * Load D3.js releated javascripts for the current page.
+ */
+function tripal_add_d3js() {
+  $library = array('loaded' => FALSE);
+
+  // First try to load d3.js using the libraries API.
+  // This will work if the site admin has saved d3.js in their libraries folder.
+  if (module_exists('libraries_api')) {
+    $library = libraries_load('d3');
+  }
+
+  // If we were not able to load d3.js using the libraries API
+  // then revert to loading the remote files manually.
+  if (!isset($library['loaded']) OR !$library['loaded']) {
+
+    // If SSL is being used then use a secure CDN for d3.js
+    if (isset($_SERVER['HTTPS'])) {
+      drupal_add_js('https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js');
+    }
+    else {
+      drupal_add_js('http://d3js.org/d3.v3.min.js');
+    }
+  }
+}

+ 25 - 8
tripal_core/api/tripal_core.files.api.inc

@@ -16,10 +16,16 @@
  */
  */
 
 
 /**
 /**
- * This function is typically used in the '.install' file for a Tripal module
- * Each module should call this function during installation to create
- * the module data directory which is sites/default/files/tripal/[module_name].
- * This directory can then be used by the module for storing files.
+ * Creates a directory for a module in the Drupal's public files directory.
+ *
+ * Previously it was recommended that this function be called during
+ * installation of the module in the .install file.  However this causes
+ * permission problems if the module is installed via drush with a
+ * user account that is not the same as the web user.  Therefore, this
+ * function should not be called in a location accessiblve via a drush
+ * command.  The tripal_get_files_dir() and tripal_get_files_stream()
+ * will automatically create the directory if it doesn't exist so there is
+ * little need to call this function directly.
  *
  *
  * @param $module_name
  * @param $module_name
  *   the name of the module being installed
  *   the name of the module being installed
@@ -50,7 +56,6 @@ function tripal_create_files_dir($module_name, $path = FALSE) {
 
 
     // now make sure the sub dir exists
     // now make sure the sub dir exists
     $sub_dir = tripal_get_files_dir() . '/' . $module_name . '/' . $path;
     $sub_dir = tripal_get_files_dir() . '/' . $module_name . '/' . $path;
-    print "$sub_dir\n";
     if (!file_prepare_directory($sub_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
     if (!file_prepare_directory($sub_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
       $message = "Can not create directory $sub_dir. ";
       $message = "Can not create directory $sub_dir. ";
       drupal_set_message(check_plain(t($message)), 'error');
       drupal_set_message(check_plain(t($message)), 'error');
@@ -61,7 +66,7 @@ function tripal_create_files_dir($module_name, $path = FALSE) {
 
 
 /**
 /**
  * Retreives the Drupal relative directory for a Tripal module.
  * Retreives the Drupal relative directory for a Tripal module.
- * 
+ *
  * Each Tripal module has a unique data directory which was created using the
  * Each Tripal module has a unique data directory which was created using the
  * tripal_create_files_dir function during installation.  This function
  * tripal_create_files_dir function during installation.  This function
  * retrieves the directory path.
  * retrieves the directory path.
@@ -76,10 +81,16 @@ function tripal_create_files_dir($module_name, $path = FALSE) {
  */
  */
 function tripal_get_files_dir($module_name = FALSE) {
 function tripal_get_files_dir($module_name = FALSE) {
 
 
+  // Build the directory path.
   $data_dir = variable_get('file_public_path', conf_path() . '/files/tripal');
   $data_dir = variable_get('file_public_path', conf_path() . '/files/tripal');
 
 
+  // If a module name is provided then append the module directory.
   if ($module_name) {
   if ($module_name) {
     $data_dir .= "/$module_name";
     $data_dir .= "/$module_name";
+
+    // Make sure the directory exists.
+    tripal_create_files_dir($module_name, "/$module_name");
+
   }
   }
 
 
   return $data_dir;
   return $data_dir;
@@ -87,7 +98,7 @@ function tripal_get_files_dir($module_name = FALSE) {
 
 
 /**
 /**
  * Retreives the Drupal stream (e.g. public://...) for a Tripal module.
  * Retreives the Drupal stream (e.g. public://...) for a Tripal module.
- * 
+ *
  * Each Tripal module has a unique data directory which was created using the
  * Each Tripal module has a unique data directory which was created using the
  * tripal_create_files_dir function during installation.  This function
  * tripal_create_files_dir function during installation.  This function
  * retrieves the directory path.
  * retrieves the directory path.
@@ -101,10 +112,16 @@ function tripal_get_files_dir($module_name = FALSE) {
  * @ingroup tripal_files_api
  * @ingroup tripal_files_api
  */
  */
 function tripal_get_files_stream($module_name = FALSE) {
 function tripal_get_files_stream($module_name = FALSE) {
+  // Build the directory path.
   $stream =  'public://tripal';
   $stream =  'public://tripal';
+
+  // If a module name is provided then append the module directory.
   if ($module_name) {
   if ($module_name) {
     $stream .= "/$module_name";
     $stream .= "/$module_name";
+
+    // Make sure the directory exists.
+    tripal_create_files_dir($module_name, "/$module_name");
   }
   }
-  
+
   return $stream;
   return $stream;
 }
 }

+ 6 - 1
tripal_core/api/tripal_core.jobs.api.inc

@@ -65,6 +65,7 @@
  * @ingroup tripal_jobs_api
  * @ingroup tripal_jobs_api
  */
  */
 function tripal_add_job($job_name, $modulename, $callback, $arguments, $uid, $priority = 10) {
 function tripal_add_job($job_name, $modulename, $callback, $arguments, $uid, $priority = 10) {
+  global $user;
 
 
   // convert the arguments into a string for storage in the database
   // convert the arguments into a string for storage in the database
   $args = array();
   $args = array();
@@ -86,7 +87,11 @@ function tripal_add_job($job_name, $modulename, $callback, $arguments, $uid, $pr
     drupal_set_message(t("Job '%job_name' submitted.", array('%job_name' => $job_name)));
     drupal_set_message(t("Job '%job_name' submitted.", array('%job_name' => $job_name)));
     if (user_access('administer tripal')) {
     if (user_access('administer tripal')) {
       $jobs_url = url("admin/tripal/tripal_jobs");
       $jobs_url = url("admin/tripal/tripal_jobs");
-      drupal_set_message(t("Check the <a href='!jobs_url'>jobs page</a> for status.", array('!jobs_url' => $jobs_url)));
+      drupal_set_message(t("Check the <a href='!jobs_url'>jobs page</a> for status.",
+        array('!jobs_url' => $jobs_url)));
+      drupal_set_message(t("You can execute the job queue manually on the command line " .
+        "using the following Drush command: <br>drush trp-run-jobs --username=%uname --root=%base_path",
+        array('%base_path' => DRUPAL_ROOT, '%uname' => $user->name)));
     }
     }
   }
   }
   else {
   else {

+ 2 - 1
tripal_core/api/tripal_core.mviews.api.inc

@@ -41,7 +41,7 @@
  * @ingroup tripal_mviews_api
  * @ingroup tripal_mviews_api
  *
  *
 function tripal_add_legacy_mview($name, $modulename, $mv_table, $mv_specs, $indexed,
 function tripal_add_legacy_mview($name, $modulename, $mv_table, $mv_specs, $indexed,
-  $query, $special_index, $comment = NULL) {
+  $query, $special_index, $comment =OR NULL) {
 
 
   // Create a new record
   // Create a new record
   $record = new stdClass();
   $record = new stdClass();
@@ -314,6 +314,7 @@ function chado_get_mview_table_names() {
   $sql = "SELECT name FROM {tripal_mviews}";
   $sql = "SELECT name FROM {tripal_mviews}";
   $resource = db_query($sql);
   $resource = db_query($sql);
 
 
+  $tables = array();
   foreach ($resource as $r) {
   foreach ($resource as $r) {
     $tables[$r->name] = $r->name;
     $tables[$r->name] = $r->name;
   }
   }

+ 19 - 13
tripal_core/includes/tripal_core.extensions.inc

@@ -319,6 +319,8 @@ function tripal_core_extension_form_add_extensions(&$form, $form_state, $extensi
         continue;
         continue;
       }
       }
 
 
+      $extension['title'] = trim($extension['title']);
+
       // If this is an extension module then there will be a home page for it
       // If this is an extension module then there will be a home page for it
       $home_page = '';
       $home_page = '';
       if (array_key_exists('home_page', $extension[$namespace])) {
       if (array_key_exists('home_page', $extension[$namespace])) {
@@ -347,7 +349,7 @@ function tripal_core_extension_form_add_extensions(&$form, $form_state, $extensi
             ->execute()
             ->execute()
             ->fetchField();
             ->fetchField();
           if ($blk_id) {
           if ($blk_id) {
-            $is_installed = '<li>A bulk loader tempalte with this name is already installed.</li>';
+            $is_installed = '<li>A bulk loader template with this name is already installed.</li>';
           }
           }
           break;
           break;
         case 'Materialized View':
         case 'Materialized View':
@@ -524,20 +526,24 @@ function tripal_core_extensions_form_submit($form, &$form_state) {
     $type = $extension['category'];
     $type = $extension['category'];
     switch ($type) {
     switch ($type) {
       case 'Bulk Loader Template':
       case 'Bulk Loader Template':
-        // TODO: we need an API function for adding a bulk loader
-        $id = db_insert('tripal_bulk_loader_template')
-          ->fields(array(
-            'name' => $extension['title'],
-            'template_array' => $extension[$namespace]['bulkldr_export'],
-            'created' => time(),
-            'changed' => time()
-          ))
-          ->execute();
-        if (!$id) {
-          drupal_set_message("Cannot import this bulk loader. Please view the 'Recent log messages' report for more details.",  'error');
+        $options = array(
+          'template_name' => $extension['title'],
+          'template_array' => $extension[$namespace]['bulkldr_export'],
+          'strict' => TRUE,
+        );
+        $errors = array();
+        $warnings = array();
+        $success = tripal_insert_bulk_loader_template($options, $errors, $warnings);
+        if ($success) {
+          drupal_set_message("Bulk loader succesfully added.");
         }
         }
         else {
         else {
-          drupal_set_message("Bulk loader succesfully added.");
+          drupal_set_message("Error importing this bulk loader.",  'error');
+          if (count($errors) > 0) {
+            foreach($errors as $field => $message) {
+              drupal_set_message($message, 'error');
+            }
+          }
         }
         }
         break;
         break;
       case 'Materialized View':
       case 'Materialized View':

+ 11 - 4
tripal_core/includes/tripal_core.jobs.inc

@@ -252,10 +252,17 @@ function tripal_jobs_view($job_id) {
 
 
   // We do not know what the arguments are for and we want to provide a
   // We do not know what the arguments are for and we want to provide a
   // meaningful description to the end-user. So we use a callback function
   // meaningful description to the end-user. So we use a callback function
-  // deinfed in the module that created the job to describe in an array
+  // defined in the module that created the job to describe in an array
   // the arguments provided.  If the callback fails then just use the
   // the arguments provided.  If the callback fails then just use the
-  // arguments as they are
-  $args = preg_split("/::/", $job->arguments);
+  // arguments as they are.  Historically, job arguments were separated with
+  // two colon. We now store them as a serialized array. So, we need to handle
+  // both cases.
+  if (preg_match("/::/", $job->arguments)) {
+    $args = preg_split("/::/", $job->arguments);
+  }
+  else {
+    $args = unserialize($job->arguments);
+  }
   $arg_hook = $job->modulename . "_job_describe_args";
   $arg_hook = $job->modulename . "_job_describe_args";
   if (is_callable($arg_hook)) {
   if (is_callable($arg_hook)) {
     $new_args = call_user_func_array($arg_hook, array($job->callback, $args));
     $new_args = call_user_func_array($arg_hook, array($job->callback, $args));
@@ -276,7 +283,7 @@ function tripal_jobs_view($job_id) {
   }
   }
 
 
   // build the links
   // build the links
-  $links  = l('Return to jobs list', "admin/tripal/tripal_jobs/") . ' | ' .
+  $links  = l('Return to jobs list', "admin/tripal/tripal_jobs/") . ' | ';
   $links .= l('Re-run this job', "admin/tripal/tripal_jobs/rerun/" . $job->job_id) . ' | ';
   $links .= l('Re-run this job', "admin/tripal/tripal_jobs/rerun/" . $job->job_id) . ' | ';
   if ($job->start_time == 0 and $job->end_time == 0) {
   if ($job->start_time == 0 and $job->end_time == 0) {
     $links .= l('Cancel this job', "admin/tripal/tripal_jobs/cancel/" . $job->job_id) . ' | ';
     $links .= l('Cancel this job', "admin/tripal/tripal_jobs/cancel/" . $job->job_id) . ' | ';

+ 1 - 0
tripal_core/includes/tripal_core.mviews.inc

@@ -76,6 +76,7 @@ function tripal_mview_report($mview_id) {
   $update_url = url("admin/tripal/schema/mviews/action/update/$mview->mview_id");
   $update_url = url("admin/tripal/schema/mviews/action/update/$mview->mview_id");
   $delete_url = url("admin/tripal/schema/mviews/action/delete/$mview->mview_id");
   $delete_url = url("admin/tripal/schema/mviews/action/delete/$mview->mview_id");
   $edit_url = url("admin/tripal/schema/mviews/edit/$mview->mview_id");
   $edit_url = url("admin/tripal/schema/mviews/edit/$mview->mview_id");
+  $export_url = url("admin/tripal/schema/mviews/export/$mview->mview_id");
   $rows[] = array('Actions', "<a href='$update_url'>Populate</a>, <a href='$edit_url'>Edit</a>,  <a href='$delete_url'>Delete</a>");
   $rows[] = array('Actions', "<a href='$update_url'>Populate</a>, <a href='$edit_url'>Edit</a>,  <a href='$delete_url'>Delete</a>");
 
 
   if ($mview->last_update > 0) {
   if ($mview->last_update > 0) {

+ 60 - 23
tripal_core/tripal_core.drush.inc

@@ -21,7 +21,7 @@
  */
  */
 function tripal_core_drush_help($command) {
 function tripal_core_drush_help($command) {
   switch ($command) {
   switch ($command) {
-    
+
     // TRIPAL JOBS
     // TRIPAL JOBS
     case 'trp-run-jobs':
     case 'trp-run-jobs':
       return dt('Launches pending jobs waiting in the queue.');
       return dt('Launches pending jobs waiting in the queue.');
@@ -101,14 +101,16 @@ function tripal_core_drush_command() {
   $items['trp-run-jobs'] = array(
   $items['trp-run-jobs'] = array(
     'description' => dt('Launches jobs waiting in the queue. Only one job can execute at a time unless the --parllel=1 option is provided.'),
     'description' => dt('Launches jobs waiting in the queue. Only one job can execute at a time unless the --parllel=1 option is provided.'),
     'examples' => array(
     'examples' => array(
-      'Single Job' => 'drush trp-run-jobs --user=administrator',
-      'Parallel Job' => 'drush trp-run-jobs --user=administrator --parallel=1'
+      'Single Job' => 'drush trp-run-jobs --username=administrator',
+      'Parallel Job' => 'drush trp-run-jobs --username=administrator --parallel=1'
     ),
     ),
     'arguments' => array(),
     'arguments' => array(),
     'options' => array(
     'options' => array(
       'user' => array(
       'user' => array(
+        'description' => dt('DEPRECATED. Conflicts with Drush 7.x --user argument. Please use the --username argument.'),
+      ),
+      'username' => array(
         'description' => dt('The Drupal user name for which the job should be run.  The permissions for this user will be used.'),
         'description' => dt('The Drupal user name for which the job should be run.  The permissions for this user will be used.'),
-        'required' => TRUE,
       ),
       ),
       'parallel' => dt('Normally jobs are executed one at a time. But if you are certain no conflicts will occur with other currently running jobs you may set this argument to a value of 1 to make the job run in parallel with other running jobs.'),
       'parallel' => dt('Normally jobs are executed one at a time. But if you are certain no conflicts will occur with other currently running jobs you may set this argument to a value of 1 to make the job run in parallel with other running jobs.'),
       'job_id' => dt('Provide a job_id to run a specific job. Only jobs that have not been run already can be used'),
       'job_id' => dt('Provide a job_id to run a specific job. Only jobs that have not been run already can be used'),
@@ -117,14 +119,16 @@ function tripal_core_drush_command() {
   $items['trp-rerun-job'] = array(
   $items['trp-rerun-job'] = array(
     'description' => dt('Re-run a specific job from the queue.'),
     'description' => dt('Re-run a specific job from the queue.'),
     'examples' => array(
     'examples' => array(
-      'Single Job' => 'drush trp-rerun-job --user=administrator --job_id=2',
-      'Parallel Job' => 'drush trp-rerun-job --user=administrator  --job_id=2 --parallel=1'
+      'Single Job' => 'drush trp-rerun-job --username=administrator --job_id=2',
+      'Parallel Job' => 'drush trp-rerun-job --username=administrator  --job_id=2 --parallel=1'
     ),
     ),
     'arguments' => array(),
     'arguments' => array(),
     'options' => array(
     'options' => array(
       'user' => array(
       'user' => array(
+        'description' => dt('DEPRECATED. Conflicts with Drush 7.x --user argument. Please use the --username argument.'),
+      ),
+      'username' => array(
         'description' => dt('The Drupal user name for which the job should be run.  The permissions for this user will be used.'),
         'description' => dt('The Drupal user name for which the job should be run.  The permissions for this user will be used.'),
-        'required' => TRUE,
       ),
       ),
       'job_id' => array(
       'job_id' => array(
         'description' => dt('The job ID to run.'),
         'description' => dt('The job ID to run.'),
@@ -199,7 +203,7 @@ function tripal_core_drush_command() {
       'Parallel Job' => 'drush tripal-jobs-launch admin --parallel=1'
       'Parallel Job' => 'drush tripal-jobs-launch admin --parallel=1'
     ),
     ),
     'arguments' => array(
     'arguments' => array(
-      'user' => dt('The Drupal username under which the job should be run.  The permissions for this user will be used.'),
+      'username' => dt('The Drupal username under which the job should be run.  The permissions for this user will be used.'),
     ),
     ),
     'options' => array(
     'options' => array(
       'parallel' => dt('Normally jobs are executed one at a time. But if you are certain no conflicts will occur with other currently running jobs you may set this argument to a value of 1 to make the job run in parallel with other running jobs.'),
       'parallel' => dt('Normally jobs are executed one at a time. But if you are certain no conflicts will occur with other currently running jobs you may set this argument to a value of 1 to make the job run in parallel with other running jobs.'),
@@ -214,7 +218,7 @@ function tripal_core_drush_command() {
       'Parallel Job' => 'drush tripal-jobs-rerun admin  2 --parallel=1'
       'Parallel Job' => 'drush tripal-jobs-rerun admin  2 --parallel=1'
     ),
     ),
     'arguments' => array(
     'arguments' => array(
-      'user' => dt('The Drupal username under which the job should be run.  The permissions for this user will be used.'),
+      'username' => dt('The Drupal username under which the job should be run.  The permissions for this user will be used.'),
       'job_id' => dt('The job ID to run.'),
       'job_id' => dt('The job ID to run.'),
     ),
     ),
     'options' => array(
     'options' => array(
@@ -269,7 +273,7 @@ function drush_tripal_core_set_user($username) {
     $results = db_query($sql, array(':name' => $username));
     $results = db_query($sql, array(':name' => $username));
     $u = $results->fetchObject();
     $u = $results->fetchObject();
     if (!$u) {
     if (!$u) {
-      drush_print('ERROR: Please provide a valid username for running this job.');
+      drush_print('ERROR: Please provide a valid username (--username argument) for running this job.');
       exit;
       exit;
     }
     }
     global $user;
     global $user;
@@ -277,7 +281,7 @@ function drush_tripal_core_set_user($username) {
     return $u->uid;
     return $u->uid;
   }
   }
   else {
   else {
-    drush_print('ERROR: Please provide a username for running this job.');
+    drush_print('ERROR: Please provide a username (--username argument) for running this job.');
     exit;
     exit;
   }
   }
 }
 }
@@ -290,10 +294,26 @@ function drush_tripal_core_set_user($username) {
  * @ingroup tripal_drush
  * @ingroup tripal_drush
  */
  */
 function drush_tripal_core_trp_run_jobs() {
 function drush_tripal_core_trp_run_jobs() {
-  $username = drush_get_option('user');
   $parallel = drush_get_option('parallel');
   $parallel = drush_get_option('parallel');
   $job_id   = drush_get_option('job_id');
   $job_id   = drush_get_option('job_id');
 
 
+  // Unfortunately later versions of Drush use the '--user' argument which
+  // makes it incompatible with how Tripal was using it.  For backwards
+  // compatabiliy we will accept --user with a non numeric value only. The
+  // numeric value should be for Drush. Tripal will instead use the
+  // --username argument for the fture.
+  $user = drush_get_option('user');
+  $uname = drush_get_option('username');
+  if ($user and is_numeric($user)) {
+  }
+  elseif ($user) {
+    print "\nNOTE: Use of the --user argument is deprecated as it conflicts with the --user argument of Drush 7.x. Please now use --username instead.\n\n";
+    $username = $user;
+  }
+  if ($uname) {
+    $username = $uname;
+  }
+
   drush_tripal_core_set_user($username);
   drush_tripal_core_set_user($username);
 
 
   if ($parallel) {
   if ($parallel) {
@@ -321,7 +341,7 @@ function drush_tripal_core_tripal_jobs_launch($username) {
   $job_id = drush_get_option('job_id');
   $job_id = drush_get_option('job_id');
 
 
   drush_tripal_core_set_user($username);
   drush_tripal_core_set_user($username);
-  
+
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
     "continue to work but please consider using the 'trp-run-jobs' command.\n\n");
     "continue to work but please consider using the 'trp-run-jobs' command.\n\n");
 
 
@@ -347,10 +367,27 @@ function drush_tripal_core_tripal_jobs_launch($username) {
  * @ingroup tripal_drush
  * @ingroup tripal_drush
  */
  */
 function drush_tripal_core_trp_rerun_job() {
 function drush_tripal_core_trp_rerun_job() {
-  $username = drush_get_option('user');
+  // Unfortunately later versions of Drush use the '--user' argument which
+  // makes it incompatible with how Tripal was using it.  For backwards
+  // compatabiliy we will accept --user with a non numeric value only. The
+  // numeric value should be for Drush. Tripal will instead use the
+  // --username argument for the fture.
+  $user = drush_get_option('user');
+  $uname = drush_get_option('username');
+  print "USER: '$user', UNAME: '$uname'\n";
+  if ($user and is_numeric($user)) {
+  }
+  elseif ($user) {
+    print "\nNOTE: Use of the --user argument is deprecated as it conflicts with the --user argument of Drush 7.x. Please now use --username instead.\n\n";
+    $username = $user;
+  }
+  if ($uname) {
+    $username = $uname;
+  }
+
   $parallel = drush_get_option('parallel');
   $parallel = drush_get_option('parallel');
   $job_id   = drush_get_option('job_id');
   $job_id   = drush_get_option('job_id');
-  
+
   drush_tripal_core_set_user($username);
   drush_tripal_core_set_user($username);
   $new_job_id = tripal_rerun_job($job_id, FALSE);
   $new_job_id = tripal_rerun_job($job_id, FALSE);
 
 
@@ -377,10 +414,10 @@ function drush_tripal_core_trp_rerun_job() {
  * @ingroup tripal_drush
  * @ingroup tripal_drush
  */
  */
 function drush_tripal_core_tripal_jobs_rerun($username, $job_id) {
 function drush_tripal_core_tripal_jobs_rerun($username, $job_id) {
-  
+
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
       "continue to work but please consider using the 'trp-rerun-job' command.\n\n");
       "continue to work but please consider using the 'trp-rerun-job' command.\n\n");
-  
+
   drush_tripal_core_set_user($username);
   drush_tripal_core_set_user($username);
   $new_job_id = tripal_rerun_job($job_id, FALSE);
   $new_job_id = tripal_rerun_job($job_id, FALSE);
   drush_tripal_core_tripal_jobs_launch($username, $new_job_id);
   drush_tripal_core_tripal_jobs_launch($username, $new_job_id);
@@ -430,7 +467,7 @@ function drush_tripal_core_trp_get_currjob() {
 function drush_tripal_core_tripal_jobs_current() {
 function drush_tripal_core_tripal_jobs_current() {
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
       "continue to work but please consider using the 'trp-get-currjob' command.\n\n");
       "continue to work but please consider using the 'trp-get-currjob' command.\n\n");
-  
+
   drush_tripal_core_trp_get_currjob();
   drush_tripal_core_trp_get_currjob();
 }
 }
 
 
@@ -476,10 +513,10 @@ function drush_tripal_core_trp_refresh_mview() {
  * @ingroup tripal_drush
  * @ingroup tripal_drush
  */
  */
 function drush_tripal_core_tripal_update_mview() {
 function drush_tripal_core_tripal_update_mview() {
-  
+
   $mview_id = drush_get_option('mview_id');
   $mview_id = drush_get_option('mview_id');
   $table_name = drush_get_option('table_name');
   $table_name = drush_get_option('table_name');
-  
+
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
       "continue to work but please consider using the 'trp-refresh-mview' command.\n\n");
       "continue to work but please consider using the 'trp-refresh-mview' command.\n\n");
 
 
@@ -518,7 +555,7 @@ function drush_tripal_core_tripal_update_mview() {
 function drush_tripal_core_tripal_chado_version() {
 function drush_tripal_core_tripal_chado_version() {
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
       "continue to work but please consider using the 'trp-get-cversion' command.\n\n");
       "continue to work but please consider using the 'trp-get-cversion' command.\n\n");
-  
+
   drush_tripal_core_trp_get_cversion();
   drush_tripal_core_trp_get_cversion();
 }
 }
 
 
@@ -562,7 +599,7 @@ function drush_tripal_core_trp_get_table() {
  */
  */
 function drush_tripal_core_tripal_chadotable_desc($table_name) {
 function drush_tripal_core_tripal_chadotable_desc($table_name) {
   $section = drush_get_option('section');
   $section = drush_get_option('section');
-  
+
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
       "continue to work but please consider using the 'trp-get-table' command.\n\n");
       "continue to work but please consider using the 'trp-get-table' command.\n\n");
 
 
@@ -584,7 +621,7 @@ function drush_tripal_core_tripal_chadotable_desc($table_name) {
  */
  */
 function drush_tripal_core_trp_clean_nodes() {
 function drush_tripal_core_trp_clean_nodes() {
   $table = drush_get_option('table');
   $table = drush_get_option('table');
-  
+
   chado_cleanup_orphaned_nodes($table, 0);
   chado_cleanup_orphaned_nodes($table, 0);
 }
 }
 
 

+ 2 - 2
tripal_core/tripal_core.info

@@ -3,7 +3,7 @@ description = Provides support for all Tripal modules and includes the Tripal AP
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 configure = admin/tripal
 configure = admin/tripal
 
 
 stylesheets[all][] = theme/css/tripal.css
 stylesheets[all][] = theme/css/tripal.css
@@ -12,4 +12,4 @@ scripts[]          = theme/js/tripal.js
 dependencies[] = views
 dependencies[] = views
 dependencies[] = path
 dependencies[] = path
 dependencies[] = search
 dependencies[] = search
-dependencies[] = php
+dependencies[] = php

+ 2 - 12
tripal_core/tripal_core.install

@@ -11,18 +11,8 @@
  */
  */
 function tripal_core_install() {
 function tripal_core_install() {
 
 
-  // make the data directory for this module
-  $data_dir = tripal_get_files_dir();
-  if (!file_prepare_directory($data_dir, FILE_CREATE_DIRECTORY)) {
-    $message = "Cannot create directory $data_dir. This module may not " .
-               "behave correctly without this directory.  Please  create " .
-               "the directory manually or fix the problem and reinstall.";
-    drupal_set_message(check_plain($message), 'error');
-    tripal_report_error('tripal_core', TRIPAL_ERROR, $message, array());
-  }
-
-  // the foreign key specification doesn't really add one to the
-  // Drupal schema, it is just used internally, but we want one
+  // The foreign key specification doesn't really add one to the
+  // Drupal schema, it is just used internally, but we want one.
   db_query('
   db_query('
       ALTER TABLE {tripal_custom_tables}
       ALTER TABLE {tripal_custom_tables}
       ADD CONSTRAINT tripal_custom_tables_fk1
       ADD CONSTRAINT tripal_custom_tables_fk1

+ 19 - 1
tripal_core/tripal_core.module

@@ -34,7 +34,7 @@ require_once 'api/tripal_core.files.api.inc';
 require_once 'api/tripal_core.jobs.api.inc';
 require_once 'api/tripal_core.jobs.api.inc';
 require_once 'api/tripal_core.tripal.api.inc';
 require_once 'api/tripal_core.tripal.api.inc';
 require_once 'api/tripal_core.tripal_variables.api.inc';
 require_once 'api/tripal_core.tripal_variables.api.inc';
-
+require_once 'api/tripal_core.d3js.api.inc';
 require_once 'api/tripal_core.DEPRECATED.inc';
 require_once 'api/tripal_core.DEPRECATED.inc';
 
 
 // INCLUDES
 // INCLUDES
@@ -313,6 +313,24 @@ function tripal_core_menu() {
     'access arguments' => array('administer tripal'),
     'access arguments' => array('administer tripal'),
     'type' => MENU_CALLBACK,
     'type' => MENU_CALLBACK,
   );
   );
+  // TODO: complete the code for exporting and importing of MViews.
+  // Need to address security issues of sharing SQL.
+  $items['admin/tripal/schema/mviews/import'] = array(
+    'title' => 'Import MView',
+    'description' => 'Import a materialized view from another Tripal instance.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_mviews_import_form'),
+    'access arguments' => array('administer tripal'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/tripal/schema/mviews/%tblid/export'] = array(
+    'title' => 'Export MView',
+    'description' => 'Export a materialized view for use by another Tripal instance.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_mviews_export_form', 5),
+    'access arguments' => array('administer tripal'),
+    'type' => MENU_CALLBACK,
+  );
 
 
   // Custom Tables
   // Custom Tables
   $items['admin/tripal/schema/custom_tables'] = array(
   $items['admin/tripal/schema/custom_tables'] = array(

+ 3 - 7
tripal_cv/includes/tripal_cv.obo_loader.inc

@@ -151,7 +151,7 @@ function tripal_cv_load_obo_v1_2_id($obo_id, $jobid = NULL) {
     $module = $matches[1];
     $module = $matches[1];
     $path = drupal_realpath(drupal_get_path('module', $module));
     $path = drupal_realpath(drupal_get_path('module', $module));
     $obo->path = preg_replace("/\{.*?\}/", $path, $obo->path);
     $obo->path = preg_replace("/\{.*?\}/", $path, $obo->path);
-  } 
+  }
 
 
   // if the reference is for a remote URL then run the URL processing function
   // if the reference is for a remote URL then run the URL processing function
   if (preg_match("/^http:\/\//", $obo->path) or preg_match("/^ftp:\/\//", $obo->path)) {
   if (preg_match("/^http:\/\//", $obo->path) or preg_match("/^ftp:\/\//", $obo->path)) {
@@ -871,11 +871,10 @@ function tripal_cv_obo_add_synonyms($term, $cvterm) {
           'name' => 'synonym_type',
           'name' => 'synonym_type',
         ),
         ),
       );
       );
-      $options = array('is_duplicate' => 1);
-      $results = chado_select_record('cvterm', array('*'), $values, $options);
+      $syntype = tripal_get_cvterm($values);
 
 
       // if it doesn't exist then add it
       // if it doesn't exist then add it
-      if (!$results) {
+      if (!$syntype) {
         // build a 'term' object so we can add the missing term
         // build a 'term' object so we can add the missing term
         $term = array(
         $term = array(
            'name' => $scope,
            'name' => $scope,
@@ -890,9 +889,6 @@ function tripal_cv_obo_add_synonyms($term, $cvterm) {
           tripal_cv_obo_quiterror("Cannot add synonym type: internal:$scope");
           tripal_cv_obo_quiterror("Cannot add synonym type: internal:$scope");
         }
         }
       }
       }
-      else {
-        $syntype = $results[0];
-      }
 
 
       // make sure the synonym doesn't already exists
       // make sure the synonym doesn't already exists
       $values = array(
       $values = array(

+ 1 - 1
tripal_cv/tripal_cv.info

@@ -3,7 +3,7 @@ description = Supports the Controlled Vocabulary (CV) tables of Chado by providi
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 configure = admin/tripal/chado/tripal_cv
 configure = admin/tripal/chado/tripal_cv
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core

+ 0 - 3
tripal_cv/tripal_cv.install

@@ -49,9 +49,6 @@ function tripal_cv_requirements($phase) {
  */
  */
 function tripal_cv_install() {
 function tripal_cv_install() {
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_cv');
-
   // add the cv_root_mview
   // add the cv_root_mview
   tripal_cv_add_cv_root_mview();
   tripal_cv_add_cv_root_mview();
 
 

+ 354 - 348
tripal_cv/tripal_cv.views_default.inc

@@ -32,51 +32,54 @@ function tripal_cv_views_default_views() {
  */
  */
 function tripal_cv_defaultview_admin_cvs_listing() {
 function tripal_cv_defaultview_admin_cvs_listing() {
 
 
-$view = new view();
-$view->name = 'tripal_cv_admin_cvs';
-$view->description = 'DO NOT DISABLE';
-$view->tag = 'tripal admin';
-$view->base_table = 'cv';
-$view->human_name = 'CVs Admin';
-$view->core = 6;
-$view->api_version = '3.0';
-$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $view = new view();
+  $view->name = 'tripal_cv_admin_cvs';
+  $view->description = 'DO NOT DISABLE';
+  $view->tag = 'tripal admin';
+  $view->base_table = 'cv';
+  $view->human_name = 'CVs Admin';
+  $view->core = 6;
+  $view->api_version = '3.0';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
 
 
-/* Display: Defaults */
-$handler = $view->new_display('default', 'Defaults', 'default');
-$handler->display->display_options['title'] = 'Controlled Vocabularies';
-$handler->display->display_options['use_more_always'] = FALSE;
-$handler->display->display_options['access']['type'] = 'perm';
-$handler->display->display_options['access']['perm'] = 'administer controlled vocabularies';
-$handler->display->display_options['cache']['type'] = 'none';
-$handler->display->display_options['query']['type'] = 'views_query';
-$handler->display->display_options['exposed_form']['type'] = 'basic';
-$handler->display->display_options['pager']['type'] = 'full';
-$handler->display->display_options['pager']['options']['items_per_page'] = '25';
-$handler->display->display_options['pager']['options']['offset'] = '0';
-$handler->display->display_options['pager']['options']['id'] = '0';
-$handler->display->display_options['pager']['options']['quantity'] = '9';
-$handler->display->display_options['style_plugin'] = 'table';
-$handler->display->display_options['style_options']['grouping'] = '';
-$handler->display->display_options['style_options']['columns'] = array(
-  'name' => 'name',
-  'definition' => 'definition',
-  'nothing' => 'nothing',
-);
-$handler->display->display_options['style_options']['default'] = 'name';
-$handler->display->display_options['style_options']['info'] = array(
-  'name' => array(
-    'sortable' => 1,
-    'separator' => '',
-  ),
-  'definition' => array(
-    'sortable' => 0,
-    'separator' => '',
-  ),
-  'nothing' => array(
-    'separator' => '',
-  ),
-);
+  /* Display: Defaults */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->display->display_options['title'] = 'Controlled Vocabularies';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['access']['perm'] = 'administer controlled vocabularies';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of controlled vocabularies that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of vocabularies or to find a specific vocabulary.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '25';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['pager']['options']['id'] = '0';
+  $handler->display->display_options['pager']['options']['quantity'] = '9';
+  $handler->display->display_options['style_plugin'] = 'table';
+  $handler->display->display_options['style_options']['grouping'] = '';
+  $handler->display->display_options['style_options']['columns'] = array(
+    'name' => 'name',
+    'definition' => 'definition',
+    'nothing' => 'nothing',
+  );
+  $handler->display->display_options['style_options']['default'] = 'name';
+  $handler->display->display_options['style_options']['info'] = array(
+    'name' => array(
+      'sortable' => 1,
+      'separator' => '',
+    ),
+    'definition' => array(
+      'sortable' => 0,
+      'separator' => '',
+    ),
+    'nothing' => array(
+      'separator' => '',
+    ),
+  );
 /* Header: Global: Action Links */
 /* Header: Global: Action Links */
   $handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
   $handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
   $handler->display->display_options['header']['action_links_area']['table'] = 'views';
   $handler->display->display_options['header']['action_links_area']['table'] = 'views';
@@ -91,118 +94,118 @@ $handler->display->display_options['style_options']['info'] = array(
     'label-2' => 'Load Ontology',
     'label-2' => 'Load Ontology',
     'path-2' => 'admin/tripal/chado/tripal_cv/obo_loader',
     'path-2' => 'admin/tripal/chado/tripal_cv/obo_loader',
   );
   );
-/* No results behavior: Global: Text area */
-$handler->display->display_options['empty']['text']['id'] = 'area';
-$handler->display->display_options['empty']['text']['table'] = 'views';
-$handler->display->display_options['empty']['text']['field'] = 'area';
-$handler->display->display_options['empty']['text']['content'] = 'No controlled vocabularies match the supplied criteria.';
-$handler->display->display_options['empty']['text']['format'] = '2';
-/* Field: Chado Cv: Cv Id */
-$handler->display->display_options['fields']['cv_id']['id'] = 'cv_id';
-$handler->display->display_options['fields']['cv_id']['table'] = 'cv';
-$handler->display->display_options['fields']['cv_id']['field'] = 'cv_id';
-$handler->display->display_options['fields']['cv_id']['exclude'] = TRUE;
-$handler->display->display_options['fields']['cv_id']['separator'] = '';
-/* Field: Chado Cv: Name */
-$handler->display->display_options['fields']['name']['id'] = 'name';
-$handler->display->display_options['fields']['name']['table'] = 'cv';
-$handler->display->display_options['fields']['name']['field'] = 'name';
-/* Field: Chado Cv: Definition */
-$handler->display->display_options['fields']['definition']['id'] = 'definition';
-$handler->display->display_options['fields']['definition']['table'] = 'cv';
-$handler->display->display_options['fields']['definition']['field'] = 'definition';
-/* Field: Global: Custom text */
-$handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
-$handler->display->display_options['fields']['nothing_1']['table'] = 'views';
-$handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
-$handler->display->display_options['fields']['nothing_1']['label'] = 'Edit Link';
-$handler->display->display_options['fields']['nothing_1']['exclude'] = TRUE;
-$handler->display->display_options['fields']['nothing_1']['alter']['text'] = 'edit';
-$handler->display->display_options['fields']['nothing_1']['alter']['make_link'] = TRUE;
-$handler->display->display_options['fields']['nothing_1']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cv/edit/[cv_id]';
-/* Field: Global: Custom text */
-$handler->display->display_options['fields']['nothing']['id'] = 'nothing';
-$handler->display->display_options['fields']['nothing']['table'] = 'views';
-$handler->display->display_options['fields']['nothing']['field'] = 'nothing';
-$handler->display->display_options['fields']['nothing']['label'] = 'View Terms link';
-$handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
-$handler->display->display_options['fields']['nothing']['alter']['text'] = 'View Terms';
-$handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
-$handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cvterms?cv=[name]';
-$handler->display->display_options['fields']['nothing']['hide_alter_empty'] = TRUE;
-/* Field: Global: Custom text */
-$handler->display->display_options['fields']['nothing_3']['id'] = 'nothing_3';
-$handler->display->display_options['fields']['nothing_3']['table'] = 'views';
-$handler->display->display_options['fields']['nothing_3']['field'] = 'nothing';
-$handler->display->display_options['fields']['nothing_3']['label'] = 'Add term';
-$handler->display->display_options['fields']['nothing_3']['exclude'] = TRUE;
-$handler->display->display_options['fields']['nothing_3']['alter']['text'] = 'Add Term';
-$handler->display->display_options['fields']['nothing_3']['alter']['make_link'] = TRUE;
-$handler->display->display_options['fields']['nothing_3']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cv/[cv_id]/cvterm/add';
-/* Field: Global: Custom text */
-$handler->display->display_options['fields']['nothing_2']['id'] = 'nothing_2';
-$handler->display->display_options['fields']['nothing_2']['table'] = 'views';
-$handler->display->display_options['fields']['nothing_2']['field'] = 'nothing';
-$handler->display->display_options['fields']['nothing_2']['label'] = '';
-$handler->display->display_options['fields']['nothing_2']['alter']['text'] = '[nothing_1]<br />
-  [nothing]   [nothing_3]';
-$handler->display->display_options['fields']['nothing_2']['element_class'] = 'short-column';
-$handler->display->display_options['fields']['nothing_2']['element_label_class'] = 'short-column';
-$handler->display->display_options['fields']['nothing_2']['element_label_colon'] = FALSE;
-/* Sort criterion: Chado Cv: Name */
-$handler->display->display_options['sorts']['name']['id'] = 'name';
-$handler->display->display_options['sorts']['name']['table'] = 'cv';
-$handler->display->display_options['sorts']['name']['field'] = 'name';
-/* Filter criterion: Chado Cv: Name */
-$handler->display->display_options['filters']['name']['id'] = 'name';
-$handler->display->display_options['filters']['name']['table'] = 'cv';
-$handler->display->display_options['filters']['name']['field'] = 'name';
-$handler->display->display_options['filters']['name']['operator'] = 'contains';
-$handler->display->display_options['filters']['name']['group'] = '0';
-$handler->display->display_options['filters']['name']['exposed'] = TRUE;
-$handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
-$handler->display->display_options['filters']['name']['expose']['label'] = 'Name Contains';
-$handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
-$handler->display->display_options['filters']['name']['expose']['identifier'] = 'name';
-$handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
-  2 => '2',
-  1 => 0,
-  3 => 0,
-);
-/* Filter criterion: Chado Cv: Definition */
-$handler->display->display_options['filters']['definition']['id'] = 'definition';
-$handler->display->display_options['filters']['definition']['table'] = 'cv';
-$handler->display->display_options['filters']['definition']['field'] = 'definition';
-$handler->display->display_options['filters']['definition']['operator'] = 'contains';
-$handler->display->display_options['filters']['definition']['group'] = '0';
-$handler->display->display_options['filters']['definition']['exposed'] = TRUE;
-$handler->display->display_options['filters']['definition']['expose']['operator_id'] = 'definition_op';
-$handler->display->display_options['filters']['definition']['expose']['label'] = 'Definition Contains';
-$handler->display->display_options['filters']['definition']['expose']['operator'] = 'definition_op';
-$handler->display->display_options['filters']['definition']['expose']['identifier'] = 'definition';
-$handler->display->display_options['filters']['definition']['expose']['remember_roles'] = array(
-  2 => '2',
-  1 => 0,
-  3 => 0,
-);
+  /* No results behavior: Global: Text area */
+  $handler->display->display_options['empty']['text']['id'] = 'area';
+  $handler->display->display_options['empty']['text']['table'] = 'views';
+  $handler->display->display_options['empty']['text']['field'] = 'area';
+  $handler->display->display_options['empty']['text']['content'] = 'No controlled vocabularies match the supplied criteria.';
+  $handler->display->display_options['empty']['text']['format'] = '2';
+  /* Field: Chado Cv: Cv Id */
+  $handler->display->display_options['fields']['cv_id']['id'] = 'cv_id';
+  $handler->display->display_options['fields']['cv_id']['table'] = 'cv';
+  $handler->display->display_options['fields']['cv_id']['field'] = 'cv_id';
+  $handler->display->display_options['fields']['cv_id']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['cv_id']['separator'] = '';
+  /* Field: Chado Cv: Name */
+  $handler->display->display_options['fields']['name']['id'] = 'name';
+  $handler->display->display_options['fields']['name']['table'] = 'cv';
+  $handler->display->display_options['fields']['name']['field'] = 'name';
+  /* Field: Chado Cv: Definition */
+  $handler->display->display_options['fields']['definition']['id'] = 'definition';
+  $handler->display->display_options['fields']['definition']['table'] = 'cv';
+  $handler->display->display_options['fields']['definition']['field'] = 'definition';
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
+  $handler->display->display_options['fields']['nothing_1']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing_1']['label'] = 'Edit Link';
+  $handler->display->display_options['fields']['nothing_1']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['nothing_1']['alter']['text'] = 'edit';
+  $handler->display->display_options['fields']['nothing_1']['alter']['make_link'] = TRUE;
+  $handler->display->display_options['fields']['nothing_1']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cv/edit/[cv_id]';
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing']['id'] = 'nothing';
+  $handler->display->display_options['fields']['nothing']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing']['label'] = 'View Terms link';
+  $handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['nothing']['alter']['text'] = 'View Terms';
+  $handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
+  $handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cvterms?cv=[name]';
+  $handler->display->display_options['fields']['nothing']['hide_alter_empty'] = TRUE;
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing_3']['id'] = 'nothing_3';
+  $handler->display->display_options['fields']['nothing_3']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing_3']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing_3']['label'] = 'Add term';
+  $handler->display->display_options['fields']['nothing_3']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['nothing_3']['alter']['text'] = 'Add Term';
+  $handler->display->display_options['fields']['nothing_3']['alter']['make_link'] = TRUE;
+  $handler->display->display_options['fields']['nothing_3']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cv/[cv_id]/cvterm/add';
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing_2']['id'] = 'nothing_2';
+  $handler->display->display_options['fields']['nothing_2']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing_2']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing_2']['label'] = '';
+  $handler->display->display_options['fields']['nothing_2']['alter']['text'] = '[nothing_1]<br />
+    [nothing]   [nothing_3]';
+  $handler->display->display_options['fields']['nothing_2']['element_class'] = 'short-column';
+  $handler->display->display_options['fields']['nothing_2']['element_label_class'] = 'short-column';
+  $handler->display->display_options['fields']['nothing_2']['element_label_colon'] = FALSE;
+  /* Sort criterion: Chado Cv: Name */
+  $handler->display->display_options['sorts']['name']['id'] = 'name';
+  $handler->display->display_options['sorts']['name']['table'] = 'cv';
+  $handler->display->display_options['sorts']['name']['field'] = 'name';
+  /* Filter criterion: Chado Cv: Name */
+  $handler->display->display_options['filters']['name']['id'] = 'name';
+  $handler->display->display_options['filters']['name']['table'] = 'cv';
+  $handler->display->display_options['filters']['name']['field'] = 'name';
+  $handler->display->display_options['filters']['name']['operator'] = 'contains';
+  $handler->display->display_options['filters']['name']['group'] = '0';
+  $handler->display->display_options['filters']['name']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
+  $handler->display->display_options['filters']['name']['expose']['label'] = 'Name Contains';
+  $handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
+  $handler->display->display_options['filters']['name']['expose']['identifier'] = 'name';
+  $handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+  /* Filter criterion: Chado Cv: Definition */
+  $handler->display->display_options['filters']['definition']['id'] = 'definition';
+  $handler->display->display_options['filters']['definition']['table'] = 'cv';
+  $handler->display->display_options['filters']['definition']['field'] = 'definition';
+  $handler->display->display_options['filters']['definition']['operator'] = 'contains';
+  $handler->display->display_options['filters']['definition']['group'] = '0';
+  $handler->display->display_options['filters']['definition']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['definition']['expose']['operator_id'] = 'definition_op';
+  $handler->display->display_options['filters']['definition']['expose']['label'] = 'Definition Contains';
+  $handler->display->display_options['filters']['definition']['expose']['operator'] = 'definition_op';
+  $handler->display->display_options['filters']['definition']['expose']['identifier'] = 'definition';
+  $handler->display->display_options['filters']['definition']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
 
 
-  /** MANUALLY ADD since filter handler no exporting correctly */
+  /** MANUALLY ADD since filter handler not exporting correctly */
   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'textfield';
   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'textfield';
   $handler->display->display_options['filters']['name']['expose']['select_multiple'] = FALSE;
   $handler->display->display_options['filters']['name']['expose']['select_multiple'] = FALSE;
   $handler->display->display_options['filters']['name']['expose']['select_optional'] = FALSE;
   $handler->display->display_options['filters']['name']['expose']['select_optional'] = FALSE;
   $handler->display->display_options['filters']['name']['expose']['max_length'] = 40;
   $handler->display->display_options['filters']['name']['expose']['max_length'] = 40;
 
 
-/* Display: Page */
-$handler = $view->new_display('page', 'Page', 'page_1');
-$handler->display->display_options['path'] = 'admin/tripal/chado/tripal_cv/cvs';
-$handler->display->display_options['menu']['type'] = 'default tab';
-$handler->display->display_options['menu']['title'] = 'Vocabularies';
-$handler->display->display_options['menu']['description'] = 'A listing of all controlled vocabularies';
-$handler->display->display_options['menu']['weight'] = '-10';
-$handler->display->display_options['menu']['name'] = 'management';
-$handler->display->display_options['menu']['context'] = 0;
-$handler->display->display_options['menu']['context_only_inline'] = 0;
-$handler->display->display_options['tab_options']['weight'] = '0';
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page_1');
+  $handler->display->display_options['path'] = 'admin/tripal/chado/tripal_cv/cvs';
+  $handler->display->display_options['menu']['type'] = 'default tab';
+  $handler->display->display_options['menu']['title'] = 'Vocabularies';
+  $handler->display->display_options['menu']['description'] = 'A listing of all controlled vocabularies';
+  $handler->display->display_options['menu']['weight'] = '-10';
+  $handler->display->display_options['menu']['name'] = 'management';
+  $handler->display->display_options['menu']['context'] = 0;
+  $handler->display->display_options['menu']['context_only_inline'] = 0;
+  $handler->display->display_options['tab_options']['weight'] = '0';
 
 
 
 
   /** MANUALLY ADD since filter handler no exporting correctly
   /** MANUALLY ADD since filter handler no exporting correctly
@@ -222,62 +225,65 @@ $handler->display->display_options['tab_options']['weight'] = '0';
  */
  */
 function tripal_cv_defaultview_admin_cvterms_listing() {
 function tripal_cv_defaultview_admin_cvterms_listing() {
 
 
-$view = new view();
-$view->name = 'tripal_cv_admin_cvterms';
-$view->description = 'DO NOT DISABLE';
-$view->tag = 'tripal admin';
-$view->base_table = 'cvterm';
-$view->human_name = 'CV Terms Admin';
-$view->core = 0;
-$view->api_version = '3.0';
-$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $view = new view();
+  $view->name = 'tripal_cv_admin_cvterms';
+  $view->description = 'DO NOT DISABLE';
+  $view->tag = 'tripal admin';
+  $view->base_table = 'cvterm';
+  $view->human_name = 'CV Terms Admin';
+  $view->core = 0;
+  $view->api_version = '3.0';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
 
 
-/* Display: Defaults */
-$handler = $view->new_display('default', 'Defaults', 'default');
-$handler->display->display_options['title'] = 'Controlled Vocabulary Terms';
-$handler->display->display_options['use_more_always'] = FALSE;
-$handler->display->display_options['access']['type'] = 'perm';
-$handler->display->display_options['access']['perm'] = 'administer controlled vocabularies';
-$handler->display->display_options['cache']['type'] = 'none';
-$handler->display->display_options['query']['type'] = 'views_query';
-$handler->display->display_options['exposed_form']['type'] = 'basic';
-$handler->display->display_options['pager']['type'] = 'full';
-$handler->display->display_options['pager']['options']['items_per_page'] = '25';
-$handler->display->display_options['pager']['options']['offset'] = '0';
-$handler->display->display_options['pager']['options']['id'] = '0';
-$handler->display->display_options['pager']['options']['quantity'] = '9';
-$handler->display->display_options['style_plugin'] = 'table';
-$handler->display->display_options['style_options']['grouping'] = '';
-$handler->display->display_options['style_options']['columns'] = array(
-  'name_1' => 'name_1',
-  'name' => 'name',
-  'definition' => 'definition',
-  'is_obsolete' => 'is_obsolete',
-  'is_relationshiptype' => 'is_relationshiptype',
-);
-$handler->display->display_options['style_options']['default'] = '-1';
-$handler->display->display_options['style_options']['info'] = array(
-  'name_1' => array(
-    'sortable' => 1,
-    'separator' => '',
-  ),
-  'name' => array(
-    'sortable' => 1,
-    'separator' => '',
-  ),
-  'definition' => array(
-    'sortable' => 0,
-    'separator' => '',
-  ),
-  'is_obsolete' => array(
-    'sortable' => 1,
-    'separator' => '',
-  ),
-  'is_relationshiptype' => array(
-    'sortable' => 1,
-    'separator' => '',
-  ),
-);
+  /* Display: Defaults */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->display->display_options['title'] = 'Controlled Vocabulary Terms';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['access']['perm'] = 'administer controlled vocabularies';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of controlled vocabulary terms that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of terms or to find a specific term.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '25';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['pager']['options']['id'] = '0';
+  $handler->display->display_options['pager']['options']['quantity'] = '9';
+  $handler->display->display_options['style_plugin'] = 'table';
+  $handler->display->display_options['style_options']['grouping'] = '';
+  $handler->display->display_options['style_options']['columns'] = array(
+    'name_1' => 'name_1',
+    'name' => 'name',
+    'definition' => 'definition',
+    'is_obsolete' => 'is_obsolete',
+    'is_relationshiptype' => 'is_relationshiptype',
+  );
+  $handler->display->display_options['style_options']['default'] = '-1';
+  $handler->display->display_options['style_options']['info'] = array(
+    'name_1' => array(
+      'sortable' => 1,
+      'separator' => '',
+    ),
+    'name' => array(
+      'sortable' => 1,
+      'separator' => '',
+    ),
+    'definition' => array(
+      'sortable' => 0,
+      'separator' => '',
+    ),
+    'is_obsolete' => array(
+      'sortable' => 1,
+      'separator' => '',
+    ),
+    'is_relationshiptype' => array(
+      'sortable' => 1,
+      'separator' => '',
+    ),
+  );
 /* Header: Global: Action Links */
 /* Header: Global: Action Links */
   $handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
   $handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
   $handler->display->display_options['header']['action_links_area']['table'] = 'views';
   $handler->display->display_options['header']['action_links_area']['table'] = 'views';
@@ -288,140 +294,140 @@ $handler->display->display_options['style_options']['info'] = array(
     'label-1' => 'Add Term',
     'label-1' => 'Add Term',
     'path-1' => 'admin/tripal/chado/tripal_cv/cvterm/add',
     'path-1' => 'admin/tripal/chado/tripal_cv/cvterm/add',
   );
   );
-/* No results behavior: Global: Text area */
-$handler->display->display_options['empty']['text']['id'] = 'area';
-$handler->display->display_options['empty']['text']['table'] = 'views';
-$handler->display->display_options['empty']['text']['field'] = 'area';
-$handler->display->display_options['empty']['text']['content'] = 'There are no terms associated with the selected controlled vocabulary. Please select a different vocabulary from the list above.';
-$handler->display->display_options['empty']['text']['format'] = '1';
-/* Field: Chado Cv: Cv Id */
-$handler->display->display_options['fields']['cv_id']['id'] = 'cv_id';
-$handler->display->display_options['fields']['cv_id']['table'] = 'cv';
-$handler->display->display_options['fields']['cv_id']['field'] = 'cv_id';
-$handler->display->display_options['fields']['cv_id']['exclude'] = TRUE;
-$handler->display->display_options['fields']['cv_id']['separator'] = '';
-/* Field: Chado Cv: Name */
-$handler->display->display_options['fields']['name_1']['id'] = 'name_1';
-$handler->display->display_options['fields']['name_1']['table'] = 'cv';
-$handler->display->display_options['fields']['name_1']['field'] = 'name';
-$handler->display->display_options['fields']['name_1']['label'] = 'Vocabulary';
-$handler->display->display_options['fields']['name_1']['alter']['make_link'] = TRUE;
-$handler->display->display_options['fields']['name_1']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cvs?name=[name_1]';
-/* Field: Chado Cvterm: Cvterm Id */
-$handler->display->display_options['fields']['cvterm_id']['id'] = 'cvterm_id';
-$handler->display->display_options['fields']['cvterm_id']['table'] = 'cvterm';
-$handler->display->display_options['fields']['cvterm_id']['field'] = 'cvterm_id';
-$handler->display->display_options['fields']['cvterm_id']['exclude'] = TRUE;
-$handler->display->display_options['fields']['cvterm_id']['separator'] = '';
-/* Field: Chado Cvterm: Name */
-$handler->display->display_options['fields']['name']['id'] = 'name';
-$handler->display->display_options['fields']['name']['table'] = 'cvterm';
-$handler->display->display_options['fields']['name']['field'] = 'name';
-/* Field: Chado Cvterm: Definition */
-$handler->display->display_options['fields']['definition']['id'] = 'definition';
-$handler->display->display_options['fields']['definition']['table'] = 'cvterm';
-$handler->display->display_options['fields']['definition']['field'] = 'definition';
-$handler->display->display_options['fields']['definition']['element_class'] = 'wide-column';
-$handler->display->display_options['fields']['definition']['element_label_class'] = 'wide-column';
-/* Field: Chado Cvterm: Is Obsolete */
-$handler->display->display_options['fields']['is_obsolete']['id'] = 'is_obsolete';
-$handler->display->display_options['fields']['is_obsolete']['table'] = 'cvterm';
-$handler->display->display_options['fields']['is_obsolete']['field'] = 'is_obsolete';
-$handler->display->display_options['fields']['is_obsolete']['label'] = 'Obsolete?';
-$handler->display->display_options['fields']['is_obsolete']['alter']['alter_text'] = TRUE;
-$handler->display->display_options['fields']['is_obsolete']['alter']['text'] = 'Yes';
-$handler->display->display_options['fields']['is_obsolete']['element_class'] = 'short-column';
-$handler->display->display_options['fields']['is_obsolete']['element_label_class'] = 'short-column';
-$handler->display->display_options['fields']['is_obsolete']['empty'] = 'No';
-$handler->display->display_options['fields']['is_obsolete']['empty_zero'] = TRUE;
-$handler->display->display_options['fields']['is_obsolete']['separator'] = '';
-/* Field: Chado Cvterm: Is Relationshiptype */
-$handler->display->display_options['fields']['is_relationshiptype']['id'] = 'is_relationshiptype';
-$handler->display->display_options['fields']['is_relationshiptype']['table'] = 'cvterm';
-$handler->display->display_options['fields']['is_relationshiptype']['field'] = 'is_relationshiptype';
-$handler->display->display_options['fields']['is_relationshiptype']['label'] = 'Relation-ship?';
-$handler->display->display_options['fields']['is_relationshiptype']['alter']['alter_text'] = TRUE;
-$handler->display->display_options['fields']['is_relationshiptype']['alter']['text'] = 'Yes';
-$handler->display->display_options['fields']['is_relationshiptype']['element_class'] = 'short-column';
-$handler->display->display_options['fields']['is_relationshiptype']['element_label_class'] = 'short-column';
-$handler->display->display_options['fields']['is_relationshiptype']['empty'] = 'No';
-$handler->display->display_options['fields']['is_relationshiptype']['empty_zero'] = TRUE;
-$handler->display->display_options['fields']['is_relationshiptype']['separator'] = '';
-/* Field: Global: Custom text */
-$handler->display->display_options['fields']['nothing']['id'] = 'nothing';
-$handler->display->display_options['fields']['nothing']['table'] = 'views';
-$handler->display->display_options['fields']['nothing']['field'] = 'nothing';
-$handler->display->display_options['fields']['nothing']['label'] = 'Edit Link';
-$handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
-$handler->display->display_options['fields']['nothing']['alter']['text'] = 'edit';
-$handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
-$handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cv/[cv_id]/cvterm/edit/[cvterm_id]';
-/* Field: Global: Custom text */
-$handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
-$handler->display->display_options['fields']['nothing_1']['table'] = 'views';
-$handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
-$handler->display->display_options['fields']['nothing_1']['label'] = '';
-$handler->display->display_options['fields']['nothing_1']['alter']['text'] = '[nothing]';
-$handler->display->display_options['fields']['nothing_1']['element_class'] = 'short-column';
-$handler->display->display_options['fields']['nothing_1']['element_label_class'] = 'short-column';
-$handler->display->display_options['fields']['nothing_1']['element_label_colon'] = FALSE;
-/* Sort criterion: Chado Cv: Name */
-$handler->display->display_options['sorts']['name']['id'] = 'name';
-$handler->display->display_options['sorts']['name']['table'] = 'cv';
-$handler->display->display_options['sorts']['name']['field'] = 'name';
-/* Sort criterion: Chado Cvterm: Name */
-$handler->display->display_options['sorts']['name_1']['id'] = 'name_1';
-$handler->display->display_options['sorts']['name_1']['table'] = 'cvterm';
-$handler->display->display_options['sorts']['name_1']['field'] = 'name';
-/* Filter criterion: Chado Cv: Name */
-$handler->display->display_options['filters']['name']['id'] = 'name';
-$handler->display->display_options['filters']['name']['table'] = 'cv';
-$handler->display->display_options['filters']['name']['field'] = 'name';
-$handler->display->display_options['filters']['name']['value'] = 'All';
-$handler->display->display_options['filters']['name']['group'] = '0';
-$handler->display->display_options['filters']['name']['exposed'] = TRUE;
-$handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
-$handler->display->display_options['filters']['name']['expose']['label'] = 'Vocabulary';
-$handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
-$handler->display->display_options['filters']['name']['expose']['identifier'] = 'cv';
-$handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
-  2 => '2',
-  1 => 0,
-  3 => 0,
-);
-/* Filter criterion: Chado Cvterm: Name */
-$handler->display->display_options['filters']['name_1']['id'] = 'name_1';
-$handler->display->display_options['filters']['name_1']['table'] = 'cvterm';
-$handler->display->display_options['filters']['name_1']['field'] = 'name';
-$handler->display->display_options['filters']['name_1']['operator'] = 'contains';
-$handler->display->display_options['filters']['name_1']['group'] = '0';
-$handler->display->display_options['filters']['name_1']['exposed'] = TRUE;
-$handler->display->display_options['filters']['name_1']['expose']['operator_id'] = '';
-$handler->display->display_options['filters']['name_1']['expose']['label'] = 'Name Contains';
-$handler->display->display_options['filters']['name_1']['expose']['identifier'] = 'name';
-$handler->display->display_options['filters']['name_1']['expose']['remember_roles'] = array(
-  2 => '2',
-  1 => 0,
-  3 => 0,
-);
-/* Filter criterion: Chado Cvterm: Definition */
-$handler->display->display_options['filters']['definition']['id'] = 'definition';
-$handler->display->display_options['filters']['definition']['table'] = 'cvterm';
-$handler->display->display_options['filters']['definition']['field'] = 'definition';
-$handler->display->display_options['filters']['definition']['operator'] = 'contains';
-$handler->display->display_options['filters']['definition']['group'] = '0';
-$handler->display->display_options['filters']['definition']['exposed'] = TRUE;
-$handler->display->display_options['filters']['definition']['expose']['operator_id'] = 'definition_op';
-$handler->display->display_options['filters']['definition']['expose']['label'] = 'Definition Contains';
-$handler->display->display_options['filters']['definition']['expose']['operator'] = 'definition_op';
-$handler->display->display_options['filters']['definition']['expose']['identifier'] = 'definition';
-$handler->display->display_options['filters']['definition']['expose']['remember_roles'] = array(
-  2 => '2',
-  1 => 0,
-  3 => 0,
-);
+  /* No results behavior: Global: Text area */
+  $handler->display->display_options['empty']['text']['id'] = 'area';
+  $handler->display->display_options['empty']['text']['table'] = 'views';
+  $handler->display->display_options['empty']['text']['field'] = 'area';
+  $handler->display->display_options['empty']['text']['content'] = 'There are no terms associated with the selected controlled vocabulary. Please select a different vocabulary from the list above.';
+  $handler->display->display_options['empty']['text']['format'] = '1';
+  /* Field: Chado Cv: Cv Id */
+  $handler->display->display_options['fields']['cv_id']['id'] = 'cv_id';
+  $handler->display->display_options['fields']['cv_id']['table'] = 'cv';
+  $handler->display->display_options['fields']['cv_id']['field'] = 'cv_id';
+  $handler->display->display_options['fields']['cv_id']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['cv_id']['separator'] = '';
+  /* Field: Chado Cv: Name */
+  $handler->display->display_options['fields']['name_1']['id'] = 'name_1';
+  $handler->display->display_options['fields']['name_1']['table'] = 'cv';
+  $handler->display->display_options['fields']['name_1']['field'] = 'name';
+  $handler->display->display_options['fields']['name_1']['label'] = 'Vocabulary';
+  $handler->display->display_options['fields']['name_1']['alter']['make_link'] = TRUE;
+  $handler->display->display_options['fields']['name_1']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cvs?name=[name_1]';
+  /* Field: Chado Cvterm: Cvterm Id */
+  $handler->display->display_options['fields']['cvterm_id']['id'] = 'cvterm_id';
+  $handler->display->display_options['fields']['cvterm_id']['table'] = 'cvterm';
+  $handler->display->display_options['fields']['cvterm_id']['field'] = 'cvterm_id';
+  $handler->display->display_options['fields']['cvterm_id']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['cvterm_id']['separator'] = '';
+  /* Field: Chado Cvterm: Name */
+  $handler->display->display_options['fields']['name']['id'] = 'name';
+  $handler->display->display_options['fields']['name']['table'] = 'cvterm';
+  $handler->display->display_options['fields']['name']['field'] = 'name';
+  /* Field: Chado Cvterm: Definition */
+  $handler->display->display_options['fields']['definition']['id'] = 'definition';
+  $handler->display->display_options['fields']['definition']['table'] = 'cvterm';
+  $handler->display->display_options['fields']['definition']['field'] = 'definition';
+  $handler->display->display_options['fields']['definition']['element_class'] = 'wide-column';
+  $handler->display->display_options['fields']['definition']['element_label_class'] = 'wide-column';
+  /* Field: Chado Cvterm: Is Obsolete */
+  $handler->display->display_options['fields']['is_obsolete']['id'] = 'is_obsolete';
+  $handler->display->display_options['fields']['is_obsolete']['table'] = 'cvterm';
+  $handler->display->display_options['fields']['is_obsolete']['field'] = 'is_obsolete';
+  $handler->display->display_options['fields']['is_obsolete']['label'] = 'Obsolete?';
+  $handler->display->display_options['fields']['is_obsolete']['alter']['alter_text'] = TRUE;
+  $handler->display->display_options['fields']['is_obsolete']['alter']['text'] = 'Yes';
+  $handler->display->display_options['fields']['is_obsolete']['element_class'] = 'short-column';
+  $handler->display->display_options['fields']['is_obsolete']['element_label_class'] = 'short-column';
+  $handler->display->display_options['fields']['is_obsolete']['empty'] = 'No';
+  $handler->display->display_options['fields']['is_obsolete']['empty_zero'] = TRUE;
+  $handler->display->display_options['fields']['is_obsolete']['separator'] = '';
+  /* Field: Chado Cvterm: Is Relationshiptype */
+  $handler->display->display_options['fields']['is_relationshiptype']['id'] = 'is_relationshiptype';
+  $handler->display->display_options['fields']['is_relationshiptype']['table'] = 'cvterm';
+  $handler->display->display_options['fields']['is_relationshiptype']['field'] = 'is_relationshiptype';
+  $handler->display->display_options['fields']['is_relationshiptype']['label'] = 'Relation-ship?';
+  $handler->display->display_options['fields']['is_relationshiptype']['alter']['alter_text'] = TRUE;
+  $handler->display->display_options['fields']['is_relationshiptype']['alter']['text'] = 'Yes';
+  $handler->display->display_options['fields']['is_relationshiptype']['element_class'] = 'short-column';
+  $handler->display->display_options['fields']['is_relationshiptype']['element_label_class'] = 'short-column';
+  $handler->display->display_options['fields']['is_relationshiptype']['empty'] = 'No';
+  $handler->display->display_options['fields']['is_relationshiptype']['empty_zero'] = TRUE;
+  $handler->display->display_options['fields']['is_relationshiptype']['separator'] = '';
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing']['id'] = 'nothing';
+  $handler->display->display_options['fields']['nothing']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing']['label'] = 'Edit Link';
+  $handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['nothing']['alter']['text'] = 'edit';
+  $handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
+  $handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/chado/tripal_cv/cv/[cv_id]/cvterm/edit/[cvterm_id]';
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
+  $handler->display->display_options['fields']['nothing_1']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing_1']['label'] = '';
+  $handler->display->display_options['fields']['nothing_1']['alter']['text'] = '[nothing]';
+  $handler->display->display_options['fields']['nothing_1']['element_class'] = 'short-column';
+  $handler->display->display_options['fields']['nothing_1']['element_label_class'] = 'short-column';
+  $handler->display->display_options['fields']['nothing_1']['element_label_colon'] = FALSE;
+  /* Sort criterion: Chado Cv: Name */
+  $handler->display->display_options['sorts']['name']['id'] = 'name';
+  $handler->display->display_options['sorts']['name']['table'] = 'cv';
+  $handler->display->display_options['sorts']['name']['field'] = 'name';
+  /* Sort criterion: Chado Cvterm: Name */
+  $handler->display->display_options['sorts']['name_1']['id'] = 'name_1';
+  $handler->display->display_options['sorts']['name_1']['table'] = 'cvterm';
+  $handler->display->display_options['sorts']['name_1']['field'] = 'name';
+  /* Filter criterion: Chado Cv: Name */
+  $handler->display->display_options['filters']['name']['id'] = 'name';
+  $handler->display->display_options['filters']['name']['table'] = 'cv';
+  $handler->display->display_options['filters']['name']['field'] = 'name';
+  $handler->display->display_options['filters']['name']['value'] = 'All';
+  $handler->display->display_options['filters']['name']['group'] = '0';
+  $handler->display->display_options['filters']['name']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
+  $handler->display->display_options['filters']['name']['expose']['label'] = 'Vocabulary';
+  $handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
+  $handler->display->display_options['filters']['name']['expose']['identifier'] = 'cv';
+  $handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+  /* Filter criterion: Chado Cvterm: Name */
+  $handler->display->display_options['filters']['name_1']['id'] = 'name_1';
+  $handler->display->display_options['filters']['name_1']['table'] = 'cvterm';
+  $handler->display->display_options['filters']['name_1']['field'] = 'name';
+  $handler->display->display_options['filters']['name_1']['operator'] = 'contains';
+  $handler->display->display_options['filters']['name_1']['group'] = '0';
+  $handler->display->display_options['filters']['name_1']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['name_1']['expose']['operator_id'] = '';
+  $handler->display->display_options['filters']['name_1']['expose']['label'] = 'Name Contains';
+  $handler->display->display_options['filters']['name_1']['expose']['identifier'] = 'name';
+  $handler->display->display_options['filters']['name_1']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+  /* Filter criterion: Chado Cvterm: Definition */
+  $handler->display->display_options['filters']['definition']['id'] = 'definition';
+  $handler->display->display_options['filters']['definition']['table'] = 'cvterm';
+  $handler->display->display_options['filters']['definition']['field'] = 'definition';
+  $handler->display->display_options['filters']['definition']['operator'] = 'contains';
+  $handler->display->display_options['filters']['definition']['group'] = '0';
+  $handler->display->display_options['filters']['definition']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['definition']['expose']['operator_id'] = 'definition_op';
+  $handler->display->display_options['filters']['definition']['expose']['label'] = 'Definition Contains';
+  $handler->display->display_options['filters']['definition']['expose']['operator'] = 'definition_op';
+  $handler->display->display_options['filters']['definition']['expose']['identifier'] = 'definition';
+  $handler->display->display_options['filters']['definition']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
 
 
-/** MANUALLY ADDED since filter handler no exporting correctly */
+  /** MANUALLY ADDED since filter handler no exporting correctly */
   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'select';
   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'select';
   $handler->display->display_options['filters']['name']['expose']['select_multiple'] = FALSE;
   $handler->display->display_options['filters']['name']['expose']['select_multiple'] = FALSE;
   $handler->display->display_options['filters']['name']['expose']['select_optional'] = TRUE;
   $handler->display->display_options['filters']['name']['expose']['select_optional'] = TRUE;
@@ -432,16 +438,16 @@ $handler->display->display_options['filters']['definition']['expose']['remember_
   $handler->display->display_options['filters']['name_1']['expose']['select_optional'] = FALSE;
   $handler->display->display_options['filters']['name_1']['expose']['select_optional'] = FALSE;
   $handler->display->display_options['filters']['name_1']['expose']['max_length'] = 40;
   $handler->display->display_options['filters']['name_1']['expose']['max_length'] = 40;
 
 
-/* Display: Page */
-$handler = $view->new_display('page', 'Page', 'page_1');
-$handler->display->display_options['path'] = 'admin/tripal/chado/tripal_cv/cvterms';
-$handler->display->display_options['menu']['type'] = 'tab';
-$handler->display->display_options['menu']['title'] = 'Terms';
-$handler->display->display_options['menu']['description'] = 'A listing of a controlled vocabulary terms for a given vocabulary';
-$handler->display->display_options['menu']['weight'] = '-8';
-$handler->display->display_options['menu']['name'] = 'management';
-$handler->display->display_options['menu']['context'] = 0;
-$handler->display->display_options['menu']['context_only_inline'] = 0;
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page_1');
+  $handler->display->display_options['path'] = 'admin/tripal/chado/tripal_cv/cvterms';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'Terms';
+  $handler->display->display_options['menu']['description'] = 'A listing of a controlled vocabulary terms for a given vocabulary';
+  $handler->display->display_options['menu']['weight'] = '-8';
+  $handler->display->display_options['menu']['name'] = 'management';
+  $handler->display->display_options['menu']['context'] = 0;
+  $handler->display->display_options['menu']['context_only_inline'] = 0;
 
 
   /** MANUALLY ADD since filter handler no exporting correctly
   /** MANUALLY ADD since filter handler no exporting correctly
   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'select';
   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'select';

+ 1 - 1
tripal_db/tripal_db.info

@@ -3,7 +3,7 @@ description = Supports the database cross-reference tables of Chado by providing
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 configure = admin/tripal/chado/tripal_db
 configure = admin/tripal/chado/tripal_db
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core

+ 0 - 3
tripal_db/tripal_db.install

@@ -48,9 +48,6 @@ function tripal_db_requirements($phase) {
  */
  */
 function tripal_db_install() {
 function tripal_db_install() {
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_db');
-
 }
 }
 
 
 /**
 /**

+ 8 - 2
tripal_db/tripal_db.views_default.inc

@@ -50,7 +50,10 @@ function tripal_db_defaultview_admin_db_listing() {
   $handler->display->display_options['access']['perm'] = 'access chado_db content';
   $handler->display->display_options['access']['perm'] = 'access chado_db content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of external databases that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of databases or to find a specific database.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '50';
   $handler->display->display_options['pager']['options']['items_per_page'] = '50';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -231,7 +234,10 @@ function tripal_db_defaultview_admin_dbxref_listing() {
   $handler->display->display_options['access']['perm'] = 'administer db cross-references';
   $handler->display->display_options['access']['perm'] = 'administer db cross-references';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of external database references that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of references or to find a specific reference.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '50';
   $handler->display->display_options['pager']['options']['items_per_page'] = '50';
   $handler->display->display_options['style_plugin'] = 'table';
   $handler->display->display_options['style_plugin'] = 'table';

+ 3 - 4
tripal_example/includes/tripal_example.chado_node.inc

@@ -220,7 +220,7 @@ function chado_example_form($node, &$form_state) {
   );
   );
 
 
   $form['description'] = array(
   $form['description'] = array(
-    '#type' => 'textarea',
+    '#type' => 'text_format',
     '#title' => t('Description'),
     '#title' => t('Description'),
     '#required' => TRUE,
     '#required' => TRUE,
     '#default_value' => $description,
     '#default_value' => $description,
@@ -324,7 +324,6 @@ function chado_example_validate($node, $form, &$form_state) {
 
 
   // be sure to always trim text fields
   // be sure to always trim text fields
   $node->uniquename   = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
   $node->uniquename   = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
-  $node->description  = property_exists($node, 'description') ? trim($node->description) : '';
 
 
   // Validating for an update. If the 'nid' property is present in the node then
   // Validating for an update. If the 'nid' property is present in the node then
   // this is an update and validation can be different for updates
   // this is an update and validation can be different for updates
@@ -385,7 +384,7 @@ function chado_example_insert($node) {
 
 
     // be sure to always trim text fields
     // be sure to always trim text fields
     $node->uniquename   = trim($node->uniquename);
     $node->uniquename   = trim($node->uniquename);
-    $node->description  = trim($node->description);
+    $node->description  = trim($node->description['value']);
 
 
     // get the example type record
     // get the example type record
     $type_cv = tripal_get_default_cv('example', 'type_id');
     $type_cv = tripal_get_default_cv('example', 'type_id');
@@ -484,7 +483,7 @@ function chado_example_insert($node) {
 function chado_example_update($node) {
 function chado_example_update($node) {
   // be sure to always trim text fields
   // be sure to always trim text fields
   $node->uniquename   = trim($node->uniquename);
   $node->uniquename   = trim($node->uniquename);
-  $node->description  = trim($node->description);
+  $node->description  = trim($node->description['value']);
 
 
   // use the chado_update_record() function to update the record
   // use the chado_update_record() function to update the record
   $match = array(
   $match = array(

+ 1 - 1
tripal_example/tripal_example.info

@@ -26,7 +26,7 @@ package = Tripal Extensions
 ; Follow these instructions when specifying the version:
 ; Follow these instructions when specifying the version:
 ; https://drupal.org/node/1015226
 ; https://drupal.org/node/1015226
 ;
 ;
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 ;
 ;
 ; Style-sheets containing CSS that should always be available for the
 ; Style-sheets containing CSS that should always be available for the

+ 0 - 9
tripal_example/tripal_example.install

@@ -69,15 +69,6 @@ function tripal_example_requirements($phase) {
  */
  */
 function tripal_example_install() {
 function tripal_example_install() {
 
 
-  // EXPLANATION: If your module will making data publicly available for
-  // download or use by the site you can create the directory using the
-  // tripal_create_files_dir() function. This will create a directory in the
-  // public access directory which will typically be in
-  // sites/default/files/tripal/[module name]/
-
-  // create the module's data directory
-  tripal_create_files_dir('tripal_example');
-
   // EXPLANATION: Here is a good place to add any materialized views, controlled
   // EXPLANATION: Here is a good place to add any materialized views, controlled
   // vocabularies CV, databases or CV terms needed by your module.
   // vocabularies CV, databases or CV terms needed by your module.
   // To keep this module code short, create functions to do each of those tasks
   // To keep this module code short, create functions to do each of those tasks

+ 11 - 5
tripal_example/tripal_example.module

@@ -9,10 +9,11 @@
  */
  */
 
 
 // EXPLANATION: include any files needed for this module. That includes any API
 // EXPLANATION: include any files needed for this module. That includes any API
-// file, the theme file, or include files.
+// file, the theme file, or files with functions for new node types.  Try to
+// include other files only when needed so as to reduce the loading time
+// for the module.
 require('api/tripal_example.api.inc');
 require('api/tripal_example.api.inc');
 require('theme/tripal_example.theme.inc');
 require('theme/tripal_example.theme.inc');
-require('includes/tripal_example.admin.inc');
 require('includes/tripal_example.chado_node.inc');
 require('includes/tripal_example.chado_node.inc');
 
 
 
 
@@ -90,6 +91,11 @@ function tripal_example_menu() {
     'page callback' => 'tripal_example_admin_examples_listing',
     'page callback' => 'tripal_example_admin_examples_listing',
     'access arguments' => array('administer tripal example'),
     'access arguments' => array('administer tripal example'),
     'type' => MENU_NORMAL_ITEM,
     'type' => MENU_NORMAL_ITEM,
+    // We include the file where the 'page callback' function
+    // is located.  This removes the need to include all of the
+    // include files at the top of the module, and speeds
+    // module loading time.
+    'file' => '/includes/tripal_example.admin.inc',
   );
   );
 
 
   // EXPLANATION: all extension modules should provide help documentation to
   // EXPLANATION: all extension modules should provide help documentation to
@@ -107,7 +113,7 @@ function tripal_example_menu() {
     'page arguments' => array('tripal_example_help'),
     'page arguments' => array('tripal_example_help'),
     'access arguments' => array('administer tripal example'),
     'access arguments' => array('administer tripal example'),
     'type' => MENU_LOCAL_TASK,
     'type' => MENU_LOCAL_TASK,
-    'weight' => 10
+    'weight' => 10,
   );
   );
 
 
   // EXPLANATION: all extension modules should provide a configuration page.
   // EXPLANATION: all extension modules should provide a configuration page.
@@ -126,7 +132,7 @@ function tripal_example_menu() {
     'page arguments' => array('tripal_example_admin'),
     'page arguments' => array('tripal_example_admin'),
     'access arguments' => array('administer tripal example'),
     'access arguments' => array('administer tripal example'),
     'type' => MENU_LOCAL_TASK,
     'type' => MENU_LOCAL_TASK,
-    'weight' => 5
+    'weight' => 5,
   );
   );
 
 
   // EXPLANATION: If your module defines a new chado node type and that node
   // EXPLANATION: If your module defines a new chado node type and that node
@@ -141,7 +147,7 @@ function tripal_example_menu() {
     'page arguments' => array('chado_node_sync_form', 'tripal_example', 'chado_example'),
     'page arguments' => array('chado_node_sync_form', 'tripal_example', 'chado_example'),
     'access arguments' => array('administer tripal example'),
     'access arguments' => array('administer tripal example'),
     'type' => MENU_LOCAL_TASK,
     'type' => MENU_LOCAL_TASK,
-    'weight' => 2
+    'weight' => 2,
   );
   );
 
 
   // EXPLANATION: If your module defines a new node type that uses the default
   // EXPLANATION: If your module defines a new node type that uses the default

+ 0 - 53
tripal_feature/api/tripal_feature.schema.api.inc

@@ -1,53 +0,0 @@
-<?php
-/**
- * @file
- * Further describe some of the feature tables to the tripal schema
- */
-
-/**
- * Implements hook_chado_schema_v1_2_tripal_gff_temp()
- * Purpose: To describe the structure of 'tripal_gff_temp' to tripal
- * @see chado_insert_record()
- * @see chado_update_record()
- * @see chado_select_record()
- *
- * @return
- *    An array describing the 'tripal_gff_temp' table
- *
- * @ingroup tripal_chado_v1.2_schema_api
- *
- */
-function tripal_feature_chado_schema_v1_2_tripal_gff_temp() {
-  $schema = array(
-    'table' => 'tripal_gff_temp',
-    'fields' => array(
-      'feature_id' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-      ),
-      'organism_id' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-      ),
-      'uniquename' => array(
-        'type' => 'text',
-        'not null' => TRUE,
-      ),
-      'type_name' => array(
-        'type' => 'varchar',
-        'length' => '1024',
-        'not null' => TRUE,
-      ),
-    ),
-    'indexes' => array(
-      'tripal_gff_temp_idx0' => array('feature_id'),
-      'tripal_gff_temp_idx0' => array('organism_id'),
-      'tripal_gff_temp_idx1' => array('uniquename'),
-    ),
-    'unique keys' => array(
-      'tripal_gff_temp_uq0' => array('feature_id'),
-      'tripal_gff_temp_uq1' => array('uniquename', 'organism_id', 'type_name'),
-    ),
-  );
-  return $schema;
-}

+ 20 - 1
tripal_feature/includes/tripal_feature.admin.inc

@@ -36,6 +36,16 @@ function tripal_feature_admin_feature_view() {
     $output .= '</ul>';
     $output .= '</ul>';
   }
   }
 
 
+  // Add a summary chart.
+  //-----------------------------------
+  $output .= theme('tripal_feature_bar_chart_type_organism_summary');
+  drupal_add_js('
+    Drupal.behaviors.tripalFeature_moveAdminSummaryChart = {
+      attach: function (context, settings) {
+        jQuery("#tripal-feature-admin-summary").insertBefore( jQuery(".view-filters") );
+    }};
+  ', 'inline');
+
   return $output;
   return $output;
 }
 }
 
 
@@ -56,7 +66,7 @@ function tripal_feature_admin() {
     'options' => array(
     'options' => array(
       '[feature.name]' => 'Feature Name Only',
       '[feature.name]' => 'Feature Name Only',
       '[feature.uniquename]' => 'Feature Unique Name Only',
       '[feature.uniquename]' => 'Feature Unique Name Only',
-        // there should always be one options matching the unique constraint.
+      // there should always be one options matching the unique constraint.
       '[feature.name], [feature.uniquename] ([feature.type_id>cvterm.name]) [feature.organism_id>organism.genus] [feature.organism_id>organism.species]' => 'Unique Contraint: Includes the name, uniquename, type and scientific name'
       '[feature.name], [feature.uniquename] ([feature.type_id>cvterm.name]) [feature.organism_id>organism.genus] [feature.organism_id>organism.species]' => 'Unique Contraint: Includes the name, uniquename, type and scientific name'
     ),
     ),
     // the token indicating the unique constraint in the options array
     // the token indicating the unique constraint in the options array
@@ -159,3 +169,12 @@ function tripal_feature_admin_validate($form, &$form_state) {
   }
   }
 
 
 }
 }
+
+/**
+ * USort function for the admin summary chart.
+ * Not meant to be called directly.
+ */
+function tripal_feature_admin_summary_sort($a, $b) {
+  if ($a['total_features'] == $b['total_features']) return 0;
+  return $b['total_features'] - $a['total_features'];
+}

+ 2 - 4
tripal_feature/includes/tripal_feature.chado_node.inc

@@ -599,13 +599,13 @@ function chado_feature_delete($node) {
 
 
   $feature_id  = chado_get_id_from_nid('feature', $node->nid);
   $feature_id  = chado_get_id_from_nid('feature', $node->nid);
 
 
-  // if we don't have a library id for this node then this isn't a node of
+  // If we don't have a feature id for this node then this isn't a node of
   // type chado_library or the entry in the chado_library table was lost.
   // type chado_library or the entry in the chado_library table was lost.
   if (!$feature_id) {
   if (!$feature_id) {
     return;
     return;
   }
   }
 
 
-  // remove the drupal content
+  // Remove the drupal content.
   $sql_del = "DELETE FROM {chado_feature} WHERE nid = :nid AND vid = :vid";
   $sql_del = "DELETE FROM {chado_feature} WHERE nid = :nid AND vid = :vid";
   db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
   db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
   $sql_del = "DELETE FROM {node} WHERE nid = :nid AND vid = :vid";
   $sql_del = "DELETE FROM {node} WHERE nid = :nid AND vid = :vid";
@@ -793,7 +793,6 @@ function tripal_feature_node_presave($node) {
  * @ingroup tripal_feature
  * @ingroup tripal_feature
  */
  */
 function tripal_feature_node_insert($node) {
 function tripal_feature_node_insert($node) {
-
   // set the URL path after inserting.  We do it here because we do not
   // set the URL path after inserting.  We do it here because we do not
   // know the feature_id in the presave
   // know the feature_id in the presave
   switch ($node->type) {
   switch ($node->type) {
@@ -810,7 +809,6 @@ function tripal_feature_node_insert($node) {
 
 
       // Now get the title.
       // Now get the title.
       $node->title = chado_get_node_title($node);
       $node->title = chado_get_node_title($node);
-
       break;
       break;
   }
   }
 }
 }

+ 67 - 109
tripal_feature/includes/tripal_feature.delete.inc

@@ -10,14 +10,6 @@
  * @ingroup tripal_feature
  * @ingroup tripal_feature
  */
  */
 function tripal_feature_delete_form() {
 function tripal_feature_delete_form() {
-  // get the list of organisms
-  $sql = "SELECT * FROM {organism} ORDER BY genus, species";
-  $org_rset = chado_query($sql);
-  $organisms = array();
-  $organisms[''] = '';
-  while ($organism = $org_rset->fetchObject()) {
-    $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
-  }
   $form['desc'] = array(
   $form['desc'] = array(
     '#markup' => t("Use one or more of the following fields to identify sets of features to be deleted."),
     '#markup' => t("Use one or more of the following fields to identify sets of features to be deleted."),
   );
   );
@@ -35,12 +27,15 @@ function tripal_feature_delete_form() {
     '#description' => t('Select this checbox if the names listed in the feature
     '#description' => t('Select this checbox if the names listed in the feature
       names box above are the unique name of the feature rather than the human readable names.'),
       names box above are the unique name of the feature rather than the human readable names.'),
   );
   );
+  $cv = tripal_get_cv(array('name' => 'sequence'));
   $form['seq_type']= array(
   $form['seq_type']= array(
-    '#type' => 'textfield',
-    '#title' => t('Sequence Type'),
-    '#description' => t('Please enter the Sequence Ontology term that describes the features to be deleted. Use in conjunction with an organism or anaylysis.'),
+   '#title'       => t('Feature Type'),
+   '#type'        => 'textfield',
+   '#description' => t("Choose the feature type."),
+   '#autocomplete_path' => "admin/tripal/chado/tripal_cv/cvterm/auto_name/$cv->cv_id",
   );
   );
 
 
+  $organisms = tripal_get_organism_select_options(FALSE);
   $form['organism_id'] = array(
   $form['organism_id'] = array(
    '#title'       => t('Organism'),
    '#title'       => t('Organism'),
    '#type'        => 'select',
    '#type'        => 'select',
@@ -48,23 +43,13 @@ function tripal_feature_delete_form() {
    '#options'     => $organisms,
    '#options'     => $organisms,
   );
   );
 
 
-
-  // get the list of analyses
-  $sql = "SELECT * FROM {analysis} ORDER BY name";
-  $org_rset = chado_query($sql);
-  $analyses = array();
-  $analyses[''] = '';
-  while ($analysis = $org_rset->fetchObject()) {
-    $analyses[$analysis->analysis_id] = "$analysis->name ($analysis->program $analysis->programversion, $analysis->sourcename)";
-  }
-  //  TODO: ADD THIS BACK IN LATER
-  //
-  //   $form['analysis']['analysis_id'] = array (
-  //     '#title'       => t('Analysis'),
-  //     '#type'        => t('select'),
-  //     '#description' => t("Choose the analysis for which associated features will be deleted."),
-  //     '#options'     => $analyses,
-  //   );
+  $analyses = tripal_get_analysis_select_options(FALSE);
+  $form['analysis_id'] = array (
+    '#title'       => t('Analysis'),
+    '#type'        => t('select'),
+    '#description' => t("Choose the analysis for which associated features will be deleted."),
+    '#options'     => $analyses,
+  );
 
 
   $form['button'] = array(
   $form['button'] = array(
     '#type' => 'submit',
     '#type' => 'submit',
@@ -81,30 +66,13 @@ function tripal_feature_delete_form() {
 function tripal_feature_delete_form_validate($form, &$form_state) {
 function tripal_feature_delete_form_validate($form, &$form_state) {
   $organism_id   = $form_state['values']['organism_id'];
   $organism_id   = $form_state['values']['organism_id'];
   $seq_type      = trim($form_state['values']['seq_type']);
   $seq_type      = trim($form_state['values']['seq_type']);
-  //$analysis_id   = $form_state['values']['analysis_id'];
+  $analysis_id   = $form_state['values']['analysis_id'];
   $is_unique     = $form_state['values']['is_unique'];
   $is_unique     = $form_state['values']['is_unique'];
   $feature_names = $form_state['values']['feature_names'];
   $feature_names = $form_state['values']['feature_names'];
 
 
-  if (!$organism_id and !$seq_type and !$feature_names) { // !$anaysis_id and
+  if (!$analysis_id and !$organism_id and !$seq_type and !$feature_names) {
     form_set_error('feature_names', t("Please select at least one option"));
     form_set_error('feature_names', t("Please select at least one option"));
   }
   }
-
-  // check to make sure the types exists
-  if ($seq_type) {
-    $cvtermsql = "
-      SELECT CVT.cvterm_id
-      FROM {cvterm} CVT
-        INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
-        LEFT JOIN {cvtermsynonym} CVTS on CVTS.cvterm_id = CVT.cvterm_id
-      WHERE cv.name = :cvname and (CVT.name = :name or CVTS.synonym = :synonym)
-    ";
-    $cvterm = chado_query($cvtermsql,
-      array(':cvname' => 'sequence', ':name' => $seq_type, ':synonym' => $seq_type))->fetchObject();
-    if (!$cvterm) {
-      form_set_error('seq_type', t("The Sequence Ontology (SO) term selected for the " .
-      "sequence type is not available in the database. Please check spelling or select another."));
-    }
-  }
 }
 }
 
 
 /**
 /**
@@ -117,13 +85,11 @@ function tripal_feature_delete_form_submit($form, &$form_state) {
 
 
   $organism_id   = $form_state['values']['organism_id'];
   $organism_id   = $form_state['values']['organism_id'];
   $seq_type      = trim($form_state['values']['seq_type']);
   $seq_type      = trim($form_state['values']['seq_type']);
-  //$analysis_id   = $form_state['values']['analysis_id'];
+  $analysis_id   = $form_state['values']['analysis_id'];
   $is_unique     = $form_state['values']['is_unique'];
   $is_unique     = $form_state['values']['is_unique'];
   $feature_names = $form_state['values']['feature_names'];
   $feature_names = $form_state['values']['feature_names'];
-  $analysis_id = NULL;
 
 
   $args = array($organism_id, $analysis_id, $seq_type, $is_unique, $feature_names);
   $args = array($organism_id, $analysis_id, $seq_type, $is_unique, $feature_names);
-
   tripal_add_job("Delete features", 'tripal_feature',
   tripal_add_job("Delete features", 'tripal_feature',
     'tripal_feature_delete_features', $args, $user->uid);
     'tripal_feature_delete_features', $args, $user->uid);
 }
 }
@@ -153,21 +119,14 @@ function tripal_feature_delete_features($organism_id, $analysis_id, $seq_type,
   global $user;
   global $user;
   $match = array();
   $match = array();
 
 
-  // Deleting of features will cause a cascade delete on the
-  // featureloc table which in turn will wind up calling create_point
-  // function which is not prefix with the schema, and an error occurs.
-  // Therefore, we set the active database to chado to get around that
-  // problem.
-  $previous_db = chado_set_active('chado');
-  
-  // begin the transaction
+  // Begin the transaction.
   $transaction = db_transaction();
   $transaction = db_transaction();
   print "\nNOTE: Deleting features is performed using a database transaction. \n" .
   print "\nNOTE: Deleting features is performed using a database transaction. \n" .
       "If the load fails or is terminated prematurely then the entire set of \n" .
       "If the load fails or is terminated prematurely then the entire set of \n" .
       "deletions is rolled back and will not be found in the database\n\n";
       "deletions is rolled back and will not be found in the database\n\n";
   try {
   try {
 
 
-    // if feature names have been provided then handle that separately
+    // If feature names have been provided then handle those
     if ($feature_names) {
     if ($feature_names) {
       $names = preg_split('/\s+/', $feature_names);
       $names = preg_split('/\s+/', $feature_names);
       if (sizeof($names) == 1) {
       if (sizeof($names) == 1) {
@@ -181,33 +140,59 @@ function tripal_feature_delete_features($organism_id, $analysis_id, $seq_type,
       }
       }
       $num_deletes = chado_select_record('feature', array('count(*) as cnt'), $match);
       $num_deletes = chado_select_record('feature', array('count(*) as cnt'), $match);
       print "Deleting " . $num_deletes[0]->cnt . " features\n";
       print "Deleting " . $num_deletes[0]->cnt . " features\n";
-      
+
       chado_delete_record('feature', $match);
       chado_delete_record('feature', $match);
+      return;
+    }
+
+    // Now handle the combintation of all other inputs.
+    $args = array();
+    $sql = "";
+    $join = '';
+    $where = '';
+    if ($analysis_id) {
+      $join .= 'INNER JOIN {analysisfeature} AF on F.feature_id = AF.feature_id ';
+      $join .= 'INNER JOIN {analysis} A on A.analysis_id = AF.analysis_id ';
+      $where .= 'AND A.analysis_id = :analysis_id ';
+      $args[':analysis_id'] = $analysis_id;
     }
     }
-  
-    // if the user has provided an analysis_id then handle that separately
-    elseif ($analysis_id) {
-      tripal_feature_delete_by_analysis();
+    if ($organism_id) {
+      $where .= 'AND F.organism_id = :organism_id ';
+      $args[':organism_id'] = $organism_id;
     }
     }
-    else {
-  
-      if ($organism_id) {
-        $match['organism_id'] = $organism_id;
-      }
-      if ($seq_type) {
-        $match['type_id'] = array(
-          'name' => $seq_type,
-          'cv_id' => array(
-            'name' => 'sequence'
-          ),
-        );
-      }
-      $num_deletes = chado_select_record('feature', array('count(*) as cnt'), $match);
-      print "Deleting " . $num_deletes[0]->cnt . " features\n";
-      chado_delete_record('feature', $match);
+    if ($seq_type) {
+      $join .= 'INNER JOIN {cvterm} CVT ON CVT.cvterm_id = F.type_id';
+      $where .= 'AND CVT.name = :type_name';
+      $args[':type_name'] = $seq_type;
     }
     }
-  
-    print "Removing orphaned feature pages\n";
+
+    // Do not perform a delete if we have no additions to the where clause
+    // otherwise all features will be deleted and this is probably not what
+    // is wanted.
+    if (!$where) {
+      throw new Exception('Cannot delete features as no filters are available');
+    }
+    // First, count the number of records to be deleted
+    $sql = "
+      SELECT count(F.feature_id)
+      FROM {feature} F
+        $join
+      WHERE 1=1 $where
+    ";
+    $num_deleted = chado_query($sql, $args)->fetchField();
+    // Second, delete the records.
+    $sql = "
+      DELETE FROM {feature} WHERE feature_id IN (
+        SELECT F.feature_id
+        FROM {feature} F
+          $join
+        WHERE 1=1 $where
+      )
+    ";
+    chado_query($sql, $args);
+    print "Deletiong completed successfully. Deleted $num_deleted feature(s).\n";
+
+    print "Now removing orphaned feature pages\n";
     chado_cleanup_orphaned_nodes('feature');
     chado_cleanup_orphaned_nodes('feature');
   }
   }
   catch (Exception $e) {
   catch (Exception $e) {
@@ -217,33 +202,6 @@ function tripal_feature_delete_features($organism_id, $analysis_id, $seq_type,
     watchdog_exception('tripal_feature', $e);
     watchdog_exception('tripal_feature', $e);
     return 0;
     return 0;
   }
   }
-  chado_set_active($previous_db);
   print "\nDone\n";
   print "\nDone\n";
 }
 }
 
 
-/**
- * Function to delete features based on an analysis passed in. This has not yet been
- * implemented in the form
- *
- * @todo: Implement this functionality and then add back in the form field
- *
- * @param $organism_id
- *   (Optional) The organism_id of the features to delete
- * @param $analysis_id
- *   (Optional) The analysis_id of the features to delete
- * @param $seq_type
- *   (Optional) The cvterm.name of the feature types to delete
- * @param $is_unique
- *   (Optional) A Boolean stating whether the names are unique (ie: feature.uniquename)
- *   or not (ie: feature.name)
- * @param $feature_names
- *   (Optional) A space separated list of the names of features to delete
- * @param $job
- *   The tripal_job id
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_delete_by_analysis($organism_id, $analysis_id, $seq_type,
-  $is_unique, $feature_names, $job = NULL) {
-
-}

+ 71 - 72
tripal_feature/includes/tripal_feature.fasta_loader.inc

@@ -41,10 +41,8 @@ function tripal_feature_fasta_load_form() {
   );
   );
 
 
   // get the sequence ontology CV ID
   // get the sequence ontology CV ID
-  $values = array('name' => 'sequence'
-  );
-  $cv = chado_select_record('cv', array('cv_id'
-  ), $values);
+  $values = array('name' => 'sequence');
+  $cv = chado_select_record('cv', array('cv_id'), $values);
   $cv_id = $cv[0]->cv_id;
   $cv_id = $cv[0]->cv_id;
 
 
   $form['seqtype'] = array('#type' => 'textfield','#title' => t('Sequence Type'),
   $form['seqtype'] = array('#type' => 'textfield','#title' => t('Sequence Type'),
@@ -123,14 +121,18 @@ function tripal_feature_fasta_load_form() {
     '#description' => t('Enter the regular expression that will extract the
     '#description' => t('Enter the regular expression that will extract the
        feature name from the FASTA definition line. For example, for a
        feature name from the FASTA definition line. For example, for a
        defintion line with a name and unique name separated by a bar \'|\' (>seqname|uniquename),
        defintion line with a name and unique name separated by a bar \'|\' (>seqname|uniquename),
-       the regular expression for the name would be, "^(.*?)\|.*$".')
+       the regular expression for the name would be, "^(.*?)\|.*$".  All FASTA
+       definition lines begin with the ">" symbol.  You do not need to incldue
+       this symbol in your regular expression.')
   );
   );
   $form['advanced']['re_uname'] = array('#type' => 'textfield',
   $form['advanced']['re_uname'] = array('#type' => 'textfield',
     '#title' => t('Regular expression for the unique name'),'#required' => FALSE,
     '#title' => t('Regular expression for the unique name'),'#required' => FALSE,
     '#description' => t('Enter the regular expression that will extract the
     '#description' => t('Enter the regular expression that will extract the
        feature name from the FASTA definition line. For example, for a
        feature name from the FASTA definition line. For example, for a
        defintion line with a name and unique name separated by a bar \'|\' (>seqname|uniquename),
        defintion line with a name and unique name separated by a bar \'|\' (>seqname|uniquename),
-       the regular expression for the unique name would be "^.*?\|(.*)$").')
+       the regular expression for the unique name would be "^.*?\|(.*)$").  All FASTA
+       definition lines begin with the ">" symbol.  You do not need to incldue
+       this symbol in your regular expression.')
   );
   );
 
 
   // Advanced database cross-reference optoins
   // Advanced database cross-reference optoins
@@ -163,7 +165,7 @@ function tripal_feature_fasta_load_form() {
   $rels = array();
   $rels = array();
   $rels[''] = '';
   $rels[''] = '';
   $rels['part_of'] = 'part of';
   $rels['part_of'] = 'part of';
-  $rels['derives_from'] = 'produced by';
+  $rels['derives_from'] = 'produced by (derives from)';
 
 
   // Advanced references options
   // Advanced references options
   $form['advanced']['relationship']['rel_type'] = array('#title' => t('Relationship Type'),
   $form['advanced']['relationship']['rel_type'] = array('#title' => t('Relationship Type'),
@@ -400,21 +402,16 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
         LEFT JOIN {cvtermsynonym} CVTS on CVTS.cvterm_id = CVT.cvterm_id
         LEFT JOIN {cvtermsynonym} CVTS on CVTS.cvterm_id = CVT.cvterm_id
       WHERE cv.name = :cvname and (CVT.name = :name or CVTS.synonym = :synonym)
       WHERE cv.name = :cvname and (CVT.name = :name or CVTS.synonym = :synonym)
     ";
     ";
-    $cvterm = chado_query($cvtermsql, array(':cvname' => 'sequence',':name' => $type,
-      ':synonym' => $type
-    ))->fetchObject();
+    $cvterm = chado_query($cvtermsql, array(':cvname' => 'sequence',':name' => $type,':synonym' => $type))->fetchObject();
     if (!$cvterm) {
     if (!$cvterm) {
-      tripal_report_error("T_fasta_loader", TRIPAL_ERROR, "Cannot find the term type: '%type'", array(
-        '%type' => $type
-      ));
+      tripal_report_error("T_fasta_loader", TRIPAL_ERROR,
+        "Cannot find the term type: '%type'", array('%type' => $type));
       return 0;
       return 0;
     }
     }
 
 
     // Second, if there is a parent type then get that.
     // Second, if there is a parent type then get that.
     if ($parent_type) {
     if ($parent_type) {
-      $parentcvterm = chado_query($cvtermsql, array(':cvname' => 'sequence',
-        ':name' => $parent_type,':synonym' => $parent_type
-      ))->fetchObject();
+      $parentcvterm = chado_query($cvtermsql, array(':cvname' => 'sequence', ':name' => $parent_type,':synonym' => $parent_type))->fetchObject();
       if (!$parentcvterm) {
       if (!$parentcvterm) {
         tripal_report_error("T_fasta_loader", TRIPAL_ERROR, "Cannot find the paretne term type: '%type'", array(
         tripal_report_error("T_fasta_loader", TRIPAL_ERROR, "Cannot find the paretne term type: '%type'", array(
           '%type' => $parentcvterm
           '%type' => $parentcvterm
@@ -425,9 +422,7 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
 
 
     // Third, if there is a relationship type then get that.
     // Third, if there is a relationship type then get that.
     if ($rel_type) {
     if ($rel_type) {
-      $relcvterm = chado_query($cvtermsql, array(':cvname' => 'sequence',':name' => $rel_type,
-        ':synonym' => $rel_type
-      ))->fetchObject();
+      $relcvterm = chado_query($cvtermsql, array(':cvname' => 'sequence',':name' => $rel_type,':synonym' => $rel_type))->fetchObject();
       if (!$relcvterm) {
       if (!$relcvterm) {
         tripal_report_error("T_fasta_loader", TRIPAL_ERROR, "Cannot find the relationship term type: '%type'", array(
         tripal_report_error("T_fasta_loader", TRIPAL_ERROR, "Cannot find the relationship term type: '%type'", array(
           '%type' => $relcvterm
           '%type' => $relcvterm
@@ -498,8 +493,7 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
           if (preg_match("/^\s*(.*?)[\s\|].*$/", $defline, $matches)) {
           if (preg_match("/^\s*(.*?)[\s\|].*$/", $defline, $matches)) {
             if (strlen($matches[1]) > $feature_tbl['fields']['name']['length']) {
             if (strlen($matches[1]) > $feature_tbl['fields']['name']['length']) {
               tripal_report_error('trp-fasta', "WARNING: Regular expression retrieves a feature name too long for the feature name. Line %line.", array(
               tripal_report_error('trp-fasta', "WARNING: Regular expression retrieves a feature name too long for the feature name. Line %line.", array(
-                '%line' => $i
-              ), 'error');
+                '%line' => $i), 'error');
             }
             }
             else {
             else {
               $name = trim($matches[1]);
               $name = trim($matches[1]);
@@ -507,8 +501,7 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
           }
           }
           else {
           else {
             tripal_report_error('trp-fasta', "ERROR: Cannot find a feature name. Line %line.", array(
             tripal_report_error('trp-fasta', "ERROR: Cannot find a feature name. Line %line.", array(
-              '%line' => $i
-            ), 'error');
+              '%line' => $i), 'error');
           }
           }
         }
         }
 
 
@@ -516,8 +509,7 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
         if ($re_uname) {
         if ($re_uname) {
           if (!preg_match("/$re_uname/", $defline, $matches)) {
           if (!preg_match("/$re_uname/", $defline, $matches)) {
             tripal_report_error('trp-fasta', "ERROR: Regular expression for the feature unique name finds nothing. Line %line.", array(
             tripal_report_error('trp-fasta', "ERROR: Regular expression for the feature unique name finds nothing. Line %line.", array(
-              '%line' => $i
-            ), 'error');
+              '%line' => $i), 'error');
           }
           }
           $uname = trim($matches[1]);
           $uname = trim($matches[1]);
         }
         }
@@ -530,8 +522,7 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
           }
           }
           else {
           else {
             tripal_report_error('trp-fasta', "ERROR: Cannot find a feature unique name. Line %line.", array(
             tripal_report_error('trp-fasta', "ERROR: Cannot find a feature unique name. Line %line.", array(
-              '%line' => $i
-            ), 'error');
+              '%line' => $i), 'error');
           }
           }
         }
         }
 
 
@@ -551,8 +542,12 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type, $re_name, $re_un
         $subject = trim($matches[1]);
         $subject = trim($matches[1]);
 
 
         // Add the details to the sequence.
         // Add the details to the sequence.
-        $seqs[$num_seqs] = array('name' => $name,'uname' => $uname,'accession' => $accession,
-          'subject' => $subject,'seq_start' => ftell($fh)
+        $seqs[$num_seqs] = array(
+          'name' => $name,
+          'uname' => $uname,
+          'accession' => $accession,
+          'subject' => $subject,
+          'seq_start' => ftell($fh)
         );
         );
         $set_start = TRUE;
         $set_start = TRUE;
         // If this isn't the first sequence, then we want to specify where
         // If this isn't the first sequence, then we want to specify where
@@ -634,9 +629,7 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
     ), $values);
     ), $values);
     if (count($results) > 1) {
     if (count($results) > 1) {
       tripal_report_error('T_fasta_loader', "Multiple features exist with the name '%name' of type
       tripal_report_error('T_fasta_loader', "Multiple features exist with the name '%name' of type
-               '%type' for the organism.  skipping", array(
-        '%name' => $name,'%type' => $type
-      ));
+               '%type' for the organism.  skipping", array('%name' => $name,'%type' => $type));
       return 0;
       return 0;
     }
     }
     if (count($results) == 1) {
     if (count($results) == 1) {
@@ -646,16 +639,16 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
 
 
   // Check if this feature already exists if the match_type is 'Unique Name'.
   // Check if this feature already exists if the match_type is 'Unique Name'.
   if (strcmp($match_type, 'Unique name') == 0) {
   if (strcmp($match_type, 'Unique name') == 0) {
-    $values = array('organism_id' => $organism_id,'uniquename' => $uname,
+    $values = array(
+      'organism_id' => $organism_id,
+      'uniquename' => $uname,
       'type_id' => $cvterm->cvterm_id
       'type_id' => $cvterm->cvterm_id
     );
     );
 
 
-    $results = chado_select_record('feature', array('feature_id'
-    ), $values);
+    $results = chado_select_record('feature', array('feature_id'), $values);
     if (count($results) > 1) {
     if (count($results) > 1) {
       tripal_report_error('T_fasta_loader', TRIPAL_WARNING, "Multiple features exist with the name '%name' of type '%type' for the organism.  skipping", array(
       tripal_report_error('T_fasta_loader', TRIPAL_WARNING, "Multiple features exist with the name '%name' of type '%type' for the organism.  skipping", array(
-        '%name' => $name,'%type' => $type
-      ));
+        '%name' => $name,'%type' => $type));
       return 0;
       return 0;
     }
     }
     if (count($results) == 1) {
     if (count($results) == 1) {
@@ -683,31 +676,33 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
     }
     }
 
 
     // Insert the feature record.
     // Insert the feature record.
-    $values = array('organism_id' => $organism_id,'name' => $name,'uniquename' => $uname,
+    $values = array(
+      'organism_id' => $organism_id,
+      'name' => $name,
+      'uniquename' => $uname,
       'type_id' => $cvterm->cvterm_id
       'type_id' => $cvterm->cvterm_id
     );
     );
     $success = chado_insert_record('feature', $values);
     $success = chado_insert_record('feature', $values);
     if (!$success) {
     if (!$success) {
       tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to insert feature '%name (%uname)'", array(
       tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to insert feature '%name (%uname)'", array(
-        '%name' => $name,'%uname' => $numane
-      ));
+        '%name' => $name,'%uname' => $numane));
       return 0;
       return 0;
     }
     }
 
 
     // now get the feature we just inserted
     // now get the feature we just inserted
-    $values = array('organism_id' => $organism_id,'uniquename' => $uname,
+    $values = array(
+      'organism_id' => $organism_id,
+      'uniquename' => $uname,
       'type_id' => $cvterm->cvterm_id
       'type_id' => $cvterm->cvterm_id
     );
     );
-    $results = chado_select_record('feature', array('feature_id'
-    ), $values);
+    $results = chado_select_record('feature', array('feature_id'), $values);
     if (count($results) == 1) {
     if (count($results) == 1) {
       $inserted = 1;
       $inserted = 1;
       $feature = $results[0];
       $feature = $results[0];
     }
     }
     else {
     else {
       tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to retreive newly inserted feature '%name (%uname)'", array(
       tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to retreive newly inserted feature '%name (%uname)'", array(
-        '%name' => $name,'%uname' => $numane
-      ));
+        '%name' => $name,'%uname' => $numane));
       return 0;
       return 0;
     }
     }
 
 
@@ -719,8 +714,7 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
   if (!$feature and (strcmp($method, 'Update only') == 0 or
   if (!$feature and (strcmp($method, 'Update only') == 0 or
      drupal_strcmp($method, 'Insert and update') == 0)) {
      drupal_strcmp($method, 'Insert and update') == 0)) {
     tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to find feature '%name' ('%uname') while matching on " .
     tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to find feature '%name' ('%uname') while matching on " .
-     drupal_strtolower($match_type), array('%name' => $name,'%uname' => $uname
-    ));
+      drupal_strtolower($match_type), array('%name' => $name,'%uname' => $uname));
     return 0;
     return 0;
   }
   }
 
 
@@ -739,7 +733,9 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
         // First check to make sure that by changing the unique name of this
         // First check to make sure that by changing the unique name of this
         // feature that we won't conflict with another existing feature of
         // feature that we won't conflict with another existing feature of
         // the same name
         // the same name
-        $values = array('organism_id' => $organism_id,'uniquename' => $uname,
+        $values = array(
+          'organism_id' => $organism_id,
+          'uniquename' => $uname,
           'type_id' => $cvterm->cvterm_id
           'type_id' => $cvterm->cvterm_id
         );
         );
         $results = chado_select_record('feature', array('feature_id'
         $results = chado_select_record('feature', array('feature_id'
@@ -753,9 +749,10 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
         }
         }
 
 
         // the changes to the uniquename don't conflict so proceed with the update
         // the changes to the uniquename don't conflict so proceed with the update
-        $values = array('uniquename' => $uname
-        );
-        $match = array('name' => $name,'organism_id' => $organism_id,
+        $values = array('uniquename' => $uname);
+        $match = array(
+          'name' => $name,
+          'organism_id' => $organism_id,
           'type_id' => $cvterm->cvterm_id
           'type_id' => $cvterm->cvterm_id
         );
         );
 
 
@@ -776,9 +773,10 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
       // we want to update the name.
       // we want to update the name.
       $values = array();
       $values = array();
       if ($name) {
       if ($name) {
-        $values = array('name' => $name
-        );
-        $match = array('uniquename' => $uname,'organism_id' => $organism_id,
+        $values = array('name' => $name);
+        $match = array(
+          'uniquename' => $uname,
+          'organism_id' => $organism_id,
           'type_id' => $cvterm->cvterm_id
           'type_id' => $cvterm->cvterm_id
         );
         );
         $success = chado_update_record('feature', $match, $values);
         $success = chado_update_record('feature', $match, $values);
@@ -798,10 +796,11 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
   // add in the analysis link
   // add in the analysis link
   if ($analysis_id) {
   if ($analysis_id) {
     // if the association doens't alredy exist then add one
     // if the association doens't alredy exist then add one
-    $values = array('analysis_id' => $analysis_id,'feature_id' => $feature->feature_id
+    $values = array(
+      'analysis_id' => $analysis_id,
+      'feature_id' => $feature->feature_id
     );
     );
-    $results = chado_select_record('analysisfeature', array('analysisfeature_id'
-    ), $values);
+    $results = chado_select_record('analysisfeature', array('analysisfeature_id'), $values);
     if (count($results) == 0) {
     if (count($results) == 0) {
       $success = chado_insert_record('analysisfeature', $values);
       $success = chado_insert_record('analysisfeature', $values);
       if (!$success) {
       if (!$success) {
@@ -816,28 +815,26 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
   // now add the database cross reference
   // now add the database cross reference
   if ($db_id) {
   if ($db_id) {
     // check to see if this accession reference exists, if not add it
     // check to see if this accession reference exists, if not add it
-    $values = array('db_id' => $db_id,'accession' => $accession
+    $values = array(
+      'db_id' => $db_id,
+      'accession' => $accession
     );
     );
-    $results = chado_select_record('dbxref', array('dbxref_id'
-    ), $values);
+    $results = chado_select_record('dbxref', array('dbxref_id'), $values);
     // if the accession doesn't exist then add it
     // if the accession doesn't exist then add it
     if (count($results) == 0) {
     if (count($results) == 0) {
       $results = chado_insert_record('dbxref', $values);
       $results = chado_insert_record('dbxref', $values);
       if (!$results) {
       if (!$results) {
         tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to add database accession '%accession'", array(
         tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to add database accession '%accession'", array(
-          '%accession' => $accession
-        ));
+          '%accession' => $accession));
         return 0;
         return 0;
       }
       }
-      $results = chado_select_record('dbxref', array('dbxref_id'
-      ), $values);
+      $results = chado_select_record('dbxref', array('dbxref_id'), $values);
       if (count($results) == 1) {
       if (count($results) == 1) {
         $dbxref = $results[0];
         $dbxref = $results[0];
       }
       }
       else {
       else {
         tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to retreive newly inserted dbxref '%name (%uname)'", array(
         tripal_report_error('T_fasta_loader', TRIPAL_ERROR, "Failed to retreive newly inserted dbxref '%name (%uname)'", array(
-          '%name' => $name,'%uname' => $numane
-        ));
+          '%name' => $name,'%uname' => $numane));
         return 0;
         return 0;
       }
       }
     }
     }
@@ -846,10 +843,11 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
     }
     }
 
 
     // check to see if the feature dbxref record exists if not, then add it
     // check to see if the feature dbxref record exists if not, then add it
-    $values = array('feature_id' => $feature->feature_id,'dbxref_id' => $dbxref->dbxref_id
+    $values = array(
+      'feature_id' => $feature->feature_id,
+      'dbxref_id' => $dbxref->dbxref_id
     );
     );
-    $results = chado_select_record('feature_dbxref', array('feature_dbxref_id'
-    ), $values);
+    $results = chado_select_record('feature_dbxref', array('feature_dbxref_id'), $values);
     if (count($results) == 0) {
     if (count($results) == 0) {
       $success = chado_insert_record('feature_dbxref', $values);
       $success = chado_insert_record('feature_dbxref', $values);
       if (!$success) {
       if (!$success) {
@@ -878,11 +876,12 @@ function tripal_feature_load_fasta_feature($fh, $name, $uname, $db_id, $accessio
     $parent_feature = $results[0];
     $parent_feature = $results[0];
 
 
     // check to see if the relationship already exists if not then add it
     // check to see if the relationship already exists if not then add it
-    $values = array('subject_id' => $feature->feature_id,'object_id' => $parent_feature->feature_id,
+    $values = array(
+      'subject_id' => $feature->feature_id,
+      'object_id' => $parent_feature->feature_id,
       'type_id' => $relcvterm->cvterm_id
       'type_id' => $relcvterm->cvterm_id
     );
     );
-    $results = chado_select_record('feature_relationship', array('feature_relationship_id'
-    ), $values);
+    $results = chado_select_record('feature_relationship', array('feature_relationship_id'), $values);
     if (count($results) == 0) {
     if (count($results) == 0) {
       $success = chado_insert_record('feature_relationship', $values);
       $success = chado_insert_record('feature_relationship', $values);
       if (!$success) {
       if (!$success) {

+ 267 - 138
tripal_feature/includes/tripal_feature.gff_loader.inc

@@ -125,20 +125,26 @@ function tripal_feature_gff3_load_form() {
                          database will not be altered.'),
                          database will not be altered.'),
     '#default_value' => 1,
     '#default_value' => 1,
   );
   );
-  $form['import_options']['refresh']= array(
-    '#type' => 'checkbox',
-    '#title' => t('Import all and replace'),
-    '#required' => FALSE,
-    '#description' => t('Existing features will be updated and feature properties not
-                         present in the GFF file will be removed.'),
-  );
-  $form['import_options']['remove']= array(
-    '#type' => 'checkbox',
-    '#title' => t('Delete features'),
-    '#required' => FALSE,
-    '#description' => t('Features present in the GFF file that exist in the database
-                         will be removed rather than imported'),
-  );
+// SPF: there are bugs in refreshing and removing features.  The bugs arise
+//      if a feature in the GFF does not have a uniquename. GenSAS will auto
+//      generate this uniquename and it will not be the same as a previous
+//      load because it uses the date.  This causes orphaned CDS/exons, UTRs
+//      to be left behind during a delete or refresh.  So, the short term
+//      fix is to remove these options.
+//   $form['import_options']['refresh']= array(
+//     '#type' => 'checkbox',
+//     '#title' => t('Import all and replace'),
+//     '#required' => FALSE,
+//     '#description' => t('Existing features will be updated and feature properties not
+//                          present in the GFF file will be removed.'),
+//   );
+//   $form['import_options']['remove']= array(
+//     '#type' => 'checkbox',
+//     '#title' => t('Delete features'),
+//     '#required' => FALSE,
+//     '#description' => t('Features present in the GFF file that exist in the database
+//                          will be removed rather than imported'),
+//   );
   $form['import_options']['create_organism']= array(
   $form['import_options']['create_organism']= array(
     '#type' => 'checkbox',
     '#type' => 'checkbox',
     '#title' => t('Create organism'),
     '#title' => t('Create organism'),
@@ -218,8 +224,8 @@ function tripal_feature_gff3_load_form_validate($form, &$form_state) {
   $create_organism = $form_state['values']['create_organism'];
   $create_organism = $form_state['values']['create_organism'];
   $add_only = $form_state['values']['add_only'];
   $add_only = $form_state['values']['add_only'];
   $update   = $form_state['values']['update'];
   $update   = $form_state['values']['update'];
-  $refresh  = $form_state['values']['refresh'];
-  $remove   = $form_state['values']['remove'];
+  $refresh  = 0; //$form_state['values']['refresh'];
+  $remove   = 0; //$form_state['values']['remove'];
   $use_transaction   = $form_state['values']['use_transaction'];
   $use_transaction   = $form_state['values']['use_transaction'];
   $line_number   = trim($form_state['values']['line_number']);
   $line_number   = trim($form_state['values']['line_number']);
   $landmark_type   = trim($form_state['values']['landmark_type']);
   $landmark_type   = trim($form_state['values']['landmark_type']);
@@ -264,8 +270,8 @@ function tripal_feature_gff3_load_form_submit($form, &$form_state) {
   $organism_id = $form_state['values']['organism_id'];
   $organism_id = $form_state['values']['organism_id'];
   $add_only = $form_state['values']['add_only'];
   $add_only = $form_state['values']['add_only'];
   $update   = $form_state['values']['update'];
   $update   = $form_state['values']['update'];
-  $refresh  = $form_state['values']['refresh'];
-  $remove   = $form_state['values']['remove'];
+  $refresh  = 0; //$form_state['values']['refresh'];
+  $remove   = 0; //$form_state['values']['remove'];
   $analysis_id = $form_state['values']['analysis_id'];
   $analysis_id = $form_state['values']['analysis_id'];
   $use_transaction   = $form_state['values']['use_transaction'];
   $use_transaction   = $form_state['values']['use_transaction'];
   $target_organism_id = $form_state['values']['target_organism_id'];
   $target_organism_id = $form_state['values']['target_organism_id'];
@@ -381,10 +387,19 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
   $job = NULL) {
   $job = NULL) {
 
 
   $ret = array();
   $ret = array();
+  $date = getdate();
 
 
-  // empty the temp table
+  // An array that stores CVterms that have been looked up so we don't have
+  // to do the database query every time.
+  $cvterm_lookup = array();
+
+  // empty the temp tables
   $sql = "DELETE FROM {tripal_gff_temp}";
   $sql = "DELETE FROM {tripal_gff_temp}";
   chado_query($sql);
   chado_query($sql);
+  $sql = "DELETE FROM {tripal_gffcds_temp}";
+  chado_query($sql);
+  $sql = "DELETE FROM {tripal_gffprotein_temp}";
+  chado_query($sql);
 
 
   // begin the transaction
   // begin the transaction
   $transaction = null;
   $transaction = null;
@@ -429,7 +444,6 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
         "Cannot find the 'sequence' ontology", array());
         "Cannot find the 'sequence' ontology", array());
       return '';
       return '';
     }
     }
-
     // get the organism for which this GFF3 file belongs
     // get the organism for which this GFF3 file belongs
     $sql = "SELECT * FROM {organism} WHERE organism_id = :organism_id";
     $sql = "SELECT * FROM {organism} WHERE organism_id = :organism_id";
     $organism = chado_query($sql, array(':organism_id' => $organism_id))->fetchObject();
     $organism = chado_query($sql, array(':organism_id' => $organism_id))->fetchObject();
@@ -454,6 +468,23 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
        (lower(CVT.name) = lower(:name) or lower(CVTS.synonym) = lower(:synonym))
        (lower(CVT.name) = lower(:name) or lower(CVTS.synonym) = lower(:synonym))
      ";
      ";
 
 
+    // If a landmark type was provided then pre-retrieve that.
+    if ($landmark_type) {
+      $query = array(
+        ':cv_id' => $cv->cv_id,
+        ':name' => $landmark_type,
+        ':synonym' => $landmark_type
+      );
+      $result = chado_query($sel_cvterm_sql, $query);
+      $landmark_cvterm = $result->fetchObject();
+      if (!$landmark_cvterm) {
+        tripal_report_error('tripal_feature', TRIPAL_ERROR,
+          'cannot find landmark feature type \'%landmark_type\'.',
+          array('%landmark_type' => $landmark_type));
+        return '';
+      }
+    }
+
     // iterate through each line of the GFF file
     // iterate through each line of the GFF file
     print "Parsing Line $line_num (0.00%). Memory: " . number_format(memory_get_usage()) . " bytes\r";
     print "Parsing Line $line_num (0.00%). Memory: " . number_format(memory_get_usage()) . " bytes\r";
     while ($line = fgets($fh)) {
     while ($line = fgets($fh)) {
@@ -491,20 +522,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
         $rstart = $region_matches[2];
         $rstart = $region_matches[2];
         $rend = $region_matches[3];
         $rend = $region_matches[3];
         if ($landmark_type) {
         if ($landmark_type) {
-          $query = array(
-            ':cv_id' => $cv->cv_id,
-            ':name' => $landmark_type,
-            ':synonym' => $landmark_type
-          );
-          $result = chado_query($sel_cvterm_sql, $query);
-          $cvterm = $result->fetchObject();
-          if (!$cvterm) {
-            tripal_report_error('tripal_feature', TRIPAL_ERROR,
-             'cannot find feature type \'%landmark_type\' on line %line_num of the GFF file',
-              array('%landmark_type' => $landmark_type, '%line_num' => $line_num));
-            return '';
-          }
-          tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $rid,
+          tripal_feature_load_gff3_feature($organism, $analysis_id, $landmark_cvterm, $rid,
             $rid, '', 'f', 'f', 1, 0);
             $rid, '', 'f', 'f', 1, 0);
         }
         }
         continue;
         continue;
@@ -561,13 +579,18 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
       if (strcmp($phase, '.') == 0) {
       if (strcmp($phase, '.') == 0) {
         $phase = '';
         $phase = '';
       }
       }
-      $result = chado_query($sel_cvterm_sql, array(':cv_id' => $cv->cv_id, ':name' => $type, ':synonym' => $type));
-
-      $cvterm = $result->fetchObject();
-      if (!$cvterm) {
-        tripal_report_error('tripal_feature', TRIPAL_ERROR, 'cannot find feature term \'%type\' on line %line_num of the GFF file',
-          array('%type' => $type, '%line_num' => $line_num));
-        return '';
+      if (array_key_exists($type, $cvterm_lookup)) {
+        $cvterm = $cvterm_lookup[$type];
+      }
+      else {
+        $result = chado_query($sel_cvterm_sql, array(':cv_id' => $cv->cv_id, ':name' => $type, ':synonym' => $type));
+        $cvterm = $result->fetchObject();
+        $cvterm_lookup[$type] = $cvterm;
+        if (!$cvterm) {
+          tripal_report_error('tripal_feature', TRIPAL_ERROR, 'cannot find feature term \'%type\' on line %line_num of the GFF file',
+            array('%type' => $type, '%line_num' => $line_num));
+          return '';
+        }
       }
       }
 
 
       // break apart each of the attributes
       // break apart each of the attributes
@@ -650,7 +673,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
               }
               }
             }
             }
             else {
             else {
-              // we found the organism in the database so use it
+              // We found the organism in the database so use it.
               $feature_organism = $org[0];
               $feature_organism = $org[0];
             }
             }
           }
           }
@@ -661,7 +684,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
             $skip_feature = 1;
             $skip_feature = 1;
           }
           }
         }
         }
-        // get the list of non-reserved attributes
+        // Get the list of non-reserved attributes.
         elseif (strcmp($tag_name, 'Alias') != 0        and strcmp($tag_name, 'Parent') != 0 and
         elseif (strcmp($tag_name, 'Alias') != 0        and strcmp($tag_name, 'Parent') != 0 and
                 strcmp($tag_name, 'Target') != 0       and strcmp($tag_name, 'Gap') != 0 and
                 strcmp($tag_name, 'Target') != 0       and strcmp($tag_name, 'Gap') != 0 and
                 strcmp($tag_name, 'Derives_from') != 0 and strcmp($tag_name, 'Note') != 0 and
                 strcmp($tag_name, 'Derives_from') != 0 and strcmp($tag_name, 'Note') != 0 and
@@ -673,49 +696,46 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           }
           }
         }
         }
       }
       }
-      // if neither name nor uniquename are provided then generate one
+      // If neither name nor uniquename are provided then generate one.
       if (!$attr_uniquename and !$attr_name) {
       if (!$attr_uniquename and !$attr_name) {
-        // check if an alternate ID field is suggested, if so, then use
-        // that for the name
+        // Check if an alternate ID field is suggested, if so, then use
+        // that for the name.
         if (array_key_exists($alt_id_attr, $tags)) {
         if (array_key_exists($alt_id_attr, $tags)) {
           $attr_uniquename = $tags[$alt_id_attr][0];
           $attr_uniquename = $tags[$alt_id_attr][0];
           $attr_name = $attr_uniquename;
           $attr_name = $attr_uniquename;
         }
         }
-        // if the row has a parent then generate a uniquename using the parent name
+        // If the row has a parent then generate a uniquename using the parent name
         // add the date to the name in the event there are more than one child with
         // add the date to the name in the event there are more than one child with
         // the same parent.
         // the same parent.
         elseif (array_key_exists('Parent', $tags)) {
         elseif (array_key_exists('Parent', $tags)) {
-          $date = getdate();
           $attr_uniquename = $tags['Parent'][0] . "-$type-$landmark-" . $date[0] . ":" . ($fmin + 1) . ".." . $fmax;
           $attr_uniquename = $tags['Parent'][0] . "-$type-$landmark-" . $date[0] . ":" . ($fmin + 1) . ".." . $fmax;
           $attr_name = $attr_uniquename;
           $attr_name = $attr_uniquename;
         }
         }
-        // generate a unique name based on the date, type and location
-        // and set the name to simply be the type
+        // Generate a unique name based on the date, type and location
+        // and set the name to simply be the type.
         else {
         else {
-          $date = getdate();
           $attr_uniquename = $date[0] . "-$type-$landmark:" . ($fmin + 1) . ".." . $fmax;
           $attr_uniquename = $date[0] . "-$type-$landmark:" . ($fmin + 1) . ".." . $fmax;
           $attr_name = $type;
           $attr_name = $type;
         }
         }
       }
       }
 
 
-      // if a name is not specified then use the unique name as the name
+      // If a name is not specified then use the unique name as the name
       if (strcmp($attr_name, '') == 0) {
       if (strcmp($attr_name, '') == 0) {
         $attr_name = $attr_uniquename;
         $attr_name = $attr_uniquename;
       }
       }
 
 
-      // if an ID attribute is not specified then we must generate a
+      // If an ID attribute is not specified then we must generate a
       // unique ID. Do this by combining the attribute name with the date
       // unique ID. Do this by combining the attribute name with the date
       // and line number.
       // and line number.
       if (!$attr_uniquename) {
       if (!$attr_uniquename) {
-        $date = getdate();
         $attr_uniquename = $attr_name . '-' . $date[0] . '-' . $line_num;
         $attr_uniquename = $attr_name . '-' . $date[0] . '-' . $line_num;
       }
       }
 
 
-      // make sure the landmark sequence exists in the database.  If the user
-      // has not specified a landmark type (and it's not requiredin the GFF foramt)
-      // then We don't know the type of the landmark so we'll hope that it's unique across
-      // all types for the orgnaism. Only do this test if the landmark and the feature are
-      // different.
+      // Make sure the landmark sequence exists in the database.  If the user
+      // has not specified a landmark type (and it's not required in the GFF
+      // format) then we don't know the type of the landmark so we'll hope
+      // that it's unique across all types for the orgnaism. Only do this
+      // test if the landmark and the feature are different.
       if (!$remove and !(strcmp($landmark, $attr_uniquename) == 0 or strcmp($landmark, $attr_name) == 0)) {
       if (!$remove and !(strcmp($landmark, $attr_uniquename) == 0 or strcmp($landmark, $attr_name) == 0)) {
         $select = array(
         $select = array(
           'organism_id' => $organism->organism_id,
           'organism_id' => $organism->organism_id,
@@ -760,16 +780,17 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           return '';
           return '';
         }
         }
       }
       }
-
-      // if the option is to remove or refresh then we want to remove
+/*
+      // If the option is to remove or refresh then we want to remove
       // the feature from the database.
       // the feature from the database.
       if ($remove or $refresh) {
       if ($remove or $refresh) {
+        // Next remove the feature itself.
         $sql = "DELETE FROM {feature}
         $sql = "DELETE FROM {feature}
                 WHERE organism_id = %d and uniquename = '%s' and type_id = %d";
                 WHERE organism_id = %d and uniquename = '%s' and type_id = %d";
         $match = array(
         $match = array(
-           'organism_id' => $feature_organism->organism_id,
-           'uniquename'  => $attr_uniquename,
-           'type_id'     => $cvterm->cvterm_id
+          'organism_id' => $feature_organism->organism_id,
+          'uniquename'  => $attr_uniquename,
+          'type_id'     => $cvterm->cvterm_id
         );
         );
         $result = chado_delete_record('feature', $match);
         $result = chado_delete_record('feature', $match);
         if (!$result) {
         if (!$result) {
@@ -779,19 +800,19 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
         $feature = 0;
         $feature = 0;
         unset($result);
         unset($result);
       }
       }
-
-      // add or update the feature and all properties
+ */
+      // Add or update the feature and all properties.
       if ($update or $refresh or $add_only) {
       if ($update or $refresh or $add_only) {
 
 
-        // add/update the feature
+        // Add/update the feature.
         $feature = tripal_feature_load_gff3_feature($feature_organism, $analysis_id, $cvterm,
         $feature = tripal_feature_load_gff3_feature($feature_organism, $analysis_id, $cvterm,
           $attr_uniquename, $attr_name, $residues, $attr_is_analysis,
           $attr_uniquename, $attr_name, $residues, $attr_is_analysis,
           $attr_is_obsolete, $add_only, $score);
           $attr_is_obsolete, $add_only, $score);
 
 
         if ($feature) {
         if ($feature) {
 
 
-          // add a record for this feature to the tripal_gff_temp table for
-          // later lookup
+          // Add a record for this feature to the tripal_gff_temp table for
+          // later lookup.
           $values = array(
           $values = array(
             'feature_id' => $feature->feature_id,
             'feature_id' => $feature->feature_id,
             'organism_id' => $feature->organism_id,
             'organism_id' => $feature->organism_id,
@@ -830,7 +851,8 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           }
           }
           // add parent relationships
           // add parent relationships
           if (array_key_exists('Parent', $tags)) {
           if (array_key_exists('Parent', $tags)) {
-            tripal_feature_load_gff3_parents($feature, $cvterm, $tags['Parent'], $feature_organism->organism_id, $fmin);
+            tripal_feature_load_gff3_parents($feature, $cvterm, $tags['Parent'],
+              $feature_organism->organism_id, $strand, $phase, $fmin, $fmax);
           }
           }
 
 
           // add target relationships
           // add target relationships
@@ -851,7 +873,8 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           }
           }
           // add the Derives_from relationship (e.g. polycistronic genes).
           // add the Derives_from relationship (e.g. polycistronic genes).
           if (array_key_exists('Derives_from', $tags)) {
           if (array_key_exists('Derives_from', $tags)) {
-            tripal_feature_load_gff3_derives_from($feature, $tags['Derives_from'][0], $feature_organism);
+            tripal_feature_load_gff3_derives_from($feature, $cvterm, $tags['Derives_from'][0],
+              $feature_organism, $fmin, $fmax);
           }
           }
           // add in the GFF3_source dbxref so that GBrowse can find the feature using the source column
           // add in the GFF3_source dbxref so that GBrowse can find the feature using the source column
           $source_ref = array('GFF_source:' . $source);
           $source_ref = array('GFF_source:' . $source);
@@ -869,10 +892,79 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
       }
       }
     }
     }
 
 
+    // Do some last bit of processing.
     if (!$remove) {
     if (!$remove) {
+
+      // First, add any protein sequences if needed.
+      $sql = "SELECT feature_id FROM {tripal_gffcds_temp} LIMIT 1 OFFSET 1";
+      $has_cds = chado_query($sql)->fetchField();
+      if ($has_cds) {
+        print "\nAdding protein sequences if CDS exist and no proteins in GFF...\n";
+        $sql = "
+          SELECT F.feature_id, F.name, F.uniquename, TGCT.strand,
+            CVT.cvterm_id, CVT.name as feature_type,
+            min(TGCT.fmin) as fmin, max(TGCT.fmax) as fmax,
+            TGPT.feature_id as protein_id, TGPT.fmin as protein_fmin,
+            TGPT.fmax as protein_fmax
+          FROM {tripal_gffcds_temp} TGCT
+            INNER JOIN {feature} F on F.feature_id = TGCT.parent_id
+            INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
+            LEFT JOIN {tripal_gffprotein_temp} TGPT on TGPT.parent_id = F.feature_id
+          GROUP BY F.feature_id, F.name, F.uniquename, CVT.cvterm_id, CVT.name,
+            TGPT.feature_id, TGPT.fmin, TGPT.fmax, TGCT.strand
+        ";
+        $results = chado_query($sql);
+        $protein_cvterm = tripal_get_cvterm(array(
+          'name' => 'polypeptide',
+          'cv_id' => array(
+            'name' => 'sequence'
+          )
+        ));
+        while ($result = $results->fetchObject()) {
+          // If a protein exists with this same parent then don't add a new
+          // protein.
+          if (!$result->protein_id) {
+            // Get details about this protein
+            $uname = $result->uniquename . '-protein';
+            $name =  $result->name;
+            $values = array(
+              'parent_id' => $result->feature_id,
+              'fmin' => $result->fmin
+            );
+            $min_phase = chado_select_record('tripal_gffcds_temp', array('phase'), $values);
+            $values = array(
+              'parent_id' => $result->feature_id,
+              'fmax' => $result->fmax
+            );
+            $max_phase = chado_select_record('tripal_gffcds_temp', array('phase'), $values);
+
+            $pfmin = $result->fmin;
+            $pfmax = $result->fmax;
+            if ($result->strand == '-1') {
+              $pfmax -= $max_phase[0]->phase;
+            }
+            else {
+              $pfmin += $min_phase[0]->phase;
+            }
+
+            // Add the new protein record.
+            $feature = tripal_feature_load_gff3_feature($organism, $analysis_id,
+              $protein_cvterm, $uname, $name, '', 'f', 'f', 1, 0);
+            // Add the derives_from relationship.
+            $cvterm = tripal_get_cvterm(array('cvterm_id' => $result->cvterm_id));
+            tripal_feature_load_gff3_derives_from($feature, $cvterm,
+              $result->uniquename, $organism, $pfmin, $pfmax);
+            // Add the featureloc record. Set the start of the protein to
+            // be the start of the coding sequence minus the phase.
+            tripal_feature_load_gff3_featureloc($feature, $organism, $landmark,
+              $pfmin, $pfmax, $strand, '', 'f', 'f', '', 0);
+          }
+        }
+      }
+
       print "\nSetting ranks of children...\n";
       print "\nSetting ranks of children...\n";
 
 
-      // get features in a relationship that are also children of an alignment
+      // Get features in a relationship that are also children of an alignment.
       $sql = "
       $sql = "
         SELECT DISTINCT F.feature_id, F.organism_id, F.type_id,
         SELECT DISTINCT F.feature_id, F.organism_id, F.type_id,
           F.uniquename, FL.strand
           F.uniquename, FL.strand
@@ -885,15 +977,17 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
       ";
       ";
       $parents = chado_query($sql);
       $parents = chado_query($sql);
 
 
-      // build and prepare the SQL for selecting the children relationship
+      // Build and prepare the SQL for selecting the children relationship.
       $sel_gffchildren_sql = "
       $sel_gffchildren_sql = "
         SELECT DISTINCT FR.feature_relationship_id, FL.fmin, FR.rank
         SELECT DISTINCT FR.feature_relationship_id, FL.fmin, FR.rank
         FROM {feature_relationship} FR
         FROM {feature_relationship} FR
           INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
           INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
-        WHERE FR.object_id = :feature_id ORDER BY FL.fmin ASC
+          INNER JOIN {cvterm} CVT on CVT.cvterm_id = FR.type_id
+        WHERE FR.object_id = :feature_id AND CVT.name = 'part_of'
+        ORDER BY FL.fmin ASC
       ";
       ";
 
 
-      // now set the rank of any parent/child relationships.  The order is based
+      // Now set the rank of any parent/child relationships.  The order is based
       // on the fmin.  The start rank is 1.  This allows features with other
       // on the fmin.  The start rank is 1.  This allows features with other
       // relationships to be '0' (the default), and doesn't interfer with the
       // relationships to be '0' (the default), and doesn't interfer with the
       // ordering defined here.
       // ordering defined here.
@@ -977,37 +1071,42 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
  *
  *
  * @ingroup gff3_loader
  * @ingroup gff3_loader
  */
  */
-function tripal_feature_load_gff3_derives_from($feature, $subject, $organism) {
+function tripal_feature_load_gff3_derives_from($feature, $cvterm, $object,
+  $organism, $fmin, $fmax) {
+
+  $type = $cvterm->name;
 
 
-  // get the subject. If the subject is not in the tripal_gff_temp table
-  // then look for the subject in the feature table using the unique name.
-  // if it is not unique then we can provide an error
+  // First look for the object feature in the temp table to get it's type.
   $values = array(
   $values = array(
     'organism_id' => $organism->organism_id,
     'organism_id' => $organism->organism_id,
-    'uniquename' => $subject,
+    'uniquename' => $object,
   );
   );
   $result = chado_select_record('tripal_gff_temp', array('type_name'), $values);
   $result = chado_select_record('tripal_gff_temp', array('type_name'), $values);
-  $type_id = array();
+  $type_id = NULL;
   if (count($result) > 0) {
   if (count($result) > 0) {
-    $type_id = array(
+    $otype = tripal_get_cvterm(array(
       'name' => $result[0]->type_name,
       'name' => $result[0]->type_name,
       'cv_id' => array(
       'cv_id' => array(
         'name' => 'sequence'
         'name' => 'sequence'
-      ),
-    );
+      )
+    ));
+    if ($otype) {
+      $type_id = $otype->cvterm_id;
+    }
   }
   }
 
 
-  // if we don't have a subject type then look for the feature in the feature table
-  if (empty($type_id)) {
+  // If the object wasn't in the temp table then look for it in the
+  // feature table and get it's type.
+  if (!$type_id) {
     $result = chado_select_record('feature', array('type_id'), $values);
     $result = chado_select_record('feature', array('type_id'), $values);
     if (count($result) > 1) {
     if (count($result) > 1) {
-      watchdog("tripal_feature", "Cannot find subject type for feature,'%subject' , in 'derives_from' relationship. Multiple matching features exist with this uniquename.",
-        array('%subject' => $subject), WATCHDOG_WARNING);
+      watchdog("tripal_feature", "Cannot find feature type for, '%subject' , in 'derives_from' relationship. Multiple matching features exist with this uniquename.",
+        array('%subject' => $object), WATCHDOG_WARNING);
       return '';
       return '';
     }
     }
     else if (count($result) == 0) {
     else if (count($result) == 0) {
-      watchdog("tripal_feature", "Cannot find subject type for feature,'%subject' , in 'derives_from' relationship.",
-        array('%subject' => $subject), WATCHDOG_WARNING);
+      watchdog("tripal_feature", "Cannot find feature type for, '%subject' , in 'derives_from' relationship.",
+        array('%subject' => $object), WATCHDOG_WARNING);
       return '';
       return '';
     }
     }
     else {
     else {
@@ -1015,32 +1114,43 @@ function tripal_feature_load_gff3_derives_from($feature, $subject, $organism) {
     }
     }
   }
   }
 
 
-  // get the subject feature
+  // Get the object feature.
   $match = array(
   $match = array(
     'organism_id' => $organism->organism_id,
     'organism_id' => $organism->organism_id,
-    'uniquename' => $subject,
-    'type_id' => array(
-      'name' => $subject_type,
-      'cv_id' => array(
-        'name' => 'sequence'
-      ),
-    ),
+    'uniquename' => $object,
+    'type_id' => $type_id,
   );
   );
-  $sfeature = chado_select_record('feature', array('feature_id'), $match);
-  if (count($sfeature)==0) {
+  $ofeature = chado_select_record('feature', array('feature_id'), $match);
+  if (count($ofeature) == 0) {
     tripal_report_error('tripal_feature', TRIPAL_ERROR, "Could not add 'Derives_from' relationship " .
     tripal_report_error('tripal_feature', TRIPAL_ERROR, "Could not add 'Derives_from' relationship " .
       "for %uniquename and %subject.  Subject feature, '%subject', " .
       "for %uniquename and %subject.  Subject feature, '%subject', " .
       "cannot be found", array('%uniquename' => $feature->uniquename, '%subject' => $subject));
       "cannot be found", array('%uniquename' => $feature->uniquename, '%subject' => $subject));
     return;
     return;
   }
   }
 
 
-   // now check to see if the relationship already exists
+  // If this feature is a protein then add it to the tripal_gffprotein_temp.
+  if ($type == 'protein' or $type == 'polypeptide') {
+    $values = array(
+      'feature_id' => $feature->feature_id,
+      'parent_id' => $ofeature[0]->feature_id,
+      'fmin' => $fmin,
+      'fmax' => $fmax
+    );
+    $result = chado_insert_record('tripal_gffprotein_temp', $values);
+    if (!$result) {
+      tripal_report_error('tripal_feature', TRIPAL_ERROR, "Cound not save record in temporary protein table, Cannot continue.", array());
+      exit;
+    }
+  }
+
+   // Now check to see if the relationship already exists. If it does
+   // then just return.
   $values = array(
   $values = array(
-    'object_id' => $sfeature[0]->feature_id,
+    'object_id' => $ofeature[0]->feature_id,
     'subject_id' => $feature->feature_id,
     'subject_id' => $feature->feature_id,
     'type_id' => array(
     'type_id' => array(
        'cv_id' => array(
        'cv_id' => array(
-          'name' => 'relationship'
+          'name' => 'sequence'
         ),
         ),
        'name' => 'derives_from',
        'name' => 'derives_from',
     ),
     ),
@@ -1070,13 +1180,14 @@ function tripal_feature_load_gff3_derives_from($feature, $subject, $organism) {
  *
  *
  * @ingroup gff3_loader
  * @ingroup gff3_loader
  */
  */
-function tripal_feature_load_gff3_parents($feature, $cvterm, $parents, $organism_id, $fmin) {
+function tripal_feature_load_gff3_parents($feature, $cvterm, $parents,
+  $organism_id, $strand, $phase, $fmin, $fmax) {
 
 
   $uname = $feature->uniquename;
   $uname = $feature->uniquename;
   $type = $cvterm->name;
   $type = $cvterm->name;
   $rel_type = 'part_of';
   $rel_type = 'part_of';
 
 
-  // prepare these SQL statements that will be used repeatedly.
+  // Prepare these SQL statements that will be used repeatedly.
   $cvterm_sql = "
   $cvterm_sql = "
     SELECT CVT.cvterm_id
     SELECT CVT.cvterm_id
     FROM {cvterm} CVT
     FROM {cvterm} CVT
@@ -1085,9 +1196,9 @@ function tripal_feature_load_gff3_parents($feature, $cvterm, $parents, $organism
     WHERE cv.name = :cvname and (CVT.name = :name or CVTS.synonym = :synonym)
     WHERE cv.name = :cvname and (CVT.name = :name or CVTS.synonym = :synonym)
   ";
   ";
 
 
-  // iterate through the parents in the list
+  // Iterate through the parents in the list.
   foreach ($parents as $parent) {
   foreach ($parents as $parent) {
-    // get the parent cvterm
+    // Get the parent cvterm.
     $values = array(
     $values = array(
       'organism_id' => $organism_id,
       'organism_id' => $organism_id,
       'uniquename' => $parent,
       'uniquename' => $parent,
@@ -1101,7 +1212,7 @@ function tripal_feature_load_gff3_parents($feature, $cvterm, $parents, $organism
 
 
     // try to find the parent
     // try to find the parent
     $parentcvterm = chado_query($cvterm_sql, array(':cvname' => 'sequence', ':name' => $parent_type, ':synonym' => $parent_type))->fetchObject();
     $parentcvterm = chado_query($cvterm_sql, array(':cvname' => 'sequence', ':name' => $parent_type, ':synonym' => $parent_type))->fetchObject();
-    $relcvterm = chado_query($cvterm_sql, array(':cvname' => 'relationship', ':name' => $rel_type, ':synonym' => $rel_type))->fetchObject();
+    $relcvterm = chado_query($cvterm_sql, array(':cvname' => 'sequence', ':name' => $rel_type, ':synonym' => $rel_type))->fetchObject();
     $values = array(
     $values = array(
         'organism_id' => $organism_id,
         'organism_id' => $organism_id,
         'uniquename' => $parent,
         'uniquename' => $parent,
@@ -1136,6 +1247,24 @@ function tripal_feature_load_gff3_parents($feature, $cvterm, $parents, $organism
             array());
             array());
         }
         }
       }
       }
+
+      // If this feature is a CDS and now that we know the parent we can
+      // add it to the tripal_gffcds_temp table for later lookup.
+      if ($type == 'CDS') {
+        $values = array(
+          'feature_id' => $feature->feature_id,
+          'parent_id' => $parent_feature->feature_id,
+          'fmin' => $fmin,
+          'fmax' => $fmax,
+          'strand' => $strand,
+          'phase' => $phase,
+        );
+        $result = chado_insert_record('tripal_gffcds_temp', $values);
+        if (!$result) {
+          tripal_report_error('tripal_feature', TRIPAL_ERROR, "Cound not save record in temporary CDS table, Cannot continue.", array());
+          exit;
+        }
+      }
     }
     }
     else {
     else {
       tripal_report_error("tripal_feature", TRIPAL_WARNING, "Cannot establish relationship '$uname' ($type) $rel_type '$parent' ($parent_type): Cannot find the parent",
       tripal_report_error("tripal_feature", TRIPAL_WARNING, "Cannot establish relationship '$uname' ($type) $rel_type '$parent' ($parent_type): Cannot find the parent",
@@ -1482,12 +1611,12 @@ function tripal_feature_load_gff3_alias($feature, $aliases) {
 function tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $uniquename,
 function tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $uniquename,
   $name, $residues, $is_analysis = 'f', $is_obsolete = 'f', $add_only, $score) {
   $name, $residues, $is_analysis = 'f', $is_obsolete = 'f', $add_only, $score) {
 
 
-  // check to see if the feature already exists
+  // Check to see if the feature already exists.
   $feature = NULL;
   $feature = NULL;
   $fselect = array(
   $fselect = array(
-     'organism_id' => $organism->organism_id,
-     'uniquename' => $uniquename,
-     'type_id' => $cvterm->cvterm_id
+    'organism_id' => $organism->organism_id,
+    'uniquename' => $uniquename,
+    'type_id' => $cvterm->cvterm_id
   );
   );
   $columns = array('feature_id', 'name', 'uniquename', 'seqlen', 'organism_id', 'type_id');
   $columns = array('feature_id', 'name', 'uniquename', 'seqlen', 'organism_id', 'type_id');
   $result = chado_select_record('feature', $columns, $fselect);
   $result = chado_select_record('feature', $columns, $fselect);
@@ -1508,21 +1637,19 @@ function tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $uni
     $is_analysis = 'TRUE';
     $is_analysis = 'TRUE';
   }
   }
 
 
-  // insert the feature if it does not exist otherwise perform an update
+  // Insert the feature if it does not exist otherwise perform an update.
   if (!$feature) {
   if (!$feature) {
     $values = array(
     $values = array(
-       'organism_id' => $organism->organism_id,
-       'name' => $name,
-       'uniquename' => $uniquename,
-//       'residues' => $residues,
-//       'seqlen' => drupal_strlen($residues),
-       'md5checksum' => md5($residues),
-       'type_id' => $cvterm->cvterm_id,
-       'is_analysis' => $is_analysis,
-       'is_obsolete' => $is_obsolete,
+      'organism_id' => $organism->organism_id,
+      'name' => $name,
+      'uniquename' => $uniquename,
+      'md5checksum' => md5($residues),
+      'type_id' => $cvterm->cvterm_id,
+      'is_analysis' => $is_analysis,
+      'is_obsolete' => $is_obsolete,
     );
     );
-    $result = chado_insert_record('feature', $values);
-    if (!$result) {
+    $feature = (object) chado_insert_record('feature', $values);
+    if (!$feature) {
       tripal_report_error("tripal_feature", TRIPAL_WARNING, "Failed to insert feature '$uniquename' ($cvterm->name)", array());
       tripal_report_error("tripal_feature", TRIPAL_WARNING, "Failed to insert feature '$uniquename' ($cvterm->name)", array());
       return 0;
       return 0;
     }
     }
@@ -1530,8 +1657,6 @@ function tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $uni
   elseif (!$add_only) {
   elseif (!$add_only) {
     $values = array(
     $values = array(
       'name' => $name,
       'name' => $name,
-//      'residues' => $residues,
-//      'seqlen' => drupal_strlen($residues),
       'md5checksum' => md5($residues),
       'md5checksum' => md5($residues),
       'is_analysis' => $is_analysis,
       'is_analysis' => $is_analysis,
       'is_obsolete' => $is_obsolete,
       'is_obsolete' => $is_obsolete,
@@ -1548,17 +1673,13 @@ function tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $uni
     }
     }
   }
   }
   else {
   else {
-    // the feature exists and we don't want to update it so return
+    // The feature exists and we don't want to update it so return
     // a value of 0.  This will stop all downstream property additions
     // a value of 0.  This will stop all downstream property additions
-    return 0;
+    return $feature;
   }
   }
 
 
-  // get the newly added feature
-  $columns = array('feature_id', 'name', 'uniquename', 'seqlen', 'organism_id', 'type_id');
-  $result = chado_select_record('feature', $columns, $fselect);
-  $feature = $result[0];
-
-  // add the analysisfeature entry to the analysisfeature table if it doesn't already exist
+  // Add the analysisfeature entry to the analysisfeature table if
+  // it doesn't already exist.
   $af_values = array(
   $af_values = array(
     'analysis_id' => $analysis_id,
     'analysis_id' => $analysis_id,
     'feature_id' => $feature->feature_id
     'feature_id' => $feature->feature_id
@@ -1589,6 +1710,7 @@ function tripal_feature_load_gff3_feature($organism, $analysis_id, $cvterm, $uni
       }
       }
     }
     }
   }
   }
+
   return $feature;
   return $feature;
 }
 }
 
 
@@ -1916,14 +2038,18 @@ function tripal_feature_load_gff3_fasta($fh, $interval, &$num_read, &$intv_read,
         else {
         else {
           // if we have a feature then add the residues
           // if we have a feature then add the residues
           $feature = $result[0];
           $feature = $result[0];
-          $values = array('residues' => $residues);
+          $values = array(
+            'residues' => $residues,
+            'seqlen' => strlen($residues)
+          );
           $match = array('feature_id' => $feature->feature_id);
           $match = array('feature_id' => $feature->feature_id);
           chado_update_record('feature', $match, $values);
           chado_update_record('feature', $match, $values);
         }
         }
       }
       }
 
 
-      // get the feature ID for this ID from the tripal_gff_temp table
-      $id = preg_replace('/^>(.*)$/', '\1', $line);
+      // get the feature ID for this ID from the tripal_gff_temp table. It
+      // should be the name up to the first space
+      $id = preg_replace('/^>([^\s]+).*$/', '\1', $line);
       $residues = '';
       $residues = '';
     }
     }
     else {
     else {
@@ -1941,7 +2067,10 @@ function tripal_feature_load_gff3_fasta($fh, $interval, &$num_read, &$intv_read,
   else {
   else {
     // if we have a feature then add the residues
     // if we have a feature then add the residues
     $feature = $result[0];
     $feature = $result[0];
-    $values = array('residues' => $residues);
+    $values = array(
+      'residues' => $residues,
+      'seqlen' => strlen($residues)
+    );
     $match = array('feature_id' => $feature->feature_id);
     $match = array('feature_id' => $feature->feature_id);
     chado_update_record('feature', $match, $values);
     chado_update_record('feature', $match, $values);
   }
   }

+ 26 - 5
tripal_feature/theme/css/tripal_feature.css

@@ -11,7 +11,7 @@
 pre.tripal_feature-sequence {
 pre.tripal_feature-sequence {
   color: #000000;
   color: #000000;
   height: 300px;
   height: 300px;
-  overflow: scroll; 
+  overflow: scroll;
   border: 1px solid #DDDDDD;
   border: 1px solid #DDDDDD;
   max-width: 500px;
   max-width: 500px;
   white-space: normal;
   white-space: normal;
@@ -52,23 +52,23 @@ span.tripal_feature-featureloc_sequence-exon {
 
 
 span.tripal_feature-featureloc_sequence-intron {
 span.tripal_feature-featureloc_sequence-intron {
    background-image: url('../images/type_color6.png');
    background-image: url('../images/type_color6.png');
- 
+
 }
 }
 
 
-/* 
+/*
  * Sequence Retrieval Form
  * Sequence Retrieval Form
  */
  */
 #tripal-feature-seq-extract-form-table {
 #tripal-feature-seq-extract-form-table {
   border-collapse: collapse;
   border-collapse: collapse;
   border: 0px solid #DDDDDD;
   border: 0px solid #DDDDDD;
-  border-spacing: 0;  
+  border-spacing: 0;
   margin: 1em 0;
   margin: 1em 0;
   width: auto;
   width: auto;
 }
 }
 #tripal-feature-seq-extract-form-table tr {
 #tripal-feature-seq-extract-form-table tr {
   background-color: transparent;
   background-color: transparent;
   border: 0px solid #CCCCCC;
   border: 0px solid #CCCCCC;
-  padding: 0.1em 0.6em;  
+  padding: 0.1em 0.6em;
 }
 }
 #tripal-feature-seq-extract-form-table td {
 #tripal-feature-seq-extract-form-table td {
   border: 0px solid #DDDDDD;
   border: 0px solid #DDDDDD;
@@ -77,4 +77,25 @@ span.tripal_feature-featureloc_sequence-intron {
 }
 }
 #tripal-feature-seq-extract-form-table .form-item {
 #tripal-feature-seq-extract-form-table .form-item {
   white-space: normal;
   white-space: normal;
+}
+
+/*
+ * Admin Summary Charts
+ */
+.tripal-admin-summary {
+  border: 1px solid #ccc;
+  padding: 15px;
+  margin-bottom: 15px;
+}
+.tripal-admin-summary .axis {
+  font: 10px sans-serif;
+}
+.tripal-admin-summary .axis path,
+.tripal-admin-summary .axis line {
+  fill: none;
+  stroke: #000;
+  shape-rendering: crispEdges;
+}
+.tripal-admin-figure-desc .figure-title {
+  font-weight: bold;
 }
 }

+ 243 - 0
tripal_feature/theme/js/tripalFeature.adminChart.js

@@ -0,0 +1,243 @@
+Drupal.behaviors.tripalFeature_adminSummaryChart = {
+  attach: function (context, settings) {
+
+    // Set-up the dimensions for our chart canvas.
+    // Note: these are adjusted below so think of these are your minimum size.
+    var margin = {top: 20, right: 50, bottom: 20, left: 100},
+        fullWidth = document.getElementById('tripal-feature-admin-summary').offsetWidth,
+        width = fullWidth - margin.left - margin.right,
+        height = 300 - margin.top - margin.bottom;
+
+    var color = d3.scale.ordinal()
+        .range(["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"]);
+
+    var formatNum = d3.format("0,000");
+
+    // The data was parsed and saved into tripalFeature.admin.summary
+    // in the preprocess function for this template.
+    if (Drupal.settings.tripalFeature.admin.summary) {
+
+      // Determine the max number of characters in both the type name
+      // and the total number of features per bar for use in width/magin adjustments.
+      var maxTypeLength = 0;
+      var maxTotalLength = 0;
+      var numBars = Drupal.settings.tripalFeature.admin.summary.length;
+      for(var i=0; i < numBars; i++){
+        var element = Drupal.settings.tripalFeature.admin.summary[i];
+
+        if(element.name.length > maxTypeLength){
+          maxTypeLength = element.name.length;
+        }
+
+        if(element.total_features.length > maxTotalLength){
+          maxTotalLength = element.total_features.length;
+        }
+      }
+      // Ensure a minimum in case something goes wrong...
+      if (maxTotalLength < 4) { maxTotalLength = 4; }
+      if (maxTypeLength < 10) { maxTypeLength = 10; }
+
+      // Adjust our bottom margin based on the length of type names in the data.
+      // Assume 4px/character based on the slope of the label.
+      xAxisHeight = maxTypeLength * 3;
+      margin.bottom = xAxisHeight + 25;
+
+      // Adjust the width of the chart based on the number or bars (types)
+      // and the length of the bar totals which need to fit on the top of the bar.
+      // Assume 9px/character since it's not rotated.
+      if ((width + margin.left + margin.right) < (numBars * (maxTotalLength * 9))) {
+        width = numBars * (maxTotalLength * 9);
+      }
+
+      // Determine the best place for the legend. Default to top since that
+      // will for sure not cause conflict... even though it looks better
+      // on the right ;).
+      // Logic: If the difference between the max & min bar heights is greater
+      // than 1/2 the chart height (max bar height) then there "should"
+      // be room for the chart nested on the right.
+      minBarHeight = d3.min(Drupal.settings.tripalFeature.admin.summary, function(d,i) { return d.total_features; });
+      barHeightDifference = Drupal.settings.tripalFeature.admin.maxBarHeight - minBarHeight;
+      if (barHeightDifference >= Drupal.settings.tripalFeature.admin.maxBarHeight/2) {
+        Drupal.settings.tripalFeature.admin.legendPosition = 'right';
+      }
+
+      // Also if we need to put the legend along the top we need to
+      // increase the top margin.
+      if (Drupal.settings.tripalFeature.admin.legendPosition == 'top') {
+        // Draw a top legend in the margin.
+        var columnWidth = d3.max(Drupal.settings.tripalFeature.admin.organisms, function(d,i) {return d.length;}) * 10;
+        var maxNumColumns = Math.round(width / columnWidth);
+        var numRows = Math.ceil(Drupal.settings.tripalFeature.admin.organisms.length / maxNumColumns);
+        var idealNumColumns = Math.round(Drupal.settings.tripalFeature.admin.organisms.length / numRows);
+        var legendMargin = {
+          left: (width - (idealNumColumns * columnWidth))/2,
+          right: (width - (idealNumColumns * columnWidth))/2,
+          bottom: 25
+        };
+
+        margin.top = margin.top + (numRows * 20) + legendMargin.bottom;
+      }
+
+      // Set-up the scales of the chart.
+      var x0 = d3.scale.ordinal()
+        .rangeRoundBands([0, width], .1);
+      var x1 = d3.scale.ordinal();
+      var y = d3.scale.linear()
+        .range([height, 0]);
+
+      // Now set-up the axis functions.
+      var xAxis = d3.svg.axis()
+        .scale(x0)
+        .orient('bottom');
+      var yAxis = d3.svg.axis()
+        .scale(y)
+        .orient('left')
+        .ticks(10, '');
+
+      // Create our chart canvas.
+      var svg = d3.select('#tripal-feature-admin-summary-chart').append('svg')
+          .attr('width', width + margin.left + margin.right)
+          .attr('height', height + margin.top + margin.bottom)
+        .append('g')
+          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+      // map the data to the x & y axis' of our chart.
+      data = Drupal.settings.tripalFeature.admin.summary;
+      x0.domain(data.map(function(d) { return d.name; }));
+      x1.domain(Drupal.settings.tripalFeature.admin.organisms).rangeRoundBands([0, x0.rangeBand()]);
+      y.domain([0, Drupal.settings.tripalFeature.admin.maxBarHeight]);
+
+      // Create the x-axis.
+      var xaxis = svg.append('g')
+        .attr('class', 'x axis')
+        .attr('transform', 'translate(0,' + height + ')')
+        .call(xAxis);
+
+      xaxis.selectAll("text")
+        .style("text-anchor", "end")
+        .attr("dx", "-.8em")
+        .attr("dy", ".15em")
+        .attr("transform", function(d) { return "rotate(-25)"; });
+
+      // Label the  x-axis.
+      xaxis.append('g')
+        .attr('class', 'axis-label')
+          .attr('transform', 'translate(' + width/2 + ',' + xAxisHeight + ')')
+        .append('text')
+          .attr('font-size', '16px')
+          .attr('dy', '.71em')
+          .style('text-anchor', 'middle')
+          .text('Types of Features');
+
+      // Create the y-axis.
+      var yaxis = svg.append('g')
+          .attr('class', 'y axis')
+          .call(yAxis);
+
+      // Label the y-axis.
+      yaxis.append('g')
+        .attr('class', 'axis-label')
+          .attr('transform', 'translate(-70,' + height/2 + ')')
+        .append('text')
+          .attr('transform', 'rotate(-90)')
+          .attr('font-size', '16px')
+          .attr('dy', '.71em')
+          .style('text-anchor', 'middle')
+          .text('Total Number of Features');
+
+      // Add a g element to contain each set of bars (1 per type).
+      var type = svg.selectAll(".type")
+          .data(data)
+        .enter().append("g")
+          .attr("class", "g")
+          .attr("transform", function(d) { return "translate(" + x0(d.name) + ",0)"; });
+
+      // Now add the bars :)
+      // Keep in mind some processing was done in the preprocess function to
+      // generate the bars array based on the organisms array
+      // and pre-calculated the y0 & y1 used here.
+      type.selectAll("rect")
+          .data(function(d) { return d.bars; })
+        .enter().append("rect")
+          .attr("width", x0.rangeBand())
+          .attr("y", function(d) { return y(d.y1); })
+          .attr("height", function(d) { return y(d.y0) - y(d.y1); })
+          .style("fill", function(d) { return color(d.name); })
+        .append("svg:title")
+          .text(function(d) { return formatNum(d.y1 - d.y0); });
+
+      // Add the total to the top of the bar.
+      svg.selectAll("g.bar-totals")
+        .data(data)
+      .enter().append('g')
+        .classed('bar-totals', true)
+      .append("text")
+        .attr("class", "bar-label")
+        .attr("text-anchor", "middle")
+        .attr('font-size', '10px')
+        .attr("x", function(d) { return x0(d.name) + x0.rangeBand()/2; })
+        .attr("y", function(d) { return y(d.total_features) -5; })
+        .text(function(d) { return formatNum(d.total_features); });
+
+      // Legend
+      //---------
+      // NOTE: we would prefer to have the legend overlapping the chart on the
+      // right side but this could be a problem if you have a similar count
+      // for all features (legend overlaps bars) or a large number of types
+      // (legend gets pushed out of the viewable screen area). In these cases
+      // switch to a bottom legend.
+      if (Drupal.settings.tripalFeature.admin.legendPosition == 'top') {
+        // Draw a bottom legend in the margin.
+        var legend = svg.append('g')
+          .classed('legend', true)
+          .attr('transform', 'translate(' + (legendMargin.left - 20) + ',-' + margin.top + ')');
+
+        var legendItem = legend.selectAll('g')
+            .data(Drupal.settings.tripalFeature.admin.organisms.slice().reverse())
+          .enter().append("g")
+            .attr("class", "legend-item")
+            .attr("transform", function(d,i) {
+              xOff = (i % idealNumColumns) * columnWidth;
+              yOff = Math.floor(i  / idealNumColumns) * 25;
+              return "translate(" + xOff + "," + yOff + ")"
+          });
+        legendItem.append("rect")
+            //.attr("x", width - 18)
+            .attr("width", 18)
+            .attr("height", 18)
+            .style("fill", color);
+        legendItem.append("text")
+            .attr("x", 24)
+            .attr("y", 9)
+            .attr("dy", ".35em")
+            .style("text-anchor", "start")
+            .attr('font-style','italic')
+            .text(function(d) { return d; });
+      }
+      else {
+        // Draw a right inset legend.
+        var legend = svg.append('g')
+          .classed('legend', true)
+          .attr('transform', 'translate(0,-' + margin.top + ')');
+
+        var legendItem = legend.selectAll('g')
+            .data(Drupal.settings.tripalFeature.admin.organisms.slice().reverse())
+          .enter().append("g")
+            .attr("class", "legend")
+            .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
+        legendItem.append("rect")
+            .attr("x", width - 18)
+            .attr("width", 18)
+            .attr("height", 18)
+            .style("fill", color);
+        legendItem.append("text")
+            .attr("x", width - 24)
+            .attr("y", 9)
+            .attr("dy", ".35em")
+            .style("text-anchor", "end")
+            .attr('font-style','italic')
+            .text(function(d) { return d; });
+      }
+    }
+  }
+};

+ 28 - 0
tripal_feature/theme/templates/tripal_feature_bar_chart_type_organism_summary.tpl.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Feature Summary Bar Chart (broken down by type & organism).
+ *
+ * This template displays a feature summary stacked bar chart
+ * where each bar depicts the total number of features per
+ * feature type and the stacked portions of a given bar
+ * respresent the organism breakdown of those featurs.
+ *
+ * Most of the functionality is in the preprocess for this template and
+ * the acompanying javascript file.
+ * @see tripal_feature/theme/js/tripalFeature.adminChart.js
+ * @see tripal_feature/theme/tripal_feature.theme.inc:tripal_feature_preprocess_tripal_feature_bar_chart_type_organism_summary()
+ */
+?>
+
+<div id="tripal-feature-admin-summary" class="tripal-admin-summary">
+  <div id="tripal-feature-admin-summary-chart" "tripal-admin-chart"></div>
+  <div id="tripal-feature-admin-summary-figure-desc" "tripal-admin-figure-desc">
+    <span class="figure-title">Feature Composition</span>:
+    This figure depicts the type and source organism of features in your Tripal
+    site. It is populated from the <em><?php print $chart_details['mviewTable']; ?></em>
+    materialized view which was last updated on <em><?php print $chart_details['mviewLastUpdate']; ?></em>.
+    <strong><em>To update this chart, <a href="<?php print $chart_details['mviewUrl'];?>">
+    submit a job to update the materialized view</a></em></strong>.
+  </div>
+</div>
+

+ 93 - 26
tripal_feature/theme/templates/tripal_feature_relationships.tpl.php

@@ -1,17 +1,17 @@
 <?php
 <?php
 /* Typically in a Tripal template, the data needed is retrieved using a call to
 /* Typically in a Tripal template, the data needed is retrieved using a call to
- * chado_expand_var function.  For example, to retrieve all 
+ * chado_expand_var function.  For example, to retrieve all
  * of the feature relationships for this node, the following function call would be made:
  * of the feature relationships for this node, the following function call would be made:
- * 
+ *
  *   $feature = chado_expand_var($feature,'table','feature_relationship');
  *   $feature = chado_expand_var($feature,'table','feature_relationship');
- * 
+ *
  * However, this function call can be extremely slow when there are numerous relationships.
  * However, this function call can be extremely slow when there are numerous relationships.
- * This is because the chado_expand_var function is recursive and expands 
+ * This is because the chado_expand_var function is recursive and expands
  * all data following the foreign key relationships tree.  Therefore, to speed retrieval
  * all data following the foreign key relationships tree.  Therefore, to speed retrieval
  * of data, a special variable is provided to this template:
  * of data, a special variable is provided to this template:
- * 
+ *
  *   $feature->all_relationships;
  *   $feature->all_relationships;
- *   
+ *
  * This variable is an array with two sub arrays with the keys 'object' and 'subject'.  The array with
  * This variable is an array with two sub arrays with the keys 'object' and 'subject'.  The array with
  * key 'object' contains relationships where the feature is the object, and the array with
  * key 'object' contains relationships where the feature is the object, and the array with
  * the key 'subject' contains relationships where the feature is the subject
  * the key 'subject' contains relationships where the feature is the subject
@@ -24,23 +24,57 @@ $subject_rels = $all_relationships['subject'];
 
 
 if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
 if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
   <div class="tripal_feature-data-block-desc tripal-data-block-desc"></div> <?php
   <div class="tripal_feature-data-block-desc tripal-data-block-desc"></div> <?php
-  
-  // first add in the subject relationships.  
+
+  // first add in the subject relationships.
   foreach ($subject_rels as $rel_type => $rels){
   foreach ($subject_rels as $rel_type => $rels){
-    foreach ($rels as $obj_type => $objects){ ?>
-      <p>This <?php print $feature->type_id->name;?> is <?php print $rel_type ?> the following <b><?php print $obj_type ?></b> feature(s): <?php
-       
+    foreach ($rels as $obj_type => $objects){
+
+      // Make the verb in the sentence make sense in English.
+      switch ($rel_type) {
+        case 'integral part of':
+        case 'instance of':
+          $verb = 'is an';
+          break;
+        case 'proper part of':
+        case 'transformation of':
+        case 'genome of':
+        case 'part of':
+        case 'position of':
+        case 'sequence of':
+        case 'variant of':
+          $verb = 'is a';
+          break;
+        case 'derives from':
+        case 'connects on':
+        case 'contains':
+        case 'finishes':
+        case 'guides':
+        case 'has origin':
+        case 'has part':
+        case 'has quality':
+        case 'is consecutive sequence of':
+        case 'maximally overlaps':
+        case 'overlaps':
+        case 'starts':
+          $verb = '';
+          break;
+        default:
+          $verb = 'is';
+      } ?>
+
+      <p>This <?php print $feature->type_id->name;?> <?php print $verb ?> <?php print $rel_type ?> the following <b><?php print $obj_type ?></b> feature(s): <?php
+
       // the $headers array is an array of fields to use as the colum headers.
       // the $headers array is an array of fields to use as the colum headers.
       // additional documentation can be found here
       // additional documentation can be found here
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
       $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
-      
+
       // the $rows array contains an array of rows where each row is an array
       // the $rows array contains an array of rows where each row is an array
       // of values for each column of the table in that row.  Additional documentation
       // of values for each column of the table in that row.  Additional documentation
       // can be found here:
       // can be found here:
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       $rows = array();
       $rows = array();
-      
+
       foreach ($objects as $object){
       foreach ($objects as $object){
         // link the feature to it's node
         // link the feature to it's node
         $feature_name = $object->record->object_id->name;
         $feature_name = $object->record->object_id->name;
@@ -54,12 +88,12 @@ if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
           $organism_name = l("<i>" . $organism->genus . " " . $organism->species . "</i>", "node/" . $organism->nid, array('html' => TRUE));
           $organism_name = l("<i>" . $organism->genus . " " . $organism->species . "</i>", "node/" . $organism->nid, array('html' => TRUE));
         }
         }
         $rows[] = array(
         $rows[] = array(
-          array('data' => $feature_name, 'width' => '30%'), 
+          array('data' => $feature_name, 'width' => '30%'),
           array('data' => $object->record->object_id->uniquename, 'width' => '30%'),
           array('data' => $object->record->object_id->uniquename, 'width' => '30%'),
           array('data' => $organism_name, 'width' => '30%'),
           array('data' => $organism_name, 'width' => '30%'),
           array('data' => $object->record->object_id->type_id->name, 'width' => '10%'),
           array('data' => $object->record->object_id->type_id->name, 'width' => '10%'),
-        ); 
-       } 
+        );
+       }
        // the $table array contains the headers and rows array as well as other
        // the $table array contains the headers and rows array as well as other
        // options for controlling the display of the table.  Additional
        // options for controlling the display of the table.  Additional
        // documentation can be found here:
        // documentation can be found here:
@@ -76,7 +110,7 @@ if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
          'colgroups' => array(),
          'colgroups' => array(),
          'empty' => '',
          'empty' => '',
        );
        );
-       
+
        // once we have our table array structure defined, we call Drupal's theme_table()
        // once we have our table array structure defined, we call Drupal's theme_table()
        // function to generate the table.
        // function to generate the table.
        print theme_table($table); ?>
        print theme_table($table); ?>
@@ -84,22 +118,55 @@ if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
        <br><?php
        <br><?php
      }
      }
   }
   }
-  
-  // second add in the object relationships.  
+
+  // second add in the object relationships.
   foreach ($object_rels as $rel_type => $rels){
   foreach ($object_rels as $rel_type => $rels){
-    foreach ($rels as $subject_type => $subjects){?>
-      <p>The following <b><?php print $subjects[0]->record->subject_id->type_id->name ?></b> feature(s) are <?php print $rel_type ?> this <?php print $feature->type_id->name;?>: <?php 
+    foreach ($rels as $subject_type => $subjects){
+
+      // Make the verb in the sentence make sense in English.
+      switch ($rel_type) {
+        case 'integral part of':
+        case 'instance of':
+          $verb = 'are an';
+          break;
+        case 'proper part of':
+        case 'transformation of':
+        case 'genome of':
+        case 'part of':
+        case 'position of':
+        case 'sequence of':
+        case 'variant of':
+          $verb = 'are a';
+          break;
+        case 'derives from':
+        case 'connects on':
+        case 'contains':
+        case 'finishes':
+        case 'guides':
+        case 'has origin':
+        case 'has part':
+        case 'has quality':
+        case 'is consecutive sequence of':
+        case 'maximally overlaps':
+        case 'overlaps':
+        case 'starts':
+          $verb = '';
+          break;
+        default:
+          $verb = 'are';
+      } ?>
+      <p>The following <b><?php print $subjects[0]->record->subject_id->type_id->name ?></b> feature(s) <?php print $verb ?> <?php print $rel_type ?> this <?php print $feature->type_id->name;?>: <?php
       // the $headers array is an array of fields to use as the colum headers.
       // the $headers array is an array of fields to use as the colum headers.
       // additional documentation can be found here
       // additional documentation can be found here
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
       $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
-      
+
       // the $rows array contains an array of rows where each row is an array
       // the $rows array contains an array of rows where each row is an array
       // of values for each column of the table in that row.  Additional documentation
       // of values for each column of the table in that row.  Additional documentation
       // can be found here:
       // can be found here:
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
       $rows = array();
       $rows = array();
-      
+
       foreach ($subjects as $subject){
       foreach ($subjects as $subject){
         // link the feature to it's node
         // link the feature to it's node
         $feature_name = $subject->record->subject_id->name;
         $feature_name = $subject->record->subject_id->name;
@@ -117,8 +184,8 @@ if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
           array('data' =>$subject->record->subject_id->uniquename, 'width' => '30%'),
           array('data' =>$subject->record->subject_id->uniquename, 'width' => '30%'),
           array('data' =>$organism_name, 'width' => '30%'),
           array('data' =>$organism_name, 'width' => '30%'),
           array('data' =>$subject->record->subject_id->type_id->name, 'width' => '10%'),
           array('data' =>$subject->record->subject_id->type_id->name, 'width' => '10%'),
-        ); 
-       } 
+        );
+       }
        // the $table array contains the headers and rows array as well as other
        // the $table array contains the headers and rows array as well as other
        // options for controlling the display of the table.  Additional
        // options for controlling the display of the table.  Additional
        // documentation can be found here:
        // documentation can be found here:
@@ -135,7 +202,7 @@ if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
          'colgroups' => array(),
          'colgroups' => array(),
          'empty' => '',
          'empty' => '',
        );
        );
-       
+
        // once we have our table array structure defined, we call Drupal's theme_table()
        // once we have our table array structure defined, we call Drupal's theme_table()
        // function to generate the table.
        // function to generate the table.
        print theme_table($table); ?>
        print theme_table($table); ?>

+ 106 - 121
tripal_feature/theme/templates/tripal_organism_feature_browser.tpl.php

@@ -5,141 +5,126 @@ $organism = $variables['node']->organism;
 // get the list of available sequence ontology terms for which
 // get the list of available sequence ontology terms for which
 // we will build drupal pages from features in chado.  If a feature
 // we will build drupal pages from features in chado.  If a feature
 // is not one of the specified typse we won't build a node for it.
 // is not one of the specified typse we won't build a node for it.
-$allowed_types = variable_get('chado_browser_feature_types', 'gene mRNA');
+$allowed_types = variable_get('chado_browser_feature_types');
 $allowed_types = preg_replace("/[\s\n\r]+/", " ", $allowed_types);
 $allowed_types = preg_replace("/[\s\n\r]+/", " ", $allowed_types);
 $so_terms = explode(' ', $allowed_types);
 $so_terms = explode(' ', $allowed_types);
 
 
-// get the feature_id's of the feature that belong to this organism.  But we only
-// want 25 and we want a pager to let the user cycle between pages of features.
-// so we, use the chado_select_record API function to get the results and
-// generate the pager.  The function is smart enough to know which page the user is
-// on and retrieves the proper set of features
-$element = 0;        // an index to specify the pager if more than one is on the page
-$num_per_page = 25;  // the number of features to show per page
-$values = array(
-  'organism_id' => $organism->organism_id,
-  'type_id' => array(
-    'name' => $so_terms
-  ),
-);
-$columns = array('feature_id');
-$options = array(
-  'pager' => array(
-    'limit' => $num_per_page,
-    'element' => $element
-   ),
-  'order_by' => array('name' => 'ASC'),
-);
-$results = chado_select_record('feature', $columns, $values, $options);
+// Don't show the browser if there are no terms
+if (count($so_terms) > 0) {
 
 
-// now that we have all of the feature IDs, we want to expand each one so that we
-// have all of the neccessary values, including the node ID, if one exists, and the
-// cvterm type name.
-$features = array();
-foreach ($results as $result) {
-  $values = array('feature_id' => $result->feature_id);
+  // get the feature_id's of the feature that belong to this organism.  But we only
+  // want 25 and we want a pager to let the user cycle between pages of features.
+  // so we, use the chado_select_record API function to get the results and
+  // generate the pager.  The function is smart enough to know which page the user is
+  // on and retrieves the proper set of features
+  $element = 0;        // an index to specify the pager if more than one is on the page
+  $num_per_page = 25;  // the number of features to show per page
+  $values = array(
+    'organism_id' => $organism->organism_id,
+    'type_id' => array(
+      'name' => $so_terms
+    ),
+  );
+  $columns = array('feature_id');
   $options = array(
   $options = array(
-    'include_fk' => array(
-      'type_id' => 1
-    )
+    'pager' => array(
+      'limit' => $num_per_page,
+      'element' => $element
+     ),
+    'order_by' => array('name' => 'ASC'),
   );
   );
-  $features[] = chado_generate_var('feature', $values, $options);
-}
+  $results = chado_select_record('feature', $columns, $values, $options);
 
 
-if (count($features) > 0) { ?>
-  <div class="tripal_organism-data-block-desc tripal-data-block-desc">The following browser provides a quick view for new visitors.  Use the searching mechanism to find specific features.</div> <?php
+  // now that we have all of the feature IDs, we want to expand each one so that we
+  // have all of the neccessary values, including the node ID, if one exists, and the
+  // cvterm type name.
+  $features = array();
+  foreach ($results as $result) {
+    $values = array('feature_id' => $result->feature_id);
+    $options = array(
+      'include_fk' => array(
+        'type_id' => 1
+      )
+    );
+    $features[] = chado_generate_var('feature', $values, $options);
+  }
 
 
-  // the $headers array is an array of fields to use as the colum headers.
-  // additional documentation can be found here
-  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
-  $headers = array('Feature Name' ,'Unique Name', 'Type');
+  if (count($features) > 0) { ?>
+    <div class="tripal_organism-data-block-desc tripal-data-block-desc">The following browser provides a quick view for new visitors.  Use the searching mechanism to find specific features.</div> <?php
 
 
-  // the $rows array contains an array of rows where each row is an array
-  // of values for each column of the table in that row.  Additional documentation
-  // can be found here:
-  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
-  $rows = array();
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Feature Name' ,'Unique Name', 'Type');
 
 
-  // let admins know they can customize the terms that appear in the list
-  print tripal_set_message("Administrators, you can specify the feature types ".
-    "that should appear in this browser or remove it from the list of resources ".
-    "by navigating to the ".
-    l("Tripal feature settings page", "admin/tripal/chado/tripal_feature/configuration", array('attributes' => array('target' => '_blank'))),
-    TRIPAL_INFO,
-    array('return_html' => 1)
-  );
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+
+    // let admins know they can customize the terms that appear in the list
+    print tripal_set_message("Administrators, you can specify the feature types ".
+      "that should appear in this browser or remove it from the list of resources ".
+      "by navigating to the ".
+      l("Tripal feature settings page", "admin/tripal/chado/tripal_feature/configuration", array('attributes' => array('target' => '_blank'))),
+      TRIPAL_INFO,
+      array('return_html' => 1)
+    );
 
 
-  foreach ($features as $feature){
-    $fname =  $feature->name;
-    if (property_exists($feature, 'nid')) {
-      $fname =   l($fname, "node/$feature->nid", array('attributes' => array('target' => '_blank')));
+    foreach ($features as $feature){
+      $fname =  $feature->name;
+      if (property_exists($feature, 'nid')) {
+        $fname =   l($fname, "node/$feature->nid", array('attributes' => array('target' => '_blank')));
+      }
+      $rows[] = array(
+        $fname,
+        $feature->uniquename,
+        $feature->type_id->name
+      );
     }
     }
-    $rows[] = array(
-      $fname,
-      $feature->uniquename,
-      $feature->type_id->name
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_organism-table-features',
+        'class' => 'tripal-data-table'
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
     );
     );
-  }
-  // the $table array contains the headers and rows array as well as other
-  // options for controlling the display of the table.  Additional
-  // documentation can be found here:
-  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
-  $table = array(
-    'header' => $headers,
-    'rows' => $rows,
-    'attributes' => array(
-      'id' => 'tripal_organism-table-features',
-      'class' => 'tripal-data-table'
-    ),
-    'sticky' => FALSE,
-    'caption' => '',
-    'colgroups' => array(),
-    'empty' => '',
-  );
-  // once we have our table array structure defined, we call Drupal's theme_table()
-  // function to generate the table.
-  print theme_table($table);
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table);
 
 
-  // the $pager array values that control the behavior of the pager.  For
-  // documentation on the values allows in this array see:
-  // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
-  // here we add the paramter 'block' => 'feature_browser'. This is because
-  // the pager is not on the default block that appears. When the user clicks a
-  // page number we want the browser to re-appear with the page is loaded.
-  $pager = array(
-    'tags' => array(),
-    'element' => $element,
-    'parameters' => array(
-      'block' => 'feature_browser'
-    ),
-    'quantity' => $num_per_page,
-  );
-  print theme_pager($pager);
-}
-else {  ?>
-  <p>There are no results.</p><?php
-  print tripal_set_message("
-    Administrators, perform the following to show features in this browser:
-    <ul>
-      <li>Load features for this organism using the " .
-        l("FASTA loader", 'admin/tripal/loaders/fasta_loader') . ",  ".
-        l("GFF Loader",   'admin/tripal/loaders/gff3_load') . " or ".
-        l("Bulk Loader",  'admin/tripal/loaders/bulk'). "</li>
-      <li>Sync the features that should have pages using the ".
-        l("Sync features page", 'admin/tripal/chado/tripal_feature/sync'). "</li>
-      <li>Return to this page to browse features.</li>
-      <li>Ensure the user " .
-       l("has permission", 'admin/people/permissions') . " to view the feature content</li>
-    </ul>
-    <br>
-    <br>
-    You can specify the feature types
-    that should appear in this browser or remove it from the list of resources by navigating to the " .
-    l("Tripal feature settings page", "admin/tripal/chado/tripal_feature/configuration", array('attributes' => array('target' => '_blank')))  . "
-    The feature browser will not appear to site visitors unless features are present. ",
-    TRIPAL_INFO,
-    array('return_html' => 1));
-}
+    // the $pager array values that control the behavior of the pager.  For
+    // documentation on the values allows in this array see:
+    // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
+    // here we add the paramter 'block' => 'feature_browser'. This is because
+    // the pager is not on the default block that appears. When the user clicks a
+    // page number we want the browser to re-appear with the page is loaded.
+    $pager = array(
+      'tags' => array(),
+      'element' => $element,
+      'parameters' => array(
+        'block' => 'feature_browser'
+      ),
+      'quantity' => $num_per_page,
+    );
+    print theme_pager($pager);
 
 
+    print tripal_set_message("
+      Administrators, please note that the feature browser will be retired in
+      a future version of Tripal.",
+      TRIPAL_INFO,
+      array('return_html' => 1));
+  }
+}
 
 
 
 

+ 121 - 8
tripal_feature/theme/tripal_feature.theme.inc

@@ -1,4 +1,4 @@
-<?php 
+<?php
 
 
 
 
 /**
 /**
@@ -27,9 +27,9 @@ function tripal_feature_preprocess_tripal_feature_sequence(&$variables) {
   // now extract the sequences
   // now extract the sequences
   $featureloc_sequences = tripal_feature_load_featureloc_sequences($feature->feature_id, $ffeaturelocs);
   $featureloc_sequences = tripal_feature_load_featureloc_sequences($feature->feature_id, $ffeaturelocs);
   $feature->featureloc_sequences = $featureloc_sequences;
   $feature->featureloc_sequences = $featureloc_sequences;
-  
+
   // if this feature has associated protein sequences (or others via relationships
   // if this feature has associated protein sequences (or others via relationships
-  // then we want to make sure the relationships are added so that we can 
+  // then we want to make sure the relationships are added so that we can
   // show the protein sequences
   // show the protein sequences
   if (!$feature->all_relationships) {
   if (!$feature->all_relationships) {
     $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
     $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
@@ -145,7 +145,7 @@ function tripal_feature_load_featureloc_sequences($feature_id, $featurelocs) {
       $args = array(':feature_id' => $featureloc->srcfeature_id->feature_id);
       $args = array(':feature_id' => $featureloc->srcfeature_id->feature_id);
       $start = $featureloc->fmin + 1;
       $start = $featureloc->fmin + 1;
       $size = $featureloc->fmax - $featureloc->fmin;
       $size = $featureloc->fmax - $featureloc->fmin;
-      
+
       // TODO: fix the hard coded $start and $size
       // TODO: fix the hard coded $start and $size
       // the $start and $size variables are hard-coded in the SQL statement
       // the $start and $size variables are hard-coded in the SQL statement
       // because the db_query function places quotes around all placeholders
       // because the db_query function places quotes around all placeholders
@@ -852,11 +852,11 @@ function tripal_feature_get_feature_relationships($feature) {
         }
         }
       }
       }
       $rel->record = $relationship;
       $rel->record = $relationship;
-       
+
       // get the relationship and child types
       // get the relationship and child types
       $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
       $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
       $child_type = $relationship->subject_id->type_id->name;
       $child_type = $relationship->subject_id->type_id->name;
-       
+
       // get the node id of the subject
       // get the node id of the subject
       $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
       $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
       $n = db_query($sql, array(':feature_id' => $relationship->subject_id->feature_id))->fetchObject();
       $n = db_query($sql, array(':feature_id' => $relationship->subject_id->feature_id))->fetchObject();
@@ -893,14 +893,14 @@ function tripal_feature_get_feature_relationships($feature) {
       $rel->record = $relationship;
       $rel->record = $relationship;
       $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
       $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
       $parent_type = $relationship->object_id->type_id->name;
       $parent_type = $relationship->object_id->type_id->name;
-       
+
       // get the node id of the subject
       // get the node id of the subject
       $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
       $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
       $n = db_query($sql, array(':feature_id' => $relationship->object_id->feature_id))->fetchObject();
       $n = db_query($sql, array(':feature_id' => $relationship->object_id->feature_id))->fetchObject();
       if ($n) {
       if ($n) {
         $rel->record->nid = $n->nid;
         $rel->record->nid = $n->nid;
       }
       }
-       
+
       if (!array_key_exists($rel_type, $relationships['subject'])) {
       if (!array_key_exists($rel_type, $relationships['subject'])) {
         $relationships['subject'][$rel_type] = array();
         $relationships['subject'][$rel_type] = array();
       }
       }
@@ -912,3 +912,116 @@ function tripal_feature_get_feature_relationships($feature) {
   }
   }
   return $relationships;
   return $relationships;
 }
 }
+
+/**
+ *
+ */
+function tripal_feature_preprocess_tripal_feature_bar_chart_type_organism_summary(&$vars) {
+
+  // Add in all the javascript/css files.
+  tripal_add_d3js();
+  drupal_add_css(drupal_get_path('module','tripal_feature') . '/theme/css/tripal_feature.css');
+  drupal_add_js(drupal_get_path('module','tripal_feature') . '/theme/js/tripalFeature.adminChart.js');
+
+  // Retrieve and process all the data and save it as javascript settings.
+  //'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+  // We are using the organism_feature_count materialized view as the source for our data.
+  // Thus grab all the records from this materialized view.
+  $organism_feature_count = chado_select_record(
+    'organism_feature_count',
+    array('*'),
+    array(),
+    array('order_by' => array('genus' => 'ASC', 'species' => 'ASC', 'feature_type' => 'ASC', 'num_features' => 'DESC'))
+  );
+
+  // Initialize variables.
+  $chart = array();
+  $type_names = array();
+  $organism_names = array();
+  $max_bar_height = 0;
+
+  // Process each row of the materialzied view into the chart array.
+  // Note: it's first keyed by type since each type will be a bar. Each type will have
+  // a "bars" array with the start (y0) and end (y1) height on the bar for a given
+  // organism. Finally we keep a record of the names of the types & organisms
+  // for axis' and legend generation respectively.
+  foreach ($organism_feature_count as $row) {
+
+    // Build up the easy details for the current row's type. These will be overridden
+    // multiple times but that's more efficient than checking each time.
+    $chart[$row->cvterm_id]['cvterm_id'] = $row->cvterm_id;
+    $chart[$row->cvterm_id]['name'] = str_replace('_', ' ', $row->feature_type);
+
+    // Save the name of the type and organism into their respective arrays
+    // for generation of axis' and legends for the chart.
+    $type_names[$row->cvterm_id] = $row->feature_type;
+    $organism_names[$row->organism_id] = $row->genus . ' ' . $row->species;
+
+    // Save information about the current organism. This isn't actually used by the
+    // chart but can be used to debug the bar generation to follow.
+    $chart[$row->cvterm_id]['organisms'][] = array(
+      'name' => $row->genus . ' ' . $row->species,
+      'value' => (int) $row->num_features
+    );
+
+    // Now to build the bar array with the start (y0) and end (y1) height on the
+    // bar for a given organism.
+    // NOTE: we cannot assume the types are all in order so store y0 & y1 in the
+    // $chart[type] array.
+    // If y0 has not yet been set for this type then we're starting with the first
+    // chunk (organism) on the bar.
+    if (!isset($chart[$row->cvterm_id]['y0'])) {
+      $chart[$row->cvterm_id]['y0'] = 0;
+      $chart[$row->cvterm_id]['y1'] = $row->num_features;
+    }
+    // Otherwise, add the next chunk (organism) on top of the pre-existing bar.
+    else {
+      $chart[$row->cvterm_id]['y0'] = $chart[$row->cvterm_id]['y1'];
+      $chart[$row->cvterm_id]['y1'] = $chart[$row->cvterm_id]['y0'] + $row->num_features;
+    }
+    // Now save the bar chunk we just determined.
+    $chart[$row->cvterm_id]['bars'][] = array(
+      'name' => $row->genus . ' ' . $row->species,
+      'y0' => $chart[$row->cvterm_id]['y0'],
+      'y1' => $chart[$row->cvterm_id]['y1'],
+    );
+
+    // We also need to keep track of the total number of features for a single bar (Type).
+    $chart[$row->cvterm_id]['total_features'] = (int) $chart[$row->cvterm_id]['y1'];
+    // And the maximum "height" for all bars.
+    if ($max_bar_height < $chart[$row->cvterm_id]['total_features']) {
+      $max_bar_height = (int) $chart[$row->cvterm_id]['total_features'];
+    }
+  }
+
+  // Sort based on the total number of features.
+  // NOTE: This changes the keys so it's no longer the organism/type_id.
+  usort($chart, 'tripal_feature_admin_summary_sort');
+  sort($type_names);
+  sort($organism_names);
+
+  // We also need to add information about the materialized views
+  // so that admin can update it and know how recent the data is.
+  $mview = db_query('
+    SELECT mview_id, name, last_update
+    FROM tripal_mviews
+    WHERE mv_table=:mv_table',
+    array(':mv_table' => 'organism_feature_count')
+  )->fetchObject();
+
+  $vars['chart_details'] = array(
+    'summary' => $chart,
+    'types' => $type_names,
+    'organisms' => $organism_names,
+    'legendPosition' => 'top',
+    'maxBarHeight' => $max_bar_height,
+    'mviewUrl' => url('admin/tripal/schema/mviews/update/' . $mview->mview_id),
+    'mviewTable' => $mview->name,
+    'mviewLastUpdate' => $mview->last_update ? format_date($mview->last_update) : '',
+  );
+
+  // Save everything we just determined as a Drupal JS settings so that we have access to
+  // it in our js script.
+  drupal_add_js(array('tripalFeature' => array('admin' => $vars['chart_details'])), 'setting');
+}

+ 1 - 1
tripal_feature/tripal_feature.info

@@ -3,7 +3,7 @@ description = Supports the sequence (feature) tables of Chado by providing pages
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 stylesheets[all][] = theme/css/tripal_feature.css
 stylesheets[all][] = theme/css/tripal_feature.css
 scripts[]          = theme/js/tripal_feature.js
 scripts[]          = theme/js/tripal_feature.js

+ 140 - 35
tripal_feature/tripal_feature.install

@@ -48,19 +48,18 @@ function tripal_feature_requirements($phase) {
  * @ingroup tripal_feature
  * @ingroup tripal_feature
  */
  */
 function tripal_feature_install() {
 function tripal_feature_install() {
-  // create the module's data directory
-  tripal_create_files_dir('tripal_feature');
-
-  // add the materialized view
+  // Add the materialized view.
   tripal_feature_add_organism_count_mview();
   tripal_feature_add_organism_count_mview();
 
 
-  // create the temp table we will use for loading GFF files
-  tripal_cv_create_tripal_gff_temp();
+  // Add the custom tables.
+  tripal_feature_add_tripal_gff_temp_table();
+  tripal_feature_add_tripal_gffcds_temp_table();
+  tripal_feature_add_tripal_gffprotein_temp_table();
 
 
-  // add the vocabularies used by the feature module:
+  // Add the vocabularies used by the feature module.
   tripal_feature_add_cvs();
   tripal_feature_add_cvs();
 
 
-  // set the default vocabularies
+  // Set the default vocabularies.
   tripal_set_default_cv('feature', 'type_id', 'sequence');
   tripal_set_default_cv('feature', 'type_id', 'sequence');
   tripal_set_default_cv('featureprop', 'type_id', 'feature_property');
   tripal_set_default_cv('featureprop', 'type_id', 'feature_property');
   tripal_set_default_cv('feature_relationship', 'type_id', 'feature_relationship');
   tripal_set_default_cv('feature_relationship', 'type_id', 'feature_relationship');
@@ -75,36 +74,114 @@ function tripal_feature_uninstall() {
 
 
 }
 }
 
 
+function tripal_feature_add_tripal_gff_temp_table() {
+  $schema = array(
+    'table' => 'tripal_gff_temp',
+    'fields' => array(
+      'feature_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'organism_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'uniquename' => array(
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+      'type_name' => array(
+        'type' => 'varchar',
+        'length' => '1024',
+        'not null' => TRUE,
+      ),
+    ),
+    'indexes' => array(
+      'tripal_gff_temp_idx0' => array('feature_id'),
+      'tripal_gff_temp_idx0' => array('organism_id'),
+      'tripal_gff_temp_idx1' => array('uniquename'),
+    ),
+    'unique keys' => array(
+      'tripal_gff_temp_uq0' => array('feature_id'),
+      'tripal_gff_temp_uq1' => array('uniquename', 'organism_id', 'type_name'),
+    ),
+  );
+  chado_create_custom_table('tripal_gff_temp', $schema, TRUE);
+}
+
 /**
 /**
- * Create a temporary table used for loading gff3 files
  *
  *
- * @ingroup tripal_feature
  */
  */
-function tripal_cv_create_tripal_gff_temp() {
-  // the tripal_obo_temp table is used for temporary housing of records when loading OBO files
-  // we create it here using plain SQL because we want it to be in the chado schema but we
-  // do not want to use the Tripal Custom Table API because we don't want it to appear in the
-  // list of custom tables.  It needs to be available for the Tripal Chado API so we create it
-  // here and then define it in the tripal_cv/api/tripal_cv.schema.api.inc
-  if (!db_table_exists('chado.tripal_gff_temp')) {
-    $sql = "
-      CREATE TABLE {tripal_gff_temp} (
-        feature_id integer NOT NULL,
-        organism_id integer NOT NULL,
-        uniquename text NOT NULL,
-        type_name character varying(1024) NOT NULL,
-        CONSTRAINT tripal_gff_temp_uq0 UNIQUE (feature_id),
-        CONSTRAINT tripal_gff_temp_uq1 UNIQUE (uniquename, organism_id, type_name)
-      );
-    ";
-    chado_query($sql);
-    $sql = "CREATE INDEX tripal_gff_temp_idx0 ON {tripal_gff_temp} USING btree (feature_id)";
-    chado_query($sql);
-    $sql = "CREATE INDEX tripal_gff_temp_idx1 ON {tripal_gff_temp} USING btree (organism_id)";
-    chado_query($sql);
-    $sql = "CREATE INDEX tripal_gff_temp_idx2 ON {tripal_gff_temp} USING btree (uniquename)";
-    chado_query($sql);
-  }
+function tripal_feature_add_tripal_gffcds_temp_table($skip_recreate = TRUE) {
+  $schema = array(
+    'table' => 'tripal_gffcds_temp',
+    'fields' => array(
+      'feature_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'parent_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'phase' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'strand' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'fmin' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'fmax' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+    ),
+    'indexes' => array(
+      'tripal_gff_temp_idx0' => array('feature_id'),
+      'tripal_gff_temp_idx0' => array('parent_id'),
+    ),
+  );
+  chado_create_custom_table('tripal_gffcds_temp', $schema, $skip_recreate);
+}
+
+/**
+ *
+ */
+function tripal_feature_add_tripal_gffprotein_temp_table() {
+  $schema = array(
+    'table' => 'tripal_gffprotein_temp',
+    'fields' => array(
+      'feature_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'parent_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'fmin' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'fmax' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+    ),
+    'indexes' => array(
+      'tripal_gff_temp_idx0' => array('feature_id'),
+      'tripal_gff_temp_idx0' => array('parent_id'),
+    ),
+    'unique keys' => array(
+      'tripal_gff_temp_uq0' => array('feature_id'),
+    ),
+  );
+  chado_create_custom_table('tripal_gffprotein_temp', $schema, TRUE);
 }
 }
 
 
 /**
 /**
@@ -412,4 +489,32 @@ function tripal_feature_update_7201() {
     $error = $e->getMessage();
     $error = $e->getMessage();
     throw new DrupalUpdateException('Failed to complete update' . $error);
     throw new DrupalUpdateException('Failed to complete update' . $error);
   }
   }
+}
+
+/**
+ * Adds the temporary tables used for loading GFF files.
+ */
+function tripal_feature_update_7202() {
+  try {
+    tripal_feature_add_tripal_gff_temp_table();
+    tripal_feature_add_tripal_gffcds_temp_table();
+    tripal_feature_add_tripal_gffprotein_temp_table();
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Failed to complete update' . $error);
+  }
+}
+
+/**
+ * Removes the unique constraint on the tripal_gffcds_temp table.
+ */
+function tripal_feature_update_7203() {
+  try {
+    tripal_feature_add_tripal_gffcds_temp_table(FALSE);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Failed to complete update' . $error);
+  }
 }
 }

+ 42 - 33
tripal_feature/tripal_feature.module

@@ -13,7 +13,6 @@
  */
  */
 
 
 require_once 'api/tripal_feature.api.inc';
 require_once 'api/tripal_feature.api.inc';
-require_once 'api/tripal_feature.schema.api.inc';
 require_once 'api/tripal_feature.DEPRECATED.inc';
 require_once 'api/tripal_feature.DEPRECATED.inc';
 
 
 require_once 'theme/tripal_feature.theme.inc';
 require_once 'theme/tripal_feature.theme.inc';
@@ -170,7 +169,7 @@ function tripal_feature_menu() {
     'access arguments' => array('administer tripal feature'),
     'access arguments' => array('administer tripal feature'),
     'type' => MENU_LOCAL_TASK,
     'type' => MENU_LOCAL_TASK,
     'file' =>  'includes/tripal_core.toc.inc',
     'file' =>  'includes/tripal_core.toc.inc',
-    'file path' => drupal_get_path('module', 'tripal_core'), 
+    'file path' => drupal_get_path('module', 'tripal_core'),
     'weight' => 3
     'weight' => 3
   );
   );
   $items['admin/tripal/chado/tripal_feature/configuration'] = array(
   $items['admin/tripal/chado/tripal_feature/configuration'] = array(
@@ -250,6 +249,7 @@ function tripal_feature_search_biological_data_views() {
 function tripal_feature_theme($existing, $type, $theme, $path) {
 function tripal_feature_theme($existing, $type, $theme, $path) {
   $core_path = drupal_get_path('module', 'tripal_core');
   $core_path = drupal_get_path('module', 'tripal_core');
 
 
+  // Feature Node Page Templates.
   $items = array(
   $items = array(
     'node__chado_feature' => array(
     'node__chado_feature' => array(
       'template' => 'node--chado-generic',
       'template' => 'node--chado-generic',
@@ -312,36 +312,46 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
       'template' => 'tripal_feature_relationships',
       'template' => 'tripal_feature_relationships',
       'path' => "$path/theme/templates",
       'path' => "$path/theme/templates",
     ),
     ),
-    // help template
-    'tripal_feature_help' => array(
-      'template' => 'tripal_feature_help',
-      'variables' =>  array(NULL),
-      'path' => "$path/theme/templates"
-    ),
+  );
 
 
-    // template for the organism page
-    'tripal_organism_feature_browser' => array(
-      'variables' => array('node' => NULL),
-      'template' => 'tripal_organism_feature_browser',
-      'path' => "$path/theme/templates",
-    ),
-    'tripal_organism_feature_counts' => array(
-      'variables' => array('node' => NULL),
-      'template' => 'tripal_organism_feature_counts',
-      'path' => "$path/theme/templates",
-    ),
+  // Feature Node Teaser
+  $items['tripal_feature_teaser'] = array(
+    'variables' => array('node' => NULL),
+    'template' => 'tripal_feature_teaser',
+    'path' => "$path/theme/templates",
+  );
 
 
-    // themed forms
-    'tripal_feature_seq_extract_form' => array(
-       'arguments' => array('form'),
-    ),
+  // Templates for other node pages.
+  // Organism Feature Browser.
+  $items['tripal_organism_feature_browser'] = array(
+    'variables' => array('node' => NULL),
+    'template' => 'tripal_organism_feature_browser',
+    'path' => "$path/theme/templates",
+  );
+  $items['tripal_organism_feature_counts'] = array(
+    'variables' => array('node' => NULL),
+    'template' => 'tripal_organism_feature_counts',
+    'path' => "$path/theme/templates",
+  );
 
 
-    // themed teaser
-    'tripal_feature_teaser' => array(
-      'variables' => array('node' => NULL),
-      'template' => 'tripal_feature_teaser',
-      'path' => "$path/theme/templates",
-    ),
+  // Administrative Help Template.
+  $items['tripal_feature_help'] = array(
+    'template' => 'tripal_feature_help',
+    'variables' =>  array(NULL),
+    'path' => "$path/theme/templates"
+  );
+
+  // Themed Forms
+  $items['tripal_feature_seq_extract_form'] = array(
+     'arguments' => array('form'),
+  );
+
+  // D3 Charts.
+  // Feature Type/Organism Stacked Bar Chart.
+  $items['tripal_feature_bar_chart_type_organism_summary'] = array(
+    'template' => 'tripal_feature_bar_chart_type_organism_summary',
+    'variables' =>  array(NULL),
+    'path' => "$path/theme/templates"
   );
   );
 
 
   return $items;
   return $items;
@@ -401,9 +411,8 @@ function tripal_feature_job_describe_args($callback, $args) {
     }
     }
 
 
     $new_args['Sequence Type'] = $args[2];
     $new_args['Sequence Type'] = $args[2];
-    $new_args['Is Unique Name'] = $args[3];
+    $new_args['Is Unique Name'] = $args[3] ? 'Yes' : 'No';
     $new_args['Features Names'] = $args[4];
     $new_args['Features Names'] = $args[4];
-
   }
   }
   elseif ($callback == 'tripal_feature_load_gff3') {
   elseif ($callback == 'tripal_feature_load_gff3') {
 
 
@@ -492,8 +501,8 @@ function tripal_feature_match_features_page($id) {
     GROUP BY F.name, F.uniquename, F.feature_id, O.genus, O.species,
     GROUP BY F.name, F.uniquename, F.feature_id, O.genus, O.species,
       O.organism_id, CVT.cvterm_id, CVT.name, CF.nid
       O.organism_id, CVT.cvterm_id, CVT.name, CF.nid
   ";
   ";
-  
-  $args = array(':uname' => $id, ':fname' => $id, ':sname' => $id); 
+
+  $args = array(':uname' => $id, ':fname' => $id, ':sname' => $id);
   $results = chado_query($sql, $args);
   $results = chado_query($sql, $args);
 
 
   $num_matches = 0;
   $num_matches = 0;

+ 10 - 14
tripal_feature/tripal_feature.views_default.inc

@@ -13,7 +13,7 @@ function tripal_feature_views_default_views() {
   $views = array();
   $views = array();
 
 
   // User View ("Search Biological Content")
   // User View ("Search Biological Content")
-  // Remember, if you change the name/path of this view, you also want to 
+  // Remember, if you change the name/path of this view, you also want to
   // change it's description in tripal_feature_search_biological_data_views()
   // change it's description in tripal_feature_search_biological_data_views()
   $view = tripal_feature_defaultvalue_user_features();
   $view = tripal_feature_defaultvalue_user_features();
   $view = tripal_make_view_compatible_with_external($view);
   $view = tripal_make_view_compatible_with_external($view);
@@ -286,7 +286,10 @@ function tripal_feature_defaultview_admin_features() {
   $handler->display->display_options['access']['perm'] = 'access chado_feature content';
   $handler->display->display_options['access']['perm'] = 'access chado_feature content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of features that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of features or to find a specific feature.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -472,18 +475,11 @@ function tripal_feature_defaultview_admin_features() {
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
-  /* Sort criterion: Chado Organism: Common Name */
-  $handler->display->display_options['sorts']['common_name']['id'] = 'common_name';
-  $handler->display->display_options['sorts']['common_name']['table'] = 'organism';
-  $handler->display->display_options['sorts']['common_name']['field'] = 'common_name';
-  /* Sort criterion: Chado Cvterm: Name */
-  $handler->display->display_options['sorts']['name']['id'] = 'name';
-  $handler->display->display_options['sorts']['name']['table'] = 'cvterm';
-  $handler->display->display_options['sorts']['name']['field'] = 'name';
-  /* Sort criterion: Chado Feature: Name */
-  $handler->display->display_options['sorts']['name_1']['id'] = 'name_1';
-  $handler->display->display_options['sorts']['name_1']['table'] = 'feature';
-  $handler->display->display_options['sorts']['name_1']['field'] = 'name';
+  /* Sort criterion: Chado Feature: Feature Id */
+  $handler->display->display_options['sorts']['feature_id']['id'] = 'feature_id';
+  $handler->display->display_options['sorts']['feature_id']['table'] = 'feature';
+  $handler->display->display_options['sorts']['feature_id']['field'] = 'feature_id';
+  $handler->display->display_options['sorts']['feature_id']['order'] = 'DESC';
   /* Filter criterion: Chado Organism: Common Name */
   /* Filter criterion: Chado Organism: Common Name */
   $handler->display->display_options['filters']['common_name']['id'] = 'common_name';
   $handler->display->display_options['filters']['common_name']['id'] = 'common_name';
   $handler->display->display_options['filters']['common_name']['table'] = 'organism';
   $handler->display->display_options['filters']['common_name']['table'] = 'organism';

+ 8 - 6
tripal_featuremap/includes/tripal_featuremap.chado_node.inc

@@ -100,7 +100,7 @@ function chado_featuremap_form($node, &$form_state) {
     '#maxlength'     => 255
     '#maxlength'     => 255
   );
   );
   $form['description']= array(
   $form['description']= array(
-    '#type'          => 'textarea',
+    '#type'          => 'text_format',
     '#title'         => t('Map Description'),
     '#title'         => t('Map Description'),
     '#description'   => t('A description of the map.'),
     '#description'   => t('A description of the map.'),
     '#required'      => TRUE,
     '#required'      => TRUE,
@@ -155,6 +155,9 @@ function chado_featuremap_form($node, &$form_state) {
  */
  */
 function chado_featuremap_validate($node, $form, &$form_state) {
 function chado_featuremap_validate($node, $form, &$form_state) {
 
 
+  if ($node->unittype_id == 0) {
+    form_set_error('unittype_id', 'Please provide a unit type for this map.');
+  }
   // We only want to validate when the node is saved.
   // We only want to validate when the node is saved.
   // Since this validate can be called on AJAX and Deletion of the node
   // Since this validate can be called on AJAX and Deletion of the node
   // we need to make this check to ensure queries are not executed
   // we need to make this check to ensure queries are not executed
@@ -171,7 +174,6 @@ function chado_featuremap_validate($node, $form, &$form_state) {
 
 
   // trim white space from text fields
   // trim white space from text fields
   $node->fmapname = property_exists($node, 'fmapname') ? trim($node->fmapname) : '';
   $node->fmapname = property_exists($node, 'fmapname') ? trim($node->fmapname) : '';
-  $node->description = property_exists($node, 'description') ? trim($node->description) : '';
 
 
   $featuremap = 0;
   $featuremap = 0;
   // check to make sure the unique name on the map is unique
   // check to make sure the unique name on the map is unique
@@ -268,8 +270,8 @@ function chado_featuremap_insert($node) {
   // we do need to proceed with insertion into the chado/drupal linking table.
   // we do need to proceed with insertion into the chado/drupal linking table.
   if (!property_exists($node, 'featuremap_id')) {
   if (!property_exists($node, 'featuremap_id')) {
 
 
-    $node->fmapname       = trim($node->fmapname);
-    $node->description    = trim($node->description);
+    $node->fmapname = trim($node->fmapname);
+    $node->description  = trim($node->description['value']);
 
 
     $values = array(
     $values = array(
       'name'        => $node->fmapname,
       'name'        => $node->fmapname,
@@ -345,8 +347,8 @@ function chado_featuremap_insert($node) {
  */
  */
 function chado_featuremap_update($node) {
 function chado_featuremap_update($node) {
 
 
-  $node->fmapname          = trim($node->fmapname);
-  $node->description    = trim($node->description);
+  $node->fmapname  = trim($node->fmapname);
+  $node->description  = trim($node->description['value']);
 
 
   $featuremap_id = chado_get_id_from_nid('featuremap', $node->nid) ;
   $featuremap_id = chado_get_id_from_nid('featuremap', $node->nid) ;
 
 

+ 1 - 1
tripal_featuremap/tripal_featuremap.info

@@ -3,7 +3,7 @@ description = Supports the map tables of Chado by providing pages for viewing an
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 0 - 2
tripal_featuremap/tripal_featuremap.install

@@ -47,8 +47,6 @@ function tripal_featuremap_requirements($phase) {
  * @ingroup tripal_featuremap
  * @ingroup tripal_featuremap
  */
  */
 function tripal_featuremap_install() {
 function tripal_featuremap_install() {
-  // create the module's data directory
-  tripal_create_files_dir('tripal_featuremap');
 
 
   // add the featuremapprop table to Chado
   // add the featuremapprop table to Chado
   tripal_featuremap_add_custom_tables();
   tripal_featuremap_add_custom_tables();

+ 9 - 6
tripal_featuremap/tripal_featuremap.views_default.inc

@@ -95,8 +95,10 @@ function tripal_featuremap_defaultview_admin_featuremaps() {
   $handler->display->display_options['access']['perm'] = 'access chado_featuremap content';
   $handler->display->display_options['access']['perm'] = 'access chado_featuremap content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of feature maps that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of maps or to find a specific map.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -211,10 +213,11 @@ function tripal_featuremap_defaultview_admin_featuremaps() {
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
-  /* Sort criterion: Chado Featuremap: Name */
-  $handler->display->display_options['sorts']['name']['id'] = 'name';
-  $handler->display->display_options['sorts']['name']['table'] = 'featuremap';
-  $handler->display->display_options['sorts']['name']['field'] = 'name';
+  /* Sort criterion: Chado Featuremap: Id */
+  $handler->display->display_options['sorts']['featuremap_id']['id'] = 'featuremap_id';
+  $handler->display->display_options['sorts']['featuremap_id']['table'] = 'featuremap';
+  $handler->display->display_options['sorts']['featuremap_id']['field'] = 'featuremap_id';
+  $handler->display->display_options['sorts']['featuremap_id']['order'] = 'DESC';
   /* Filter criterion: Chado Featuremap: Name */
   /* Filter criterion: Chado Featuremap: Name */
   $handler->display->display_options['filters']['name_1']['id'] = 'name_1';
   $handler->display->display_options['filters']['name_1']['id'] = 'name_1';
   $handler->display->display_options['filters']['name_1']['table'] = 'featuremap';
   $handler->display->display_options['filters']['name_1']['table'] = 'featuremap';

+ 1 - 1
tripal_genetic/tripal_genetic.info

@@ -3,7 +3,7 @@ description = Supports the genetic tables of Chado by providing pages for viewin
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 9 - 2
tripal_genetic/tripal_genetic.views_default.inc

@@ -91,8 +91,10 @@ function tripal_genetic_defaultviews_admin_genotypes() {
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of genotypes that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of genotypes or to find a specific genotype.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -138,6 +140,11 @@ function tripal_genetic_defaultviews_admin_genotypes() {
   $handler->display->display_options['fields']['description']['id'] = 'description';
   $handler->display->display_options['fields']['description']['id'] = 'description';
   $handler->display->display_options['fields']['description']['table'] = 'genotype';
   $handler->display->display_options['fields']['description']['table'] = 'genotype';
   $handler->display->display_options['fields']['description']['field'] = 'description';
   $handler->display->display_options['fields']['description']['field'] = 'description';
+  /* Sort criterion: Chado Genotype: Id */
+  $handler->display->display_options['sorts']['genotype_id']['id'] = 'genotype_id';
+  $handler->display->display_options['sorts']['genotype_id']['table'] = 'genotype';
+  $handler->display->display_options['sorts']['genotype_id']['field'] = 'genotype_id';
+  $handler->display->display_options['sorts']['genotype_id']['order'] = 'DESC';
   /* Filter criterion: Chado Genotype: Uniquename */
   /* Filter criterion: Chado Genotype: Uniquename */
   $handler->display->display_options['filters']['uniquename']['id'] = 'uniquename';
   $handler->display->display_options['filters']['uniquename']['id'] = 'uniquename';
   $handler->display->display_options['filters']['uniquename']['table'] = 'genotype';
   $handler->display->display_options['filters']['uniquename']['table'] = 'genotype';

+ 3 - 4
tripal_library/includes/tripal_library.chado_node.inc

@@ -165,7 +165,7 @@ function chado_library_form($node, &$form_state) {
   );
   );
 
 
   $form['description']= array(
   $form['description']= array(
-    '#type'          => 'textarea',
+    '#type'          => 'text_format',
     '#title'         => t('Library Description'),
     '#title'         => t('Library Description'),
     '#description'   => t('A brief description of the library'),
     '#description'   => t('A brief description of the library'),
     '#required'      => TRUE,
     '#required'      => TRUE,
@@ -235,7 +235,6 @@ function chado_library_validate($node, $form, &$form_state) {
   // trim white space from text fields
   // trim white space from text fields
   $node->libraryname = property_exists($node, 'libraryname') ? trim($node->libraryname) : '';
   $node->libraryname = property_exists($node, 'libraryname') ? trim($node->libraryname) : '';
   $node->uniquename  = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
   $node->uniquename  = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
-  $node->description = property_exists($node, 'description') ? trim($node->description) : '';
 
 
   $lib = 0;
   $lib = 0;
   // check to make sure the unique name on the library is unique
   // check to make sure the unique name on the library is unique
@@ -276,7 +275,7 @@ function chado_library_insert($node) {
   if (!property_exists($node, 'library_id')) {
   if (!property_exists($node, 'library_id')) {
     $node->libraryname = trim($node->libraryname);
     $node->libraryname = trim($node->libraryname);
     $node->uniquename  = trim($node->uniquename);
     $node->uniquename  = trim($node->uniquename);
-    $node->description = trim($node->description);
+    $node->description  = trim($node->description['value']);
 
 
     $values = array(
     $values = array(
       'name' => $node->libraryname,
       'name' => $node->libraryname,
@@ -344,7 +343,7 @@ function chado_library_update($node) {
 
 
   $node->libraryname = trim($node->libraryname);
   $node->libraryname = trim($node->libraryname);
   $node->uniquename  = trim($node->uniquename);
   $node->uniquename  = trim($node->uniquename);
-  $node->description = trim($node->description);
+  $node->description  = trim($node->description['value']);
 
 
   // update the library record
   // update the library record
   $library_id = chado_get_id_from_nid('library', $node->nid);
   $library_id = chado_get_id_from_nid('library', $node->nid);

+ 1 - 1
tripal_library/tripal_library.info

@@ -3,7 +3,7 @@ description = Supports the library tables of Chado by providing pages for viewin
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 0 - 3
tripal_library/tripal_library.install

@@ -48,9 +48,6 @@ function tripal_library_requirements($phase) {
  */
  */
 function tripal_library_install() {
 function tripal_library_install() {
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_library');
-
   // add the materialized view
   // add the materialized view
   tripal_library_add_mview_library_feature_count();
   tripal_library_add_mview_library_feature_count();
 
 

+ 9 - 6
tripal_library/tripal_library.views_default.inc

@@ -95,7 +95,10 @@ function tripal_library_admin_defaultviews_library() {
   $handler->display->display_options['access']['perm'] = 'access chado_library content';
   $handler->display->display_options['access']['perm'] = 'access chado_library content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of libraries that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of libraries or to find a specific library.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -234,10 +237,11 @@ function tripal_library_admin_defaultviews_library() {
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
-  /* Sort criterion: Chado Library: Name */
-  $handler->display->display_options['sorts']['name']['id'] = 'name';
-  $handler->display->display_options['sorts']['name']['table'] = 'library';
-  $handler->display->display_options['sorts']['name']['field'] = 'name';
+  /* Sort criterion: Chado Library: Id */
+  $handler->display->display_options['sorts']['library_id']['id'] = 'library_id';
+  $handler->display->display_options['sorts']['library_id']['table'] = 'library';
+  $handler->display->display_options['sorts']['library_id']['field'] = 'library_id';
+  $handler->display->display_options['sorts']['library_id']['order'] = 'DESC';
   /* Filter criterion: Chado Organism: Common Name */
   /* Filter criterion: Chado Organism: Common Name */
   $handler->display->display_options['filters']['common_name']['id'] = 'common_name';
   $handler->display->display_options['filters']['common_name']['id'] = 'common_name';
   $handler->display->display_options['filters']['common_name']['table'] = 'organism';
   $handler->display->display_options['filters']['common_name']['table'] = 'organism';
@@ -258,7 +262,6 @@ function tripal_library_admin_defaultviews_library() {
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['table'] = 'library';
   $handler->display->display_options['filters']['type_id']['table'] = 'library';
   $handler->display->display_options['filters']['type_id']['field'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['field'] = 'type_id';
-  $handler->display->display_options['filters']['type_id']['value'] = 'All';
   $handler->display->display_options['filters']['type_id']['group'] = '0';
   $handler->display->display_options['filters']['type_id']['group'] = '0';
   $handler->display->display_options['filters']['type_id']['exposed'] = TRUE;
   $handler->display->display_options['filters']['type_id']['exposed'] = TRUE;
   $handler->display->display_options['filters']['type_id']['expose']['operator_id'] = 'type_id_op';
   $handler->display->display_options['filters']['type_id']['expose']['operator_id'] = 'type_id_op';

+ 1 - 1
tripal_natural_diversity/tripal_natural_diversity.info

@@ -3,7 +3,7 @@ description = Supports the natural diversity (ND) tables of Chado by providing p
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 0 - 3
tripal_natural_diversity/tripal_natural_diversity.install

@@ -48,9 +48,6 @@ function tripal_natural_diversity_requirements($phase) {
  */
  */
 function tripal_natural_diversity_install() {
 function tripal_natural_diversity_install() {
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_natural_diversity');
-
   // add cvterms
   // add cvterms
   tripal_natural_diversity_add_cvterms();
   tripal_natural_diversity_add_cvterms();
 
 

+ 36 - 16
tripal_natural_diversity/tripal_natural_diversity.views_default.inc

@@ -59,8 +59,10 @@ function tripal_natural_diversity_defaultview_admin_natdiv_exp() {
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of natural diversity experiments that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of experiments or to find a specific experiment.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -99,14 +101,11 @@ function tripal_natural_diversity_defaultview_admin_natdiv_exp() {
   $handler->display->display_options['fields']['description']['table'] = 'nd_geolocation';
   $handler->display->display_options['fields']['description']['table'] = 'nd_geolocation';
   $handler->display->display_options['fields']['description']['field'] = 'description';
   $handler->display->display_options['fields']['description']['field'] = 'description';
   $handler->display->display_options['fields']['description']['label'] = 'Location Experiment Performed';
   $handler->display->display_options['fields']['description']['label'] = 'Location Experiment Performed';
-  /* Sort criterion: Chado Cvterm: Name */
-  $handler->display->display_options['sorts']['name']['id'] = 'name';
-  $handler->display->display_options['sorts']['name']['table'] = 'cvterm';
-  $handler->display->display_options['sorts']['name']['field'] = 'name';
-  /* Sort criterion: Chado Nd Geolocation: Description */
-  $handler->display->display_options['sorts']['description']['id'] = 'description';
-  $handler->display->display_options['sorts']['description']['table'] = 'nd_geolocation';
-  $handler->display->display_options['sorts']['description']['field'] = 'description';
+  /* Sort criterion: Chado Nd Experiment: Id */
+  $handler->display->display_options['sorts']['nd_experiment_id']['id'] = 'nd_experiment_id';
+  $handler->display->display_options['sorts']['nd_experiment_id']['table'] = 'nd_experiment';
+  $handler->display->display_options['sorts']['nd_experiment_id']['field'] = 'nd_experiment_id';
+  $handler->display->display_options['sorts']['nd_experiment_id']['order'] = 'DESC';
   /* Filter criterion: Chado Nd Experiment: Type Id */
   /* Filter criterion: Chado Nd Experiment: Type Id */
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['table'] = 'nd_experiment';
   $handler->display->display_options['filters']['type_id']['table'] = 'nd_experiment';
@@ -181,8 +180,10 @@ function tripal_natural_diversity_defaultview_admin_geolocations() {
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of natural diversity experiment locations that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of locations or to find a specific location.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -247,6 +248,11 @@ function tripal_natural_diversity_defaultview_admin_geolocations() {
   $handler->display->display_options['fields']['geodetic_datum']['id'] = 'geodetic_datum';
   $handler->display->display_options['fields']['geodetic_datum']['id'] = 'geodetic_datum';
   $handler->display->display_options['fields']['geodetic_datum']['table'] = 'nd_geolocation';
   $handler->display->display_options['fields']['geodetic_datum']['table'] = 'nd_geolocation';
   $handler->display->display_options['fields']['geodetic_datum']['field'] = 'geodetic_datum';
   $handler->display->display_options['fields']['geodetic_datum']['field'] = 'geodetic_datum';
+  /* Sort criterion: Chado Nd Geolocation: Id */
+  $handler->display->display_options['sorts']['nd_geolocation_id']['id'] = 'nd_geolocation_id';
+  $handler->display->display_options['sorts']['nd_geolocation_id']['table'] = 'nd_geolocation';
+  $handler->display->display_options['sorts']['nd_geolocation_id']['field'] = 'nd_geolocation_id';
+  $handler->display->display_options['sorts']['nd_geolocation_id']['order'] = 'DESC';
   /* Filter criterion: Chado Nd Geolocation: Geodetic Datum */
   /* Filter criterion: Chado Nd Geolocation: Geodetic Datum */
   $handler->display->display_options['filters']['geodetic_datum']['id'] = 'geodetic_datum';
   $handler->display->display_options['filters']['geodetic_datum']['id'] = 'geodetic_datum';
   $handler->display->display_options['filters']['geodetic_datum']['table'] = 'nd_geolocation';
   $handler->display->display_options['filters']['geodetic_datum']['table'] = 'nd_geolocation';
@@ -355,8 +361,10 @@ function tripal_natural_diversity_defaultview_admin_reagents() {
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of natural diversity protocol reagents that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of reagents or to find a specific reagent.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -378,6 +386,11 @@ function tripal_natural_diversity_defaultview_admin_reagents() {
   $handler->display->display_options['fields']['name']['table'] = 'cvterm';
   $handler->display->display_options['fields']['name']['table'] = 'cvterm';
   $handler->display->display_options['fields']['name']['field'] = 'name';
   $handler->display->display_options['fields']['name']['field'] = 'name';
   $handler->display->display_options['fields']['name']['label'] = 'Type';
   $handler->display->display_options['fields']['name']['label'] = 'Type';
+  /* Sort criterion: Chado Nd Reagent: Id */
+  $handler->display->display_options['sorts']['nd_reagent_id']['id'] = 'nd_reagent_id';
+  $handler->display->display_options['sorts']['nd_reagent_id']['table'] = 'nd_reagent';
+  $handler->display->display_options['sorts']['nd_reagent_id']['field'] = 'nd_reagent_id';
+  $handler->display->display_options['sorts']['nd_reagent_id']['order'] = 'DESC';
   /* Filter criterion: Chado Nd Reagent: Type Id */
   /* Filter criterion: Chado Nd Reagent: Type Id */
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['id'] = 'type_id';
   $handler->display->display_options['filters']['type_id']['table'] = 'nd_reagent';
   $handler->display->display_options['filters']['type_id']['table'] = 'nd_reagent';
@@ -462,8 +475,10 @@ function tripal_natural_diversity_defaultview_admin_protocols() {
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['access']['type'] = 'perm';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of natural diversity experiment protocols that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of protocols or to find a specific protocol.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'none';
   $handler->display->display_options['pager']['type'] = 'none';
   $handler->display->display_options['style_plugin'] = 'table';
   $handler->display->display_options['style_plugin'] = 'table';
   $handler->display->display_options['style_options']['grouping'] = '';
   $handler->display->display_options['style_options']['grouping'] = '';
@@ -487,6 +502,11 @@ function tripal_natural_diversity_defaultview_admin_protocols() {
   $handler->display->display_options['fields']['name']['id'] = 'name';
   $handler->display->display_options['fields']['name']['id'] = 'name';
   $handler->display->display_options['fields']['name']['table'] = 'nd_protocol';
   $handler->display->display_options['fields']['name']['table'] = 'nd_protocol';
   $handler->display->display_options['fields']['name']['field'] = 'name';
   $handler->display->display_options['fields']['name']['field'] = 'name';
+  /* Sort criterion: Chado Nd Protocol: Id */
+  $handler->display->display_options['sorts']['nd_protocol_id']['id'] = 'nd_protocol_id';
+  $handler->display->display_options['sorts']['nd_protocol_id']['table'] = 'nd_protocol';
+  $handler->display->display_options['sorts']['nd_protocol_id']['field'] = 'nd_protocol_id';
+  $handler->display->display_options['sorts']['nd_protocol_id']['order'] = 'DESC';
   /* Filter criterion: Chado Nd Protocol: Name */
   /* Filter criterion: Chado Nd Protocol: Name */
   $handler->display->display_options['filters']['name']['id'] = 'name';
   $handler->display->display_options['filters']['name']['id'] = 'name';
   $handler->display->display_options['filters']['name']['table'] = 'nd_protocol';
   $handler->display->display_options['filters']['name']['table'] = 'nd_protocol';

+ 38 - 2
tripal_organism/api/tripal_organism.api.inc

@@ -153,7 +153,6 @@ function tripal_get_organism_select_options($syncd_only = TRUE) {
 
 
     // iterate through the organisms and build an array of those that are synced
     // iterate through the organisms and build an array of those that are synced
     foreach ($orgs as $org) {
     foreach ($orgs as $org) {
-      $args = array(':organism_id' => $org->organism_id);
       $org_list[$org->organism_id] = $org->genus . ' ' . $org->species;
       $org_list[$org->organism_id] = $org->genus . ' ' . $org->species;
     }
     }
   }
   }
@@ -182,7 +181,7 @@ function tripal_get_organism_select_options($syncd_only = TRUE) {
  */
  */
 function tripal_get_organism_image_url($organism) {
 function tripal_get_organism_image_url($organism) {
   $url = '';
   $url = '';
-  
+
   if (!is_object($organism)) {
   if (!is_object($organism)) {
     return NULL;
     return NULL;
   }
   }
@@ -230,3 +229,40 @@ function tripal_get_organism_image_url($organism) {
   return NULL;
   return NULL;
 }
 }
 
 
+/**
+ * This function is intended to be used in autocomplete forms
+ * for searching for organisms that begin with the provided string
+ *
+ * @param $text
+ *   The string to search for
+ *
+ * @return
+ *   A json array of terms that begin with the provided string
+ *
+ * @ingroup tripal_organism_api
+ */
+function tripal_autocomplete_organism($text) {
+  $matches = array();
+  $genus = $text;
+  $species = '';
+  if (preg_match('/^(.*?) (.*)$/', $text, $matches)) {
+    $genus = $matches[1];
+    $species = $matches[2];
+  }
+  $sql = "SELECT * FROM {organism} WHERE lower(genus) like lower(:genus) ";
+  $args = array();
+  $args[':genus'] = $genus . '%';
+  if ($species) {
+    $sql .= "AND lower(species) like lower(:species) ";
+    $args[':species'] =  $species . '%';
+  }
+  $sql .= "ORDER BY genus, species ";
+  $sql .= "LIMIT 25 OFFSET 0 ";
+  $results = chado_query($sql, $args);
+  $items = array();
+  foreach ($results as $organism) {
+    $name = $organism->genus . ' ' .$organism->species;
+    $items[$name] = $name;
+  }
+  drupal_json_output($items);
+}

+ 3 - 4
tripal_organism/includes/tripal_organism.chado_node.inc

@@ -166,7 +166,7 @@ function chado_organism_form($node, $form_state) {
     '#default_value' => $common_name,
     '#default_value' => $common_name,
   );
   );
   $form['description']= array(
   $form['description']= array(
-    '#type' => 'textarea',
+    '#type' => 'text_format',
     '#rows' => 15,
     '#rows' => 15,
     '#title' => t('Description'),
     '#title' => t('Description'),
     '#default_value' => $description,
     '#default_value' => $description,
@@ -235,7 +235,6 @@ function chado_organism_validate($node, $form, &$form_state) {
   $node->species      = property_exists($node, 'species') ? trim($node->species) : '';
   $node->species      = property_exists($node, 'species') ? trim($node->species) : '';
   $node->abbreviation = property_exists($node, 'abbreviation') ? trim($node->abbreviation) : '';
   $node->abbreviation = property_exists($node, 'abbreviation') ? trim($node->abbreviation) : '';
   $node->common_name  = property_exists($node, 'common_name') ? trim($node->common_name) : '';
   $node->common_name  = property_exists($node, 'common_name') ? trim($node->common_name) : '';
-  $node->description  = property_exists($node, 'description') ? trim($node->description) : '';
 
 
   // Validating for an update
   // Validating for an update
   if (property_exists($node, 'organism_id')) {
   if (property_exists($node, 'organism_id')) {
@@ -296,7 +295,7 @@ function chado_organism_insert($node) {
     $node->species      = trim($node->species);
     $node->species      = trim($node->species);
     $node->abbreviation = trim($node->abbreviation);
     $node->abbreviation = trim($node->abbreviation);
     $node->common_name  = trim($node->common_name);
     $node->common_name  = trim($node->common_name);
-    $node->description  = trim($node->description);
+    $node->description  = trim($node->description['value']);
 
 
     $values = array(
     $values = array(
       'genus'        => $node->genus,
       'genus'        => $node->genus,
@@ -367,7 +366,7 @@ function chado_organism_update($node) {
   $node->species      = trim($node->species);
   $node->species      = trim($node->species);
   $node->abbreviation = trim($node->abbreviation);
   $node->abbreviation = trim($node->abbreviation);
   $node->common_name  = trim($node->common_name);
   $node->common_name  = trim($node->common_name);
-  $node->description  = trim($node->description);
+  $node->description  = trim($node->description['value']);
 
 
   $organism_id = chado_get_id_from_nid('organism', $node->nid);
   $organism_id = chado_get_id_from_nid('organism', $node->nid);
 
 

+ 1 - 1
tripal_organism/tripal_organism.info

@@ -3,7 +3,7 @@ description = Supports the organism tables of Chado by providing pages for viewi
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 configure = admin/tripal/chado/tripal_organism
 configure = admin/tripal/chado/tripal_organism
 
 
 stylesheets[all][] = theme/css/tripal_organism.css
 stylesheets[all][] = theme/css/tripal_organism.css

+ 0 - 7
tripal_organism/tripal_organism.install

@@ -27,13 +27,6 @@ function tripal_organism_disable() {
  * @ingroup tripal_organism
  * @ingroup tripal_organism
  */
  */
 function tripal_organism_install() {
 function tripal_organism_install() {
-
-  // create the module's data directory
-  tripal_create_files_dir('tripal_organism');
-
-  // create the directory where image files will be stored.  We create this
-  tripal_create_files_dir('tripal_organism', '/images');
-
   // cvs & cvterms
   // cvs & cvterms
   tripal_organism_add_cvs();
   tripal_organism_add_cvs();
   tripal_organism_add_cvterms();
   tripal_organism_add_cvterms();

+ 27 - 22
tripal_organism/tripal_organism.module

@@ -41,13 +41,13 @@ function tripal_organism_menu() {
   );
   );
 
 
   $items['admin/tripal/chado/tripal_organism/sync'] = array(
   $items['admin/tripal/chado/tripal_organism/sync'] = array(
-      'title' => ' Sync',
-      'description' => 'Create pages on this site for organisms stored in Chado',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('chado_node_sync_form', 'tripal_organism', 'chado_organism'),
-      'access arguments' => array('administer tripal organism'),
-      'type' => MENU_LOCAL_TASK,
-      'weight' => 1
+    'title' => ' Sync',
+    'description' => 'Create pages on this site for organisms stored in Chado',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('chado_node_sync_form', 'tripal_organism', 'chado_organism'),
+    'access arguments' => array('administer tripal organism'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 1
   );
   );
   $items['admin/tripal/chado/tripal_organism/delete'] = array(
   $items['admin/tripal/chado/tripal_organism/delete'] = array(
     'title' => ' Delete',
     'title' => ' Delete',
@@ -72,22 +72,22 @@ function tripal_organism_menu() {
     'weight' => 3
     'weight' => 3
   );
   );
   $items['admin/tripal/chado/tripal_organism/configuration'] = array(
   $items['admin/tripal/chado/tripal_organism/configuration'] = array(
-      'title' => 'Settings',
-      'description' => 'Manage integration of Chado organisms including associated features',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('tripal_organism_admin'),
-      'access arguments' => array('administer tripal organism'),
-      'type' => MENU_LOCAL_TASK,
-      'weight' => 5
+    'title' => 'Settings',
+    'description' => 'Manage integration of Chado organisms including associated features',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_organism_admin'),
+    'access arguments' => array('administer tripal organism'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 5
   );
   );
   $items['admin/tripal/chado/tripal_organism/help'] = array(
   $items['admin/tripal/chado/tripal_organism/help'] = array(
-      'title' => 'Help',
-      'description' => "A description of the Tripal Organism module including a short description of it's usage.",
-      'page callback' => 'theme',
-      'page arguments' => array('tripal_organism_help'),
-      'access arguments' => array('administer tripal organism'),
-      'type' => MENU_LOCAL_TASK,
-      'weight' => 10
+    'title' => 'Help',
+    'description' => "A description of the Tripal Organism module including a short description of it's usage.",
+    'page callback' => 'theme',
+    'page arguments' => array('tripal_organism_help'),
+    'access arguments' => array('administer tripal organism'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 10
   );
   );
   $items['admin/tripal/chado/tripal_organism/views/organisms/enable'] = array(
   $items['admin/tripal/chado/tripal_organism/views/organisms/enable'] = array(
     'title' => 'Enable Organism Administrative View',
     'title' => 'Enable Organism Administrative View',
@@ -96,7 +96,12 @@ function tripal_organism_menu() {
     'access arguments' => array('administer tripal organism'),
     'access arguments' => array('administer tripal organism'),
     'type' => MENU_CALLBACK,
     'type' => MENU_CALLBACK,
   );
   );
-
+  $items['admin/tripal/chado/tripal_organism/organism/auto_name/%'] = array(
+    'page callback' => 'tripal_autocomplete_organism',
+    'page arguments' => array(6),
+    'access arguments' => array('administer tripal organism'),
+    'type' => MENU_CALLBACK,
+  );
 
 
   return $items;
   return $items;
 }
 }

+ 4 - 2
tripal_organism/tripal_organism.views_default.inc

@@ -224,8 +224,10 @@ function tripal_organism_admin_defaultview_organisms() {
   $handler->display->display_options['access']['perm'] = 'administer tripal organism';
   $handler->display->display_options['access']['perm'] = 'administer tripal organism';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of organisms that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of organisms or to find a specific organism.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';

+ 1 - 1
tripal_phenotype/tripal_phenotype.info

@@ -3,7 +3,7 @@ description = Supports the phenotype tables of Chado by providing pages for view
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 9 - 2
tripal_phenotype/tripal_phenotype.views_default.inc

@@ -92,8 +92,10 @@ function tripal_phenotype_defaultview_admin_phenotypes() {
   $handler->display->display_options['access']['perm'] = 'administer tripal';
   $handler->display->display_options['access']['perm'] = 'administer tripal';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of phenotypes that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of phenotypes or to find a specific phenotype.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -175,6 +177,11 @@ function tripal_phenotype_defaultview_admin_phenotypes() {
   $handler->display->display_options['fields']['name']['field'] = 'name';
   $handler->display->display_options['fields']['name']['field'] = 'name';
   $handler->display->display_options['fields']['name']['relationship'] = 'assay_id_to_cvterm';
   $handler->display->display_options['fields']['name']['relationship'] = 'assay_id_to_cvterm';
   $handler->display->display_options['fields']['name']['label'] = 'Evidence Type';
   $handler->display->display_options['fields']['name']['label'] = 'Evidence Type';
+  /* Sort criterion: Chado Phenotype: Id */
+  $handler->display->display_options['sorts']['phenotype_id']['id'] = 'phenotype_id';
+  $handler->display->display_options['sorts']['phenotype_id']['table'] = 'phenotype';
+  $handler->display->display_options['sorts']['phenotype_id']['field'] = 'phenotype_id';
+  $handler->display->display_options['sorts']['phenotype_id']['order'] = 'DESC';
   /* Filter criterion: Chado Phenotype: Attr Id */
   /* Filter criterion: Chado Phenotype: Attr Id */
   $handler->display->display_options['filters']['attr_id']['id'] = 'attr_id';
   $handler->display->display_options['filters']['attr_id']['id'] = 'attr_id';
   $handler->display->display_options['filters']['attr_id']['table'] = 'phenotype';
   $handler->display->display_options['filters']['attr_id']['table'] = 'phenotype';

+ 3 - 4
tripal_project/includes/tripal_project.chado_node.inc

@@ -131,7 +131,7 @@ function chado_project_form(&$node, $form_state) {
   );
   );
 
 
   $form['description']= array(
   $form['description']= array(
-    '#type'          => 'textarea',
+    '#type'          => 'text_format',
     '#title'         => t('Project Description'),
     '#title'         => t('Project Description'),
     '#description'   => t('A brief description of the project'),
     '#description'   => t('A brief description of the project'),
     '#required'      => TRUE,
     '#required'      => TRUE,
@@ -212,7 +212,6 @@ function chado_project_validate($node, $form, &$form_state) {
 
 
   // trim white space from text fields
   // trim white space from text fields
   $node->title = property_exists($node, 'title') ? trim($node->title) : '';
   $node->title = property_exists($node, 'title') ? trim($node->title) : '';
-  $node->description = property_exists($node, 'description') ? trim($node->description) : '';
 
 
   $project = 0;
   $project = 0;
   // check to make sure the name on the project is unique
   // check to make sure the name on the project is unique
@@ -247,7 +246,7 @@ function chado_project_insert($node) {
   // we do need to proceed with insertion into the chado/drupal linking table.
   // we do need to proceed with insertion into the chado/drupal linking table.
   if (!property_exists($node, 'project_id')) {
   if (!property_exists($node, 'project_id')) {
     $node->title = trim($node->title);
     $node->title = trim($node->title);
-    $node->description = trim($node->description);
+    $node->description  = trim($node->description['value']);
 
 
     $values = array(
     $values = array(
       'name' => $node->title,
       'name' => $node->title,
@@ -348,7 +347,7 @@ function chado_project_delete($node) {
 function chado_project_update($node) {
 function chado_project_update($node) {
 
 
   $node->title = trim($node->title);
   $node->title = trim($node->title);
-  $node->description = trim($node->description);
+  $node->description  = trim($node->description['value']);
 
 
   // update the project and the description
   // update the project and the description
   $project_id = chado_get_id_from_nid('project', $node->nid) ;
   $project_id = chado_get_id_from_nid('project', $node->nid) ;

+ 1 - 1
tripal_project/tripal_project.info

@@ -3,7 +3,7 @@ description = Supports the project tables of Chado by providing pages for viewin
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 configure = admin/tripal/chado/tripal_project
 configure = admin/tripal/chado/tripal_project
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core

+ 0 - 3
tripal_project/tripal_project.install

@@ -48,9 +48,6 @@ function tripal_project_requirements($phase) {
  */
  */
 function tripal_project_install() {
 function tripal_project_install() {
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_project');
-
   tripal_project_add_cvs();
   tripal_project_add_cvs();
   tripal_project_add_cvterms();
   tripal_project_add_cvterms();
 
 

+ 9 - 1
tripal_project/tripal_project.views_default.inc

@@ -95,7 +95,10 @@ function tripal_project_defaultview_admin_projects() {
   $handler->display->display_options['access']['perm'] = 'administer tripal project';
   $handler->display->display_options['access']['perm'] = 'administer tripal project';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of projects that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of projects or to find a specific project.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['style_plugin'] = 'table';
   $handler->display->display_options['style_plugin'] = 'table';
@@ -220,6 +223,11 @@ function tripal_project_defaultview_admin_projects() {
   $handler->display->display_options['fields']['nothing']['element_class'] = 'short-column';
   $handler->display->display_options['fields']['nothing']['element_class'] = 'short-column';
   $handler->display->display_options['fields']['nothing']['element_label_class'] = 'short-column';
   $handler->display->display_options['fields']['nothing']['element_label_class'] = 'short-column';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
+  /* Sort criterion: Chado Project: Id */
+  $handler->display->display_options['sorts']['project_id']['id'] = 'project_id';
+  $handler->display->display_options['sorts']['project_id']['table'] = 'project';
+  $handler->display->display_options['sorts']['project_id']['field'] = 'project_id';
+  $handler->display->display_options['sorts']['project_id']['order'] = 'DESC';
   /* Filter criterion: Chado Project: Name */
   /* Filter criterion: Chado Project: Name */
   $handler->display->display_options['filters']['name']['id'] = 'name';
   $handler->display->display_options['filters']['name']['id'] = 'name';
   $handler->display->display_options['filters']['name']['table'] = 'project';
   $handler->display->display_options['filters']['name']['table'] = 'project';

+ 14 - 13
tripal_pub/api/tripal_pub.api.inc

@@ -75,7 +75,7 @@ function tripal_get_publication($identifiers, $options = array()) {
     unset($identifiers['property']);
     unset($identifiers['property']);
     $pub = chado_get_record_with_property(
     $pub = chado_get_record_with_property(
       array('table' => 'pub', 'base_records' => $identifiers),
       array('table' => 'pub', 'base_records' => $identifiers),
-      array('type_name' => $property), 
+      array('type_name' => $property),
       $options
       $options
     );
     );
   }
   }
@@ -84,21 +84,22 @@ function tripal_get_publication($identifiers, $options = array()) {
       $dbname = $matches[1];
       $dbname = $matches[1];
       $accession = $matches[2];
       $accession = $matches[2];
 
 
+      // First make sure the dbxref is present.
       $values = array(
       $values = array(
-        'dbxref_id' => array (
-          'accession' => $accession,
-          'db_id' => array(
-            'name' => $dbname
-          ),
+        'accession' => $accession,
+        'db_id' => array(
+          'name' => $dbname
         ),
         ),
       );
       );
-      $pub_dbxref = chado_select_record('pub_dbxref', array('pub_id'), $values);
-      if (count($pub_dbxref) > 0) {
-        $pub = chado_generate_var('pub', array('pub_id' => $pub_dbxref[0]->pub_id), $options);
+      $dbxref = chado_select_record('dbxref', array('dbxref_id'), $values);
+      if (count($dbxref) == 0) {
+        return FALSE;
       }
       }
-      else {
+      $pub_dbxref = chado_select_record('pub_dbxref', array('pub_id'), array('dbxref_id' => $dbxref[0]->dbxref_id));
+      if (count($pub_dbxref) == 0) {
         return FALSE;
         return FALSE;
       }
       }
+      $pub = chado_generate_var('pub', array('pub_id' => $pub_dbxref[0]->pub_id), $options);
     }
     }
     else {
     else {
       tripal_report_error('tripal_pub_api', TRIPAL_ERROR,
       tripal_report_error('tripal_pub_api', TRIPAL_ERROR,
@@ -215,13 +216,13 @@ function tripal_publication_exists($pub_details) {
     $pub_type = tripal_get_cvterm($identifiers);
     $pub_type = tripal_get_cvterm($identifiers);
   }
   }
   else {
   else {
-    tripal_report_error('tripal_pub', TRIPAL_ERROR, 
+    tripal_report_error('tripal_pub', TRIPAL_ERROR,
       "tripal_publication_exists(): The Publication Type is a " .
       "tripal_publication_exists(): The Publication Type is a " .
       "required property but is missing", array());
       "required property but is missing", array());
     return array();
     return array();
   }
   }
   if (!$pub_type) {
   if (!$pub_type) {
-    tripal_report_error('tripal_pub', TRIPAL_ERROR, 
+    tripal_report_error('tripal_pub', TRIPAL_ERROR,
      "tripal_publication_exists(): Cannot find publication type: '%type'",
      "tripal_publication_exists(): Cannot find publication type: '%type'",
       array('%type' => $pub_details['Publication Type'][0]));
       array('%type' => $pub_details['Publication Type'][0]));
     return array();
     return array();
@@ -238,7 +239,7 @@ function tripal_publication_exists($pub_details) {
   if (array_key_exists('Conference Name', $pub_details)) {
   if (array_key_exists('Conference Name', $pub_details)) {
     $series_name = substr($pub_details['Conference Name'], 0, 255);
     $series_name = substr($pub_details['Conference Name'], 0, 255);
   }
   }
-  
+
   // make sure the publication is unique using the prefereed import duplication check
   // make sure the publication is unique using the prefereed import duplication check
   $import_dups_check = variable_get('tripal_pub_import_duplicate_check', 'title_year_media');
   $import_dups_check = variable_get('tripal_pub_import_duplicate_check', 'title_year_media');
   $pubs = array();
   $pubs = array();

+ 31 - 24
tripal_pub/includes/tripal_pub.chado_node.inc

@@ -1,37 +1,41 @@
 <?php
 <?php
 /**
 /**
  * @file
  * @file
- * Implements the pub node content type
+ * Implements Drupal Node hooks to create the chado_analysis node content type.
+ *
+ * @ingroup tripal_pub
  */
  */
 
 
 /**
 /**
  * Implements hook_node_info().
  * Implements hook_node_info().
  *
  *
+ * Provide information to drupal about the node types that we're creating
+ * in this module
+ *
  * @ingroup tripal_pub
  * @ingroup tripal_pub
  */
  */
 function tripal_pub_node_info() {
 function tripal_pub_node_info() {
-
-  return array(
-    'chado_pub' => array(
-      'name'        => t('Publication'),
-      'base'        => 'chado_pub',
-      'description' => t('A publication from the Chado database'),
-      'has_title'   => TRUE,
-      'locked'      => TRUE,
-      'chado_node_api' => array(
-        'base_table' => 'pub',
-        'hook_prefix' => 'chado_pub',
-        'record_type_title' => array(
-          'singular' => t('Publication'),
-          'plural' => t('Publications')
-        ),
-        'sync_filters' => array(
-          'type_id' => FALSE,
-          'organism_id' => FALSE
-        ),
+  $nodes = array();
+  $nodes['chado_pub'] = array(
+    'name'        => t('Publication'),
+    'base'        => 'chado_pub',
+    'description' => t('A publication from the Chado database'),
+    'has_title'   => TRUE,
+    'locked'      => TRUE,
+    'chado_node_api' => array(
+      'base_table' => 'pub',
+      'hook_prefix' => 'chado_pub',
+      'record_type_title' => array(
+        'singular' => t('Publication'),
+        'plural' => t('Publications')
+      ),
+      'sync_filters' => array(
+        'type_id' => FALSE,
+        'organism_id' => FALSE,
       ),
       ),
     ),
     ),
   );
   );
+  return $nodes;
 }
 }
 
 
 /**
 /**
@@ -371,7 +375,7 @@ function chado_pub_validate($node, $form, &$form_state) {
     return;
     return;
   }
   }
 
 
-  // get the media name looking at the properties
+  // Get the media name looking at the properties
   $series_name = '';
   $series_name = '';
   $properties = chado_retrieve_node_form_properties($node);
   $properties = chado_retrieve_node_form_properties($node);
   foreach ($properties as $key => $prop_values) {
   foreach ($properties as $key => $prop_values) {
@@ -380,13 +384,16 @@ function chado_pub_validate($node, $form, &$form_state) {
     if ($prop_type[0]->name == 'Conference Name' or
     if ($prop_type[0]->name == 'Conference Name' or
         $prop_type[0]->name == 'Journal Name' or
         $prop_type[0]->name == 'Journal Name' or
         $prop_type[0]->name == 'Series Name') {
         $prop_type[0]->name == 'Series Name') {
-      $series_name = $prop_values[0];
+      $v = array_values($prop_values);
+      $series_name = $v[0];
     }
     }
     if ($prop_type[0]->name == 'Citation') {
     if ($prop_type[0]->name == 'Citation') {
-      $uniquename = $prop_values[0];
+      $v = array_values($prop_values);
+      $uniquename = $v[0];
     }
     }
     if (count($prop_values) == 1) {
     if (count($prop_values) == 1) {
-      $pub[$prop_type[0]->name] = $prop_values[0];
+      $v = array_values($prop_values);
+      $pub[$prop_type[0]->name] = $v[0];
     }
     }
     else {
     else {
       $pub[$prop_type[0]->name] = $prop_values;
       $pub[$prop_type[0]->name] = $prop_values;

+ 48 - 29
tripal_pub/includes/tripal_pub.pub_citation.inc

@@ -161,7 +161,7 @@ function tripal_pub_create_citation($pub) {
   // Therefore, we need to select the type that makes most sense for
   // Therefore, we need to select the type that makes most sense for
   // construction of the citation. Here we'll iterate through them all
   // construction of the citation. Here we'll iterate through them all
   // and select the one that matches best.
   // and select the one that matches best.
-  if(is_array($pub['Publication Type'])) {
+  if (is_array($pub['Publication Type'])) {
     foreach ($pub['Publication Type'] as $ptype) {
     foreach ($pub['Publication Type'] as $ptype) {
       if ($ptype == 'Journal Article' ) {
       if ($ptype == 'Journal Article' ) {
         $pub_type = $ptype;
         $pub_type = $ptype;
@@ -193,16 +193,10 @@ function tripal_pub_create_citation($pub) {
         // we prefer that type
         // we prefer that type
       }
       }
     }
     }
+    // If we don't have a recognized publication type, then just use the
+    // first one in the list.
     if (!$pub_type) {
     if (!$pub_type) {
-      tripal_report_error('tripal_pub', TRIPAL_ERROR,
-        "Cannot generate citation for publication type: %types.\nTitle: %title.\nDbxref: %dbxref",
-        array(
-          '%types' => print_r($pub['Publication Type'], TRUE),
-          '%title' => $pub['Title'],
-          '%dbxref' => $pub['Publication Dbxref'],
-        )
-      );
-      return FALSE;
+      $pub_type = $pub['Publication Type'][0];
     }
     }
   }
   }
   else {
   else {
@@ -215,7 +209,7 @@ function tripal_pub_create_citation($pub) {
     if (array_key_exists('Authors', $pub)) {
     if (array_key_exists('Authors', $pub)) {
       $citation = $pub['Authors'] . '. ';
       $citation = $pub['Authors'] . '. ';
     }
     }
-    
+
     $citation .= $pub['Title'] .  '. ';
     $citation .= $pub['Title'] .  '. ';
 
 
     if (array_key_exists('Journal Name', $pub)) {
     if (array_key_exists('Journal Name', $pub)) {
@@ -260,7 +254,7 @@ function tripal_pub_create_citation($pub) {
     if (array_key_exists('Authors', $pub)) {
     if (array_key_exists('Authors', $pub)) {
       $citation = $pub['Authors'] . '. ';
       $citation = $pub['Authors'] . '. ';
     }
     }
-    
+
     $citation .= $pub['Title'] .  '. ';
     $citation .= $pub['Title'] .  '. ';
 
 
     if (array_key_exists('Journal Name', $pub)) {
     if (array_key_exists('Journal Name', $pub)) {
@@ -305,7 +299,7 @@ function tripal_pub_create_citation($pub) {
     if (array_key_exists('Authors', $pub)) {
     if (array_key_exists('Authors', $pub)) {
       $citation = $pub['Authors'] . '. ';
       $citation = $pub['Authors'] . '. ';
     }
     }
-    
+
     $citation .= $pub['Title'] .  '. ';
     $citation .= $pub['Title'] .  '. ';
 
 
     if (array_key_exists('Journal Name', $pub)) {
     if (array_key_exists('Journal Name', $pub)) {
@@ -326,7 +320,7 @@ function tripal_pub_create_citation($pub) {
     if (array_key_exists('Authors', $pub)) {
     if (array_key_exists('Authors', $pub)) {
       $citation = $pub['Authors'] . '. ';
       $citation = $pub['Authors'] . '. ';
     }
     }
-    
+
     $citation .= $pub['Title'] .  '. ';
     $citation .= $pub['Title'] .  '. ';
     if (array_key_exists('Journal Name', $pub)) {
     if (array_key_exists('Journal Name', $pub)) {
       $citation .= $pub['Journal Name'] . '. ';
       $citation .= $pub['Journal Name'] . '. ';
@@ -363,26 +357,14 @@ function tripal_pub_create_citation($pub) {
     }
     }
     $citation .= '.';
     $citation .= '.';
   }
   }
-  //----------------------
-  // Book
-  //----------------------
-  elseif ($pub_type == 'Book') {
-
-  }
-  //----------------------
-  // Book Chapter
-  //----------------------
-  elseif ($pub_type == 'Book Chapter') {
-
-  }
-  //----------------------
+  //-----------------------
   // Conference Proceedings
   // Conference Proceedings
-  //----------------------
+  //-----------------------
   elseif ($pub_type == 'Conference Proceedings') {
   elseif ($pub_type == 'Conference Proceedings') {
     if (array_key_exists('Authors', $pub)) {
     if (array_key_exists('Authors', $pub)) {
       $citation = $pub['Authors'] . '. ';
       $citation = $pub['Authors'] . '. ';
     }
     }
-    
+
     $citation .= $pub['Title'] .  '. ';
     $citation .= $pub['Title'] .  '. ';
     if (array_key_exists('Conference Name', $pub)) {
     if (array_key_exists('Conference Name', $pub)) {
       $citation .= $pub['Conference Name'] . '. ';
       $citation .= $pub['Conference Name'] . '. ';
@@ -416,6 +398,43 @@ function tripal_pub_create_citation($pub) {
     }
     }
     $citation .= '.';
     $citation .= '.';
   }
   }
+  //-----------------------
+  // Default
+  //-----------------------
+  else {
+    if (array_key_exists('Authors', $pub)) {
+      $citation = $pub['Authors'] . '. ';
+    }
+    $citation .= $pub['Title'] .  '. ';
+    if (array_key_exists('Series Name', $pub)) {
+      $citation .= $pub['Series Name'] . '. ';
+    }
+    elseif (array_key_exists('Series Abbreviation', $pub)) {
+      $citation .= $pub['Series Abbreviation'] . '. ';
+    }
+    if (array_key_exists('Publication Date', $pub)) {
+      $citation .= $pub['Publication Date'];
+    }
+    elseif (array_key_exists('Year', $pub)) {
+      $citation .= $pub['Year'];
+    }
+    if (array_key_exists('Volume', $pub) or array_key_exists('Issue', $pub) or array_key_exists('Pages',$pub)) {
+      $citation .= '; ';
+    }
+    if (array_key_exists('Volume', $pub)) {
+      $citation .= $pub['Volume'];
+    }
+    if (array_key_exists('Issue', $pub)) {
+      $citation .= '(' . $pub['Issue'] . ')';
+    }
+    if (array_key_exists('Pages', $pub)) {
+      if (array_key_exists('Volume', $pub)) {
+        $citation .= ':';
+      }
+      $citation .= $pub['Pages'];
+    }
+    $citation .= '.';
+  }
 
 
   return $citation;
   return $citation;
 }
 }

+ 153 - 0
tripal_pub/theme/templates/pub_types/default.inc

@@ -0,0 +1,153 @@
+<?php
+// ========================================================================
+// TO CUSTOMIZE A SPECIFIC PUBLICATION TYPE, CUT-AND-PASTE THE CODE
+// BELOW INTO A NEW FILE WITH THE SAME NAME AS THE TYPE (SEE INSTRUCTIONS
+// ABOVE), AND EDIT.
+// ========================================================================
+
+// the $headers array is an array of fields to use as the colum headers.
+// additional documentation can be found here
+// https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+// This table for the analysis has a vertical header (down the first column)
+// so we do not provide headers here, but specify them in the $rows array below.
+$headers = array();
+
+// the $rows array contains an array of rows where each row is an array
+// of values for each column of the table in that row.  Additional documentation
+// can be found here:
+// https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+$rows = array();
+
+// Title row
+$title = '';
+if ($url) {
+  $title =  l(htmlspecialchars($pub->title), $url, array('attributes' => array('target' => '_blank')));
+}
+elseif ($dbxref and $dbxref->db_id->urlprefix) {
+  $title =  l(htmlspecialchars($pub->title), $dbxref->db_id->urlprefix . $dbxref->accession, array('attributes' => array('target' => '_blank')));
+}
+else {
+  $title =  htmlspecialchars($pub->title);
+}
+$rows[] = array(
+  array(
+    'data' => 'Title',
+    'header' => TRUE,
+    'width' => '20%',
+  ),
+  $title,
+);
+// Authors row
+$rows[] = array(
+  array(
+    'data' => 'Authors',
+    'header' => TRUE
+  ),
+  $authors_list,
+);
+// Type row
+$rows[] = array(
+  array(
+    'data' => 'Type',
+    'header' => TRUE
+  ),
+  $pub->type_id->name,
+);
+// Media Title
+$rows[] = array(
+  array(
+    'data' => 'Media Title',
+    'header' => TRUE,
+    'nowrap' => 'nowrap'
+  ),
+  $pub->series_name,
+);
+// Volume
+$rows[] = array(
+  array(
+    'data' => 'Volume',
+    'header' => TRUE
+  ),
+  $pub->volume ? $pub->volume : 'N/A',
+);
+// Issue
+$rows[] = array(
+  array(
+    'data' => 'Issue',
+    'header' => TRUE
+  ),
+  $pub->issue ? $pub->issue : 'N/A'
+);
+// Year
+$rows[] = array(
+  array(
+    'data' => 'Year',
+    'header' => TRUE
+  ),
+  $pub->pyear
+);
+// Pages
+$rows[] = array(
+  array(
+    'data' => 'Page(s)',
+    'header' => TRUE
+  ),
+  $pub->pages ? $pub->pages : 'N/A'
+);
+// Citation row
+$rows[] = array(
+  array(
+    'data' => 'Citation',
+    'header' => TRUE
+  ),
+  htmlspecialchars($citation->value)
+);
+// allow site admins to see the pub ID
+if (user_access('view ids')) {
+  // Pub ID
+  $rows[] = array(
+    array(
+      'data' => 'Pub ID',
+      'header' => TRUE,
+      'class' => 'tripal-site-admin-only-table-row',
+    ),
+    array(
+      'data' => $pub->pub_id,
+      'class' => 'tripal-site-admin-only-table-row',
+    ),
+  );
+}
+// Is Obsolete Row
+if($pub->is_obsolete == TRUE){
+  $rows[] = array(
+    array(
+      'data' => '<div class="tripal_pub-obsolete">This publication is obsolete</div>',
+      'colspan' => 2
+    ),
+  );
+}
+// the $table array contains the headers and rows array as well as other
+// options for controlling the display of the table.  Additional
+// documentation can be found here:
+// https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+$table = array(
+  'header' => $headers,
+  'rows' => $rows,
+  'attributes' => array(
+    'id' => 'tripal_pub-table-base',
+    'class' => 'tripal-data-table'
+  ),
+  'sticky' => FALSE,
+  'caption' => '',
+  'colgroups' => array(),
+  'empty' => '',
+);
+
+// once we have our table array structure defined, we call Drupal's theme_table()
+// function to generate the table.
+print theme_table($table);
+
+if ($abstract_text) { ?>
+  <p><b>Abstract</b></p>
+  <div style="text-align: justify"><?php print $abstract_text; ?></div> <?php
+}

+ 27 - 187
tripal_pub/theme/templates/tripal_pub_base.tpl.php

@@ -1,15 +1,10 @@
 <?php
 <?php
-/*
- * Note, the table generated by this template that lists the publication
- * details is generic. It can be customized to look different for different
- * publication types.  To create a custom template for a given type, create a 
- * new file in the pub_types directory.  Name the file using the name of the
- * type. The name must be all lower-case and spaces should be replaced with
- * and underscore symbol.  For example, to create a custom table for the
- * "Conference Proceedings", create the file conference_proceedings.inc inside
- * of the pub_types folder.  Cut and paste the code below that generates the table
- * structure into the new file.  Then edit to your liking.
- * 
+/**
+ * The page generated by this template depends on the publication type.  Each
+ * publication type may appear differently. You can find the publication
+ * templates for each type in the pub_types folder. The files have the same
+ * name as the type.  If a publication type is not found in that file then the
+ * generic.inc template is used for display of the publication.
  */
  */
 
 
 $pub = $variables['node']->pub;
 $pub = $variables['node']->pub;
@@ -20,22 +15,22 @@ $pub = chado_expand_var($pub, 'field', 'pub.volumetitle');
 
 
 // get the citation
 // get the citation
 $values = array(
 $values = array(
-  'pub_id' => $pub->pub_id, 
+  'pub_id' => $pub->pub_id,
   'type_id' => array(
   'type_id' => array(
     'name' => 'Citation',
     'name' => 'Citation',
   ),
   ),
 );
 );
-$citation = chado_generate_var('pubprop', $values); 
+$citation = chado_generate_var('pubprop', $values);
 $citation = chado_expand_var($citation, 'field', 'pubprop.value');
 $citation = chado_expand_var($citation, 'field', 'pubprop.value');
 
 
 // get the abstract
 // get the abstract
 $values = array(
 $values = array(
-  'pub_id' => $pub->pub_id, 
+  'pub_id' => $pub->pub_id,
   'type_id' => array(
   'type_id' => array(
     'name' => 'Abstract',
     'name' => 'Abstract',
   ),
   ),
 );
 );
-$abstract = chado_generate_var('pubprop', $values); 
+$abstract = chado_generate_var('pubprop', $values);
 $abstract = chado_expand_var($abstract, 'field', 'pubprop.value');
 $abstract = chado_expand_var($abstract, 'field', 'pubprop.value');
 $abstract_text = '';
 $abstract_text = '';
 if ($abstract) {
 if ($abstract) {
@@ -44,23 +39,23 @@ if ($abstract) {
 
 
 // get the author list
 // get the author list
 $values = array(
 $values = array(
-  'pub_id' => $pub->pub_id, 
+  'pub_id' => $pub->pub_id,
   'type_id' => array(
   'type_id' => array(
     'name' => 'Authors',
     'name' => 'Authors',
   ),
   ),
 );
 );
-$authors = chado_generate_var('pubprop', $values); 
+$authors = chado_generate_var('pubprop', $values);
 $authors = chado_expand_var($authors, 'field', 'pubprop.value');
 $authors = chado_expand_var($authors, 'field', 'pubprop.value');
 $authors_list = 'N/A';
 $authors_list = 'N/A';
 if ($authors) {
 if ($authors) {
   $authors_list = $authors->value;
   $authors_list = $authors->value;
-} 
+}
 
 
 // get the first database cross-reference with a url
 // get the first database cross-reference with a url
 $options = array('return_array' => 1);
 $options = array('return_array' => 1);
 $pub = chado_expand_var($pub, 'table', 'pub_dbxref', $options);
 $pub = chado_expand_var($pub, 'table', 'pub_dbxref', $options);
 $dbxref = NULL;
 $dbxref = NULL;
-if ($pub->pub_dbxref) { 
+if ($pub->pub_dbxref) {
   foreach ($pub->pub_dbxref as $index => $pub_dbxref) {
   foreach ($pub->pub_dbxref as $index => $pub_dbxref) {
     if ($pub_dbxref->dbxref_id->db_id->urlprefix) {
     if ($pub_dbxref->dbxref_id->db_id->urlprefix) {
       $dbxref = $pub_dbxref->dbxref_id;
       $dbxref = $pub_dbxref->dbxref_id;
@@ -71,184 +66,29 @@ if ($pub->pub_dbxref) {
 // get the URL
 // get the URL
 // get the author list
 // get the author list
 $values = array(
 $values = array(
-  'pub_id' => $pub->pub_id, 
+  'pub_id' => $pub->pub_id,
   'type_id' => array(
   'type_id' => array(
     'name' => 'URL',
     'name' => 'URL',
   ),
   ),
 );
 );
 $options = array('return_array' => 1);
 $options = array('return_array' => 1);
-$urls = chado_generate_var('pubprop', $values, $options); 
+$urls = chado_generate_var('pubprop', $values, $options);
 $urls = chado_expand_var($urls, 'field', 'pubprop.value');
 $urls = chado_expand_var($urls, 'field', 'pubprop.value');
 $url = '';
 $url = '';
 if (count($urls) > 0) {
 if (count($urls) > 0) {
-  $url = $urls[0]->value; 
-}?>
-
-<div class="tripal_pub-data-block-desc tripal-data-block-desc"></div> <?php 
+  $url = $urls[0]->value;
+} ?>
+<div class="tripal_pub-data-block-desc tripal-data-block-desc"></div> <?php
 
 
-// to simplify the template, we have a subdirectory named 'pub_types'.  This directory
-// should have include files each specific to a publication type. If the type is 
+// To simplify the template, we have a subdirectory named 'pub_types'.  This directory
+// should have include files each specific to a publication type. If the type is
 // not present then the base template will be used, otherwise the template in the
 // not present then the base template will be used, otherwise the template in the
 // include file is used.
 // include file is used.
 $inc_name = strtolower(preg_replace('/ /', '_', $pub->type_id->name)) . '.inc';
 $inc_name = strtolower(preg_replace('/ /', '_', $pub->type_id->name)) . '.inc';
-$inc_path = drupal_realpath(drupal_get_path('module', 'tripal_pub') . "/theme/tripal_pub/pub_types/$inc_name");
+$inc_path = DRUPAL_ROOT . '/' . drupal_get_path('module', 'tripal_pub') . "/theme/templates/pub_types/$inc_name";
 if (file_exists($inc_path)) {
 if (file_exists($inc_path)) {
-  require_once "pub_types/$inc_name";  
-} 
-else { 
-  // ========================================================================
-  // TO CUSTOMIZE A SPECIFIC PUBLICATION TYPE, CUT-AND-PASTE THE CODE
-  // BELOW INTO A NEW FILE WITH THE SAME NAME AS THE TYPE (SEE INSTRUCTIONS
-  // ABOVE), AND EDIT.
-  // ========================================================================
-  
-  // the $headers array is an array of fields to use as the colum headers. 
-  // additional documentation can be found here 
-  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
-  // This table for the analysis has a vertical header (down the first column)
-  // so we do not provide headers here, but specify them in the $rows array below.
-  $headers = array();
-  
-  // the $rows array contains an array of rows where each row is an array
-  // of values for each column of the table in that row.  Additional documentation
-  // can be found here:
-  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
-  $rows = array();
-
-  // Title row
-  $title = '';
-  if ($url) {
-    $title =  l(htmlspecialchars($pub->title), $url, array('attributes' => array('target' => '_blank')));
-  }
-  elseif ($dbxref and $dbxref->db_id->urlprefix) {
-    $title =  l(htmlspecialchars($pub->title), $dbxref->db_id->urlprefix . $dbxref->accession, array('attributes' => array('target' => '_blank')));
-  }
-  else {
-    $title =  htmlspecialchars($pub->title);
-  }
-  $rows[] = array(
-    array(
-      'data' => 'Title',
-      'header' => TRUE,
-      'width' => '20%',
-    ),
-    $title,
-  );
-  // Authors row
-  $rows[] = array(
-    array(
-      'data' => 'Authors',
-      'header' => TRUE
-    ),
-    $authors_list,
-  );
-  // Type row
-  $rows[] = array(
-    array(
-      'data' => 'Type',
-      'header' => TRUE
-    ),
-    $pub->type_id->name,
-  );
-  // Media Title
-  $rows[] = array(
-    array(
-      'data' => 'Media Title',
-      'header' => TRUE,
-      'nowrap' => 'nowrap'
-    ),
-    $pub->series_name,
-  );
-  // Volume
-  $rows[] = array(
-    array(
-      'data' => 'Volume',
-      'header' => TRUE
-    ),
-    $pub->volume ? $pub->volume : 'N/A',
-  );
-  // Issue
-  $rows[] = array(
-    array(
-      'data' => 'Issue',
-      'header' => TRUE
-    ),
-    $pub->issue ? $pub->issue : 'N/A'
-  );
-  // Year
-  $rows[] = array(
-    array(
-      'data' => 'Year',
-      'header' => TRUE
-    ),
-    $pub->pyear
-  );
-  // Pages
-  $rows[] = array(
-    array(
-      'data' => 'Page(s)',
-      'header' => TRUE
-    ),
-    $pub->pages ? $pub->pages : 'N/A'
-  );
-  // Citation row
-  $rows[] = array(
-    array(
-      'data' => 'Citation',
-      'header' => TRUE
-    ),
-    htmlspecialchars($citation->value)
-  );
-  // allow site admins to see the pub ID
-  if (user_access('view ids')) {
-    // Pub ID
-    $rows[] = array(
-      array(
-        'data' => 'Pub ID',
-        'header' => TRUE,
-        'class' => 'tripal-site-admin-only-table-row',
-      ),
-      array(
-        'data' => $pub->pub_id,
-        'class' => 'tripal-site-admin-only-table-row',
-      ),
-    );
-  }
-  // Is Obsolete Row
-  if($pub->is_obsolete == TRUE){
-    $rows[] = array(
-      array(
-        'data' => '<div class="tripal_pub-obsolete">This publication is obsolete</div>',
-        'colspan' => 2
-      ),
-    );
-  }
-  // the $table array contains the headers and rows array as well as other
-  // options for controlling the display of the table.  Additional
-  // documentation can be found here:
-  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
-  $table = array(
-    'header' => $headers,
-    'rows' => $rows,
-    'attributes' => array(
-      'id' => 'tripal_pub-table-base',
-      'class' => 'tripal-data-table'
-    ),
-    'sticky' => FALSE,
-    'caption' => '',
-    'colgroups' => array(),
-    'empty' => '',
-  );
-  
-  // once we have our table array structure defined, we call Drupal's theme_table()
-  // function to generate the table.
-  print theme_table($table);
-  if ($abstract_text) { ?>
-    <p><b>Abstract</b></p>
-    <div style="text-align: justify"><?php print $abstract_text; ?></div> <?php 
-  } 
-  
-  // ========================================================================
-  // END OF CUT-AND-PASTE REGION
-  // ========================================================================
-} 
+  require_once "pub_types/$inc_name";
+}
+else {
+  require_once "pub_types/default.inc";
+}

+ 8 - 3
tripal_pub/tripal_pub.drush.inc

@@ -31,7 +31,7 @@ function tripal_pub_drush_help($command) {
  */
  */
 function tripal_pub_drush_command() {
 function tripal_pub_drush_command() {
   $items = array();
   $items = array();
-  
+
   $items['trp-import-pubs'] = array(
   $items['trp-import-pubs'] = array(
     'description' => dt('Imports publications from remote databases using saved configuration settings.'),
     'description' => dt('Imports publications from remote databases using saved configuration settings.'),
     'options' => array(
     'options' => array(
@@ -39,6 +39,9 @@ function tripal_pub_drush_command() {
       'dbxref' => dt('An accession number for a publication from a remote database (e.g. PMID:23582642).'),
       'dbxref' => dt('An accession number for a publication from a remote database (e.g. PMID:23582642).'),
       'report' => dt("Set to the email address of the recipient who should receive an HTML report of the publications that have been added."),
       'report' => dt("Set to the email address of the recipient who should receive an HTML report of the publications that have been added."),
       'update' => dt("Set to 'Y' to update existing pubs.  By default only new pubs are inserted."),
       'update' => dt("Set to 'Y' to update existing pubs.  By default only new pubs are inserted."),
+      'username' => array(
+        'description' => dt('The Drupal user name for which the job should be run.  The permissions for this user will be used.'),
+      ),
     ),
     ),
     'examples' => array(
     'examples' => array(
       'Standard example' => 'drush tripal-pubs-import',
       'Standard example' => 'drush tripal-pubs-import',
@@ -60,7 +63,7 @@ function tripal_pub_drush_command() {
       'Update all records for a single database' => 'drush tripal-pubs-update --db=PMID'
       'Update all records for a single database' => 'drush tripal-pubs-update --db=PMID'
     ),
     ),
   );
   );
-  
+
   // Deprecated commands
   // Deprecated commands
   $items['tripal-pubs-import'] = array(
   $items['tripal-pubs-import'] = array(
     'description' => dt('DEPRECATED. Please see: trp-import-pubs.'),
     'description' => dt('DEPRECATED. Please see: trp-import-pubs.'),
@@ -106,6 +109,8 @@ function drush_tripal_pub_trp_import_pubs() {
   $dbxref = drush_get_option('dbxref');
   $dbxref = drush_get_option('dbxref');
   $do_report = drush_get_option('report');
   $do_report = drush_get_option('report');
   $update = drush_get_option('update');
   $update = drush_get_option('update');
+  $uname = drush_get_option('username');
+  drush_tripal_core_set_user($uname);
 
 
   if($update == 'Y') {
   if($update == 'Y') {
     $update = TRUE;
     $update = TRUE;
@@ -154,6 +159,6 @@ function drush_tripal_pub_trp_update_pubs() {
 function drush_tripal_pub_tripal_pubs_update() {
 function drush_tripal_pub_tripal_pubs_update() {
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
   drush_print("\n\nDEPRECATED: This drush command is outdated.\nIt will ".
       "continue to work but please consider using the 'trp-update-pubs' command.\n\n");
       "continue to work but please consider using the 'trp-update-pubs' command.\n\n");
-  
+
   drush_tripal_pub_trp_update_pubs();
   drush_tripal_pub_trp_update_pubs();
 }
 }

+ 1 - 1
tripal_pub/tripal_pub.info

@@ -3,7 +3,7 @@ description = Supports the pub (publication) tables of Chado by providing pages
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 stylesheets[all][] = theme/css/tripal_pub.css
 stylesheets[all][] = theme/css/tripal_pub.css
 
 

+ 0 - 3
tripal_pub/tripal_pub.install

@@ -49,9 +49,6 @@ function tripal_pub_requirements($phase) {
 function tripal_pub_install() {
 function tripal_pub_install() {
   global $base_path;
   global $base_path;
 
 
-  // create the module's data directory
-  tripal_create_files_dir('tripal_pub');
-
   // add loading of the the tripal pub ontology to the job queue
   // add loading of the the tripal pub ontology to the job queue
   $obo_path = '{tripal_pub}/files/tpub.obo';
   $obo_path = '{tripal_pub}/files/tpub.obo';
   $obo_id = tripal_insert_obo('Tripal Publication', $obo_path);
   $obo_id = tripal_insert_obo('Tripal Publication', $obo_path);

+ 5 - 7
tripal_pub/tripal_pub.module

@@ -65,8 +65,6 @@ function tripal_pub_menu() {
     'access arguments' => array('access chado_pub content'),
     'access arguments' => array('access chado_pub content'),
     'type' => MENU_CALLBACK
     'type' => MENU_CALLBACK
   );
   );
-  
-
 
 
   $items['find/publications/criteria/%/%'] = array(
   $items['find/publications/criteria/%/%'] = array(
     'page callback' => 'tripal_pub_search_page_update_criteria',
     'page callback' => 'tripal_pub_search_page_update_criteria',
@@ -112,7 +110,7 @@ function tripal_pub_menu() {
     'type' => MENU_LOCAL_TASK,
     'type' => MENU_LOCAL_TASK,
     'weight' => 2
     'weight' => 2
   );
   );
-  
+
   $items['admin/tripal/chado/tripal_pub/chado_pub_toc'] = array(
   $items['admin/tripal/chado/tripal_pub/chado_pub_toc'] = array(
     'title' => ' TOC',
     'title' => ' TOC',
     'description' => 'Manage the table of contents for pub nodes.',
     'description' => 'Manage the table of contents for pub nodes.',
@@ -399,7 +397,7 @@ function tripal_pub_form_alter(&$form, &$form_state, $form_id) {
   if ($form_id == "chado_pub_node_form") {
   if ($form_id == "chado_pub_node_form") {
     // turn of preview button for insert/updates
     // turn of preview button for insert/updates
     $form['actions']['preview']['#access'] = FALSE;
     $form['actions']['preview']['#access'] = FALSE;
-    
+
     //remove the body field
     //remove the body field
     unset($form['body']);
     unset($form['body']);
   }
   }
@@ -445,9 +443,9 @@ function tripal_pub_job_describe_args($callback, $args) {
 }
 }
 
 
 
 
-/** 
+/**
  * A simple wrapper function to put <pre> tags around the raw results
  * A simple wrapper function to put <pre> tags around the raw results
- * returned by the 
+ * returned by the
  * @param unknown $dbxref
  * @param unknown $dbxref
  * @return string
  * @return string
  */
  */
@@ -462,7 +460,7 @@ function tripal_get_remote_pub_raw_page($dbxref) {
 }
 }
 
 
 /**
 /**
- * 
+ *
  */
  */
 function tripal_pub_search_biological_data_views() {
 function tripal_pub_search_biological_data_views() {
   return array(
   return array(

+ 9 - 13
tripal_pub/tripal_pub.views_default.inc

@@ -45,7 +45,10 @@ function tripal_pub_defaultview_admin_publications() {
   $handler->display->display_options['access']['perm'] = 'access chado_pub content';
   $handler->display->display_options['access']['perm'] = 'access chado_pub content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of publications that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of publications or to find a specific publication.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -149,18 +152,11 @@ function tripal_pub_defaultview_admin_publications() {
   $handler->display->display_options['fields']['type']['table'] = 'cvterm';
   $handler->display->display_options['fields']['type']['table'] = 'cvterm';
   $handler->display->display_options['fields']['type']['field'] = 'name';
   $handler->display->display_options['fields']['type']['field'] = 'name';
   $handler->display->display_options['fields']['type']['label'] = 'Type';
   $handler->display->display_options['fields']['type']['label'] = 'Type';
-  /* Sort criterion: Chado Pub: Pyear */
-  $handler->display->display_options['sorts']['pyear']['id'] = 'year';
-  $handler->display->display_options['sorts']['pyear']['table'] = 'pub';
-  $handler->display->display_options['sorts']['pyear']['field'] = 'pyear';
-  /* Sort criterion: Chado Pub: Title */
-  $handler->display->display_options['sorts']['title']['id'] = 'title';
-  $handler->display->display_options['sorts']['title']['table'] = 'pub';
-  $handler->display->display_options['sorts']['title']['field'] = 'title';
-  /* Sort criterion: Chado Cvterm: Name */
-  $handler->display->display_options['sorts']['type']['id'] = 'type';
-  $handler->display->display_options['sorts']['type']['table'] = 'cvterm';
-  $handler->display->display_options['sorts']['type']['field'] = 'name';
+  /* Sort criterion: Chado Pub: Id */
+  $handler->display->display_options['sorts']['pub_id']['id'] = 'pub_id';
+  $handler->display->display_options['sorts']['pub_id']['table'] = 'pub';
+  $handler->display->display_options['sorts']['pub_id']['field'] = 'pub_id';
+  $handler->display->display_options['sorts']['pub_id']['order'] = 'DESC';
   /* Filter criterion: Chado Pub: Title */
   /* Filter criterion: Chado Pub: Title */
   $handler->display->display_options['filters']['title']['id'] = 'title';
   $handler->display->display_options['filters']['title']['id'] = 'title';
   $handler->display->display_options['filters']['title']['table'] = 'pub';
   $handler->display->display_options['filters']['title']['table'] = 'pub';

+ 21 - 10
tripal_stock/includes/tripal_stock.chado_node.inc

@@ -196,8 +196,17 @@ function chado_stock_form($node, $form_state) {
 
 
   // TODO: Should we make this a textfield with an autocomplete field like the
   // TODO: Should we make this a textfield with an autocomplete field like the
   // feature type_id field?.
   // feature type_id field?.
+  $st_cv = tripal_get_default_cv("stock", "type_id");
   $type_options = tripal_get_cvterm_default_select_options('stock', 'type_id', 'stock types');
   $type_options = tripal_get_cvterm_default_select_options('stock', 'type_id', 'stock types');
   $type_options[0] = 'Select a Type';
   $type_options[0] = 'Select a Type';
+  $st_message = tripal_set_message("To add additional items to the stock type drop down list,
+     add a term to the " .
+    l($st_cv->name . " controlled vocabulary",
+      "admin/tripal/chado/tripal_cv/cv/" . $st_cv->cv_id . "/cvterm/add",
+      array('attributes' => array('target' => '_blank'))
+    ),
+    TRIPAL_INFO, array('return_html' => TRUE)
+  );
 
 
   $form['type_id'] = array(
   $form['type_id'] = array(
     '#type' => 'select',
     '#type' => 'select',
@@ -205,7 +214,8 @@ function chado_stock_form($node, $form_state) {
     '#description' => t('Select the stock type.'),
     '#description' => t('Select the stock type.'),
     '#options' => $type_options,
     '#options' => $type_options,
     '#default_value' => $type_id,
     '#default_value' => $type_id,
-    '#required'    => TRUE,
+    '#required' => TRUE,
+    '#suffix' => $st_message,
   );
   );
 
 
   // get the list of organisms
   // get the list of organisms
@@ -226,7 +236,7 @@ function chado_stock_form($node, $form_state) {
   );
   );
 
 
   $form['stock_description'] = array(
   $form['stock_description'] = array(
-    '#type' => 'textarea',
+    '#type' => 'text_format',
     '#title' => t('Notes'),
     '#title' => t('Notes'),
     '#default_value' => $sdescription,
     '#default_value' => $sdescription,
     '#description' => t('Briefly enter any notes on the above stock. This should not include phenotypes or genotypes.'),
     '#description' => t('Briefly enter any notes on the above stock. This should not include phenotypes or genotypes.'),
@@ -336,7 +346,6 @@ function chado_stock_validate(&$node, $form, &$form_state) {
   // remove surrounding whitespace
   // remove surrounding whitespace
   $node->uniquename = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
   $node->uniquename = property_exists($node, 'uniquename') ? trim($node->uniquename) : '';
   $node->sname = property_exists($node, 'sname') ? trim($node->sname) : '';
   $node->sname = property_exists($node, 'sname') ? trim($node->sname) : '';
-  $node->stock_description = property_exists($node, 'stock_description') ? trim($node->stock_description) : '';
   $node->accession = property_exists($node, 'accession') ? trim($node->accession) : '';
   $node->accession = property_exists($node, 'accession') ? trim($node->accession) : '';
   $node->db_description = property_exists($node, 'db_description') ? trim($node->db_description) : '';
   $node->db_description = property_exists($node, 'db_description') ? trim($node->db_description) : '';
 
 
@@ -365,10 +374,10 @@ function chado_stock_validate(&$node, $form, &$form_state) {
 
 
   // if this is an insert then we just need to make sure this name doesn't
   // if this is an insert then we just need to make sure this name doesn't
   // already exist for this organism if it does then we need to throw an error
   // already exist for this organism if it does then we need to throw an error
-  else {
+  elseif (!empty($node->organism_id) AND !empty($node->type_id)) {
     $sql = "
     $sql = "
       SELECT *
       SELECT *
-      FROM {Stock} S
+      FROM {stock} S
         INNER JOIN {cvterm} CVT ON S.type_id = CVT.cvterm_id
         INNER JOIN {cvterm} CVT ON S.type_id = CVT.cvterm_id
       WHERE uniquename = :uname AND organism_id = :organism_id AND CVT.name = :cvtname";
       WHERE uniquename = :uname AND organism_id = :organism_id AND CVT.name = :cvtname";
     $result = chado_query($sql, array(':uname' => $node->uniquename,
     $result = chado_query($sql, array(':uname' => $node->uniquename,
@@ -449,9 +458,10 @@ function chado_stock_insert($node) {
   // we do need to proceed with insertion into the chado/drupal linking table.
   // we do need to proceed with insertion into the chado/drupal linking table.
   if (!property_exists($node, 'stock_id')) {
   if (!property_exists($node, 'stock_id')) {
 
 
-    $node->uniquename   = trim($node->uniquename);
-    $node->sname        = trim($node->sname);
-    $node->accession    = trim($node->accession);
+    $node->uniquename = trim($node->uniquename);
+    $node->sname = trim($node->sname);
+    $node->accession = trim($node->accession);
+    $node->stock_description = trim($node->stock_description['value']);
 
 
     // before we can add the stock, we must add the dbxref if one has been
     // before we can add the stock, we must add the dbxref if one has been
     // provided by the user.
     // provided by the user.
@@ -554,8 +564,9 @@ function chado_stock_insert($node) {
  */
  */
 function chado_stock_update($node) {
 function chado_stock_update($node) {
 
 
-  $node->uniquename   = trim($node->uniquename);
-  $node->sname        = trim($node->sname);
+  $node->uniquename = trim($node->uniquename);
+  $node->sname = trim($node->sname);
+  $node->stock_description = trim($node->stock_description['value']);
 
 
   if ($node->revision) {
   if ($node->revision) {
     // there is no way to handle revisions in Chado but leave
     // there is no way to handle revisions in Chado but leave

+ 1 - 1
tripal_stock/tripal_stock.info

@@ -3,7 +3,7 @@ description = Supports the stock tables of Chado by providing pages for viewing,
 core = 7.x
 core = 7.x
 project = tripal
 project = tripal
 package = Tripal
 package = Tripal
-version = 7.x-2.0-rc1
+version = 7.x-2.0
 
 
 dependencies[] = tripal_core
 dependencies[] = tripal_core
 dependencies[] = tripal_views
 dependencies[] = tripal_views

+ 0 - 3
tripal_stock/tripal_stock.install

@@ -47,9 +47,6 @@ function tripal_stock_requirements($phase) {
  * @ingroup tripal_stock
  * @ingroup tripal_stock
  */
  */
 function tripal_stock_install() {
 function tripal_stock_install() {
-  // create the module's data directory
-  tripal_create_files_dir('tripal_stock');
-
   // add some controlled vocabularies
   // add some controlled vocabularies
   tripal_stock_add_cvs();
   tripal_stock_add_cvs();
 
 

+ 9 - 9
tripal_stock/tripal_stock.views_default.inc

@@ -95,7 +95,10 @@ function tripal_stock_defaultview_admin_stocks() {
   $handler->display->display_options['access']['perm'] = 'access chado_stock content';
   $handler->display->display_options['access']['perm'] = 'access chado_stock content';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['type'] = 'input_required';
+  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of stocks that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of stocks or to find a specific stock.';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['type'] = 'full';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['items_per_page'] = '25';
   $handler->display->display_options['pager']['options']['offset'] = '0';
   $handler->display->display_options['pager']['options']['offset'] = '0';
@@ -230,14 +233,11 @@ function tripal_stock_defaultview_admin_stocks() {
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['label'] = '';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['alter']['text'] = '[edit_node]   [delete_node]';
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
   $handler->display->display_options['fields']['nothing']['element_label_colon'] = FALSE;
-  /* Sort criterion: Chado Organism: Common Name */
-  $handler->display->display_options['sorts']['common_name']['id'] = 'common_name';
-  $handler->display->display_options['sorts']['common_name']['table'] = 'organism';
-  $handler->display->display_options['sorts']['common_name']['field'] = 'common_name';
-  /* Sort criterion: Chado Stock: Uniquename */
-  $handler->display->display_options['sorts']['uniquename']['id'] = 'uniquename';
-  $handler->display->display_options['sorts']['uniquename']['table'] = 'stock';
-  $handler->display->display_options['sorts']['uniquename']['field'] = 'uniquename';
+  /* Sort criterion: Chado Stock: Id */
+  $handler->display->display_options['sorts']['stock_id']['id'] = 'stock_id';
+  $handler->display->display_options['sorts']['stock_id']['table'] = 'stock';
+  $handler->display->display_options['sorts']['stock_id']['field'] = 'stock_id';
+  $handler->display->display_options['sorts']['stock_id']['order'] = 'DESC';
   /* Filter criterion: Chado Organism: Common Name */
   /* Filter criterion: Chado Organism: Common Name */
   $handler->display->display_options['filters']['common_name']['id'] = 'common_name';
   $handler->display->display_options['filters']['common_name']['id'] = 'common_name';
   $handler->display->display_options['filters']['common_name']['table'] = 'organism';
   $handler->display->display_options['filters']['common_name']['table'] = 'organism';

+ 0 - 1
tripal_views/api/tripal_views.api.inc

@@ -650,7 +650,6 @@ function tripal_add_views_integration($defn_array, $setup_id = FALSE) {
     $view_record['setup_id'] = $setup_id;
     $view_record['setup_id'] = $setup_id;
   }
   }
   if ($defn_array['type'] == 'mview') {
   if ($defn_array['type'] == 'mview') {
-    // D7 TODO: Check DBTNG changes work
     $mview = db_query("SELECT mview_id FROM {tripal_mviews} WHERE mv_table=:table", array(':table' => $defn_array['table']));
     $mview = db_query("SELECT mview_id FROM {tripal_mviews} WHERE mv_table=:table", array(':table' => $defn_array['table']));
     $mview = $mview->fetchObject();
     $mview = $mview->fetchObject();
     $view_record['mview_id'] = $mview->mview_id;
     $view_record['mview_id'] = $mview->mview_id;

+ 25 - 1
tripal_views/includes/tripal_views_integration.inc

@@ -31,6 +31,16 @@ function tripal_views_integrate_all_chado_tables() {
   // First integrate all of the Chado tables. Those that are base tables
   // First integrate all of the Chado tables. Those that are base tables
   // get special treatment.
   // get special treatment.
   $tables = chado_get_table_names(TRUE);
   $tables = chado_get_table_names(TRUE);
+
+  // Some chado tables might have been created via the Tripal Custom Tables
+  // or Tripal Materialized Views interfaces. We need to ensure that the
+  // corresponding mview_id and table_id are associated with these tables.
+  // @TODO: Add some way to show which integrations are for custom tables.
+  //$custom_tables = chado_get_custom_table_names();
+  $mview_tables = chado_get_mview_table_names();
+
+  // Hardcode a list of base tables since there isn't really a programatic way
+  // to determine which tables in the chado schema should be base tables.
   $base_tables = array(
   $base_tables = array(
     'acquisition', 'analysis', 'assay', 'biomaterial', 'contact', 'cv', 'cvterm',
     'acquisition', 'analysis', 'assay', 'biomaterial', 'contact', 'cv', 'cvterm',
     'db', 'dbxref', 'environment', 'expression', 'feature', 'featuremap', 'genotype',
     'db', 'dbxref', 'environment', 'expression', 'feature', 'featuremap', 'genotype',
@@ -39,15 +49,29 @@ function tripal_views_integrate_all_chado_tables() {
     'project', 'protocol', 'pub', 'stock', 'study', 'synonym'
     'project', 'protocol', 'pub', 'stock', 'study', 'synonym'
   );
   );
 
 
+  // For each chado table, generate an integration array, keeping the above
+  // details in mind, and save that integration with Tripal Views through the API.
   foreach ($tables as $tablename) {
   foreach ($tables as $tablename) {
     $priority = 10;
     $priority = 10;
     if (!tripal_is_table_integrated($tablename, $priority)) {
     if (!tripal_is_table_integrated($tablename, $priority)) {
-      if (in_array($tablename, $base_tables)) {
+
+      // Assuming that we have a default chado table, genereate an integration
+      // array describing it's Tripal Views integration.
+      if (in_array($tablename, $base_tables) OR (is_array($mview_tables) and in_array($tablename, $mview_tables))) {
         $table_integration_array = tripal_views_get_integration_array_for_chado_table($tablename, TRUE, $priority);
         $table_integration_array = tripal_views_get_integration_array_for_chado_table($tablename, TRUE, $priority);
       }
       }
       else {
       else {
         $table_integration_array = tripal_views_get_integration_array_for_chado_table($tablename, FALSE, $priority);
         $table_integration_array = tripal_views_get_integration_array_for_chado_table($tablename, FALSE, $priority);
       }
       }
+
+      // Check to see if this table is a Materialized view and if it is,
+      // treat it specially :).
+      if (is_array($mview_tables) and in_array($tablename, $mview_tables)) {
+        $table_integration_array['type'] = 'mview';
+      }
+
+      // As long as we were able to generate an integration array,
+      // Integrate It!
       if ($table_integration_array) {
       if ($table_integration_array) {
         tripal_add_views_integration($table_integration_array);
         tripal_add_views_integration($table_integration_array);
       }
       }

+ 23 - 20
tripal_views/includes/tripal_views_integration_UI.inc

@@ -306,7 +306,7 @@ function tripal_views_integration_form($form, &$form_state) {
   $chado_tables = array_merge(array('Select'), $chado_tables);
   $chado_tables = array_merge(array('Select'), $chado_tables);
   $default = '';
   $default = '';
   if ($setup_id) {
   if ($setup_id) {
-    $default = (!$setup_obj->mview_id) ? $setup_obj->table_name : '';
+    $default = ($setup_obj->table_name) ? $setup_obj->table_name : '';
   }
   }
   $form['base_table_type']['table_name'] = array(
   $form['base_table_type']['table_name'] = array(
     '#title' => t('Chado/Custom Table'),
     '#title' => t('Chado/Custom Table'),
@@ -326,7 +326,6 @@ function tripal_views_integration_form($form, &$form_state) {
 
 
 
 
   // build the form element that lists the materialized views
   // build the form element that lists the materialized views
-  // D7 TODO: Check DBTNG changes work
   $query = db_query("SELECT mview_id, name FROM {tripal_mviews} WHERE mv_schema is NULL or mv_schema = '' ORDER BY name");
   $query = db_query("SELECT mview_id, name FROM {tripal_mviews} WHERE mv_schema is NULL or mv_schema = '' ORDER BY name");
   $mview_tables = array();
   $mview_tables = array();
   $mview_tables['0'] = 'Select';
   $mview_tables['0'] = 'Select';
@@ -334,24 +333,29 @@ function tripal_views_integration_form($form, &$form_state) {
     $mview_tables[$mview->mview_id] = $mview->name;
     $mview_tables[$mview->mview_id] = $mview->name;
   }
   }
   $default = '';
   $default = '';
-  if ($setup_id && isset($setup_obj->mview_id)) {
+  $legacy_mview = FALSE;
+  if ($setup_id && !empty($setup_obj->mview_id)) {
     $default = $setup_obj->mview_id;
     $default = $setup_obj->mview_id;
   }
   }
-  $form['base_table_type']['mview_id'] = array(
-    '#title' => t('Legacy Materialized View'),
-    '#type' => 'select',
-    '#options' => $mview_tables,
-    '#description' => 'Which materialized view to use.',
-    '#default_value' => $default,
-    '#ajax' => array(
-       //D6: 'path' => 'tripal/views-integration/ajax/view_setup_table',
-       'callback' => 'tripal_views_integration_ajax_view_setup_table',
-       'wrapper' => 'tripal-views-integration-form',
-       'effect' => 'fade',
-       'event' => 'change',
-       'method' => 'replace',
-    ),
-  );
+  if (isset($mview_tables[$setup_obj->mview_id])) {
+    $legacy_mview = TRUE;
+
+    $form['base_table_type']['mview_id'] = array(
+      '#title' => t('Legacy Materialized View'),
+      '#type' => 'select',
+      '#options' => $mview_tables,
+      '#description' => 'Which materialized view to use.',
+      '#default_value' => $default,
+      '#ajax' => array(
+         //D6: 'path' => 'tripal/views-integration/ajax/view_setup_table',
+         'callback' => 'tripal_views_integration_ajax_view_setup_table',
+         'wrapper' => 'tripal-views-integration-form',
+         'effect' => 'fade',
+         'event' => 'change',
+         'method' => 'replace',
+      ),
+    );
+  }
 
 
   $form['views_type'] = array(
   $form['views_type'] = array(
     '#type' => 'fieldset',
     '#type' => 'fieldset',
@@ -470,8 +474,7 @@ function tripal_views_integration_form($form, &$form_state) {
     // get the columns in this materialized view.  They are separated by commas
     // get the columns in this materialized view.  They are separated by commas
     // where the first word is the column name and the rest is the type
     // where the first word is the column name and the rest is the type
     $columns = array();
     $columns = array();
-    if ($mview_id) {
-      // D7 TODO: Check DBTNG changes work
+    if ($legacy_mview) {
       $sql = "SELECT mv_specs FROM {tripal_mviews} WHERE mview_id = :id";
       $sql = "SELECT mv_specs FROM {tripal_mviews} WHERE mview_id = :id";
       $mview = db_query($sql, array(':id' => $mview_id));
       $mview = db_query($sql, array(':id' => $mview_id));
       $mview = $mview->fetchObject();
       $mview = $mview->fetchObject();

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません