? fieldtool-644444-generic_callbacks.patch
Index: fieldtool.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/fieldtool/fieldtool.module,v
retrieving revision 1.8
diff -u -p -r1.8 fieldtool.module
--- fieldtool.module	4 Feb 2010 04:20:45 -0000	1.8
+++ fieldtool.module	14 Feb 2010 01:49:35 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: fieldtool.module,v 1.8 2010/02/04 04:20:45 mjd Exp $
+// $Id: fieldtool.module,v 1.6 2009/08/29 14:43:22 jpetso Exp $
 /**
  * @file
  * Field Tool -
@@ -8,6 +8,7 @@
  * Copyright 2009 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020)
  */
 
+module_load_include('inc', 'fieldtool', 'generic_callbacks');
 
 /**
  * Common field callback (getter and/or import) that extracts a value from the
@@ -44,23 +45,7 @@ function fieldtool_field_verbatim_set(&$
   }
 }
 
-/**
- * Common CCK value extraction callback that retrieves the value verbatim from
- * the 'value' key of a node's CCK field. CCK field type info hooks can use
- * this callback to avoid code duplication.
- */
-function fieldtool_cck_verbatim_value_extract($field_info, $item) {
-  return $item['value'];
-}
 
-/**
- * Common CCK value itemization callback that sets the value verbatim to the
- * 'value' key of a node's CCK field. CCK field type info hooks can use this
- * callback to avoid code duplication.
- */
-function fieldtool_cck_verbatim_value_itemize($field_info, $value) {
-  return array('value' => $value);
-}
 
 /**
  * Get a list of entity types that can contain fields. For example, there is an
@@ -166,13 +151,23 @@ function fieldtool_fields($entity_type, 
         foreach ($fields_by_weight as $weight => $weight_fields) {
           foreach ($weight_fields as $field_name => $field_info) {
             $e_type_fields[$field_name] = $field_info;
+            
+            // Set a default getter/setter path if none has been specified;
+            if (!array_key_exists('field path', $e_type_fields[$field_name])) {
+              $e_type_fields[$field_name]['field path'] = fieldtool_path($e_type, $e_type_fields[$field_name]);
+            }
+            // Assign generic callback to "leaf" fields if a callback isn't defined.
+            if (!count($e_type_fields[$field_name]['fields'])) {
+              _fieldtool_find_callbacks($e_type_fields[$field_name]);
+            }
+            // TODO: Assign generic recursive callbacks to parent fields.
           }
         }
       }
       cache_set('fieldtool:fields', $fields);
     }
   }
-
+  
   // Don't waste time filtering if no filters are given at all.
   $filters_empty = TRUE;
 
@@ -248,12 +243,13 @@ function fieldtool_get_function($field_i
  * @param $object
  *   A fully loaded object to extract the field value from.
  */
-function fieldtool_get($field_info, $object) {
+function fieldtool_get($field_info, $object, $deltas = array()) {
+  $deltas = is_array($deltas) ? $deltas : array($deltas);
   $function = fieldtool_get_function($field_info, 'getter callback');
   if (empty($function)) {
     throw new Exception('Getter function could not be found.');
   }
-  return $function($object, $field_info['name'], $field_info);
+  return $function($object, $field_info['name'], $field_info, $deltas);
 }
 
 /**
@@ -270,12 +266,13 @@ function fieldtool_get($field_info, $obj
  * @param $value
  *   The new value for the field.
  */
-function fieldtool_set($field_info, &$object, $value) {
+function fieldtool_set($field_info, &$object, $value, $deltas = array()) {
+  $deltas = is_array($deltas) ? $deltas : array($deltas);
   $function = fieldtool_get_function($field_info, 'setter callback');
   if (empty($function)) {
     throw new Exception('Setter function could not be found.');
   }
-  $function($object, $field_info['name'], $value, $field_info);
+  $function($object, $field_info['name'], $value, $field_info, $deltas);
 }
 
 /**
@@ -287,12 +284,13 @@ function fieldtool_set($field_info, &$ob
  * @param $object
  *   A fully loaded object to extract the field value from.
  */
-function fieldtool_export($field_info, $object) {
+function fieldtool_export($field_info, $object, $deltas = array()) {
+  $deltas = is_array($deltas) ? $deltas : array($deltas);
   $function = fieldtool_get_function($field_info, 'export callback');
   if (empty($function)) {
     throw new Exception('Export function could not be found.');
   }
-  return $function($object, $field_info['name'], $field_info);
+  return $function($object, $field_info['name'], $field_info, $deltas);
 }
 
 /**
@@ -309,12 +307,13 @@ function fieldtool_export($field_info, $
  * @param $value
  *   The new (imported) value for the field.
  */
-function fieldtool_import($field_info, &$object, $value) {
+function fieldtool_import($field_info, &$object, $value, $deltas = array()) {
+  $deltas = is_array($deltas) ? $deltas : array($deltas);
   $function = fieldtool_get_function($field_info, 'import callback');
   if (empty($function)) {
     throw new Exception('Import function could not be found.');
   }
-  $function($object, $field_info['name'], $value, $field_info);
+  $function($object, $field_info['name'], $value, $field_info, $deltas);
 }
 
 /**
@@ -384,6 +383,10 @@ function fieldtool_cache_invalidate() {
   */
 function fieldtool_tree($entity_type, $entity_subtype = NULL) {
   //TODO: Maybe we should cache this.
+  static $tree; // At least don't go through this more than once per request.
+  if (count($tree)) {
+    return $tree;
+  }
 
   $filters = array();
   if ($entity_subtype) {
@@ -442,3 +445,47 @@ function _fieldtool_tree_add_children(&$
     unset($tree[$key]);
   }
 }
+
+/**
+ * Convenience function to find if an array has at least one non-numeric key.
+ */
+function _fieldtool_is_keyed_array($array) {
+  $found = FALSE;
+  foreach (array_keys($array) as $key) {
+    if (!is_numeric($key)) {
+      $found = TRUE;
+    }
+  }
+  return $found;
+}
+
+
+/**
+ * Get the parent field of a field (if any)
+ *
+ * @param $entity_type
+ *   The thing that you want to retrieve field information about, e.g. 'node'
+ *   for node types.
+ * @param $field_info
+ *   One of the field information arrays returned by fieldtool_fields().
+ *
+ * @return
+ *   A tree of field information keyed by the field name.
+ */
+function fieldtool_get_parent($entity_type, $field_info) {
+  $fields = fieldtool_fields($entity_type);
+
+  foreach ($fields as $field) {
+    if (count($field['fields'])) {
+      foreach ($field['fields'] as $child) {
+        if ($child == $field_info['name']) {
+          return $field;
+        }
+      }
+    }
+  }
+  
+  return FALSE;
+}
+
+
Index: generic_callbacks.inc
===================================================================
RCS file: generic_callbacks.inc
diff -N generic_callbacks.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ generic_callbacks.inc	14 Feb 2010 01:49:35 -0000
@@ -0,0 +1,262 @@
+<?php
+// $Id:$
+/**
+ * @file
+ * Field Tool - Generic callbacks
+ *
+ * Generic field handler callbacks for Field Tool.
+ *
+ * Copyright 2009 Matthew Davidson (http://drupal.org/user/52996).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * Generic fallback getter callback. Fields with no explicitly declared
+ * getter callback and no child fields are assumed to want this as their
+ * getter callback.
+ */
+function fieldtool_field_generic_get($entity, $field_name, $field_info, $deltas = array()) {
+  $path = _fieldtool_delta_replace($field_info['field path'], $deltas);
+
+  if (is_array($entity)) {
+    $path = _fieldtool_object_path_to_array($path);
+    return eval('return isset($entity'. $path .') ? $entity'. $path .' : NULL;');
+  }
+  return eval('return isset($entity->'. $path .') ? $entity->'. $path .' : NULL;');
+}
+
+/**
+ * Generic fallback setter callback. Fields with no explicitly declared
+ * setter callback and no child fields are assumed to want this as their
+ * setter callback.
+ */
+function fieldtool_field_generic_set(&$entity, $field_name, $value, $field_info, $deltas = array()) {
+  $path = _fieldtool_delta_replace($field_info['field path'], $deltas);
+  if (is_array($entity)) {
+    $path = _fieldtool_object_path_to_array($path);
+    if (isset($value)) {
+      eval('$entity'. $path .' = $value;');
+    }
+    else {
+      eval('unset($entity'. $path .');');
+    }
+  }
+  else {
+    if (isset($value)) {
+      eval('$entity->'. $path .' = $value;');
+    }
+    else {
+      eval('unset($entity->'. $path .');');
+    }
+  }
+}
+
+/**
+ * Generic fallback import callback. Fields with no explicitly declared
+ * import callback and no child fields are assumed to want this as their
+ * import callback.
+ */
+function fieldtool_field_generic_import(&$entity, $field_name, $value, $field_info, $deltas = array()) {
+  return fieldtool_set($field_info, $entity, $value, $deltas);
+}
+
+/**
+ * Generic fallback export callback. Fields with no explicitly declared
+ * export callback and no child fields are assumed to want this as their
+ * export callback.
+ */
+function fieldtool_field_generic_export($entity, $field_name, $field_info, $deltas = array()) {
+  return fieldtool_get($field_info, $entity, $deltas);
+}
+
+/**
+ * Generic fallback extraction callback. Fields with no explicitly declared
+ * extraction callback and no child fields are assumed to want this as their
+ * extraction callback.
+ */
+function fieldtool_generic_value_extract($field_info, $item) {
+  return $item;
+}
+
+/**
+ * Generic fallback itemization callback. Fields with no explicitly declared
+ * itemization callback and no child fields are assumed to want this as their
+ * itemization callback.
+ * 
+ * We assume that the setter callback wants a scalar value and try to
+ * convert objects and arrays in the most sensible way possible. Relying on
+ * this is often a BAD IDEA. If you have a last-descendant or "leaf" field
+ * that requires a non-scalar value for the setter callback, or can reasonably 
+ * expect non-scalar import data, please write your own itemization callback.
+ */
+function fieldtool_generic_value_itemize($field_info, $value) {
+  if (is_object($value)) {
+    $value = (array) $value;
+  }
+  
+  if (is_array($value)) {
+    if (_fieldtool_is_keyed_array($value)) {
+      $temp = array();
+      // This will not work satisfactorily with multidimensional arrays.
+      // Did I mention this is risky?
+      foreach ($value as $key => $val) {
+        $temp[] = $key .': '. $val;
+      }
+      $value = $temp;
+    }
+    
+    $value = implode(', ', $value);
+  } 
+  
+  return $value;
+}
+
+/**
+ * Helper function for generic callbacks.
+ */
+function _fieldtool_delta_replace($path, $deltas) {
+  foreach ($deltas as $delta) {
+    $pos = strpos($path, '[%]');
+    if ($pos === FALSE) {
+      // Assume we're trying to get an item on a field with a path that
+      // doesn't explicitly declare the tail '[%]'
+      $path .= "[$delta]";
+    }
+    else {
+      $path = substr_replace($path, (int) $delta, $pos + 1, 1);
+    }
+  }
+  
+  // Assume that if there's a placeholder remaining on the end,
+  // we want all values.
+  $path = preg_replace('/\[\%\]$/', '', $path);
+  
+  // Assume for any leftover placeholders we wanted the first item
+  $path = str_replace('[%]', '[0]', $path);
+  
+  return $path;
+}
+
+/**
+ * Helper function for generic callbacks.
+ *
+ * Good gracious, this is kludgy.
+ */
+function _fieldtool_object_path_to_array($path) {
+  $temp = explode('->', $path);
+  $temp = explode('[', $temp[0]);
+  
+  return preg_replace('/^'. $temp[0] .'/', "['". $temp[0] ."']", $path);
+}
+
+/**
+ * TODO: Recursive getter/setter/import/export/itemize/extract callbacks
+ *
+ * These are fallbacks for fields _with_ child fields, but no defined callback.
+ */
+
+
+/**
+ * Assign generic callback to a field if a callback isn't defined.
+ */
+function _fieldtool_find_callbacks(&$field_info) {
+  $callbacks = array(
+    'getter' => 'fieldtool_field_generic_get',
+    'setter' => 'fieldtool_field_generic_set',
+    'import' => 'fieldtool_field_generic_import',
+    'export' => 'fieldtool_field_generic_export',
+    'extraction' => 'fieldtool_field_generic_value_extract',
+    'itemization' => 'fieldtool_field_generic_value_itemize',
+  );
+  
+  foreach ($callbacks as $type => $function) {
+    $field_info[$type .' callback'] = $field_info[$type .' callback'] ? $field_info[$type .' callback'] : $callbacks[$type];
+  }
+    
+  return $field_info;
+}
+
+
+/**
+ * Work out path back to root field for generic getter/setter callbacks.
+ *
+ * @param $entity_type
+ *   The thing that you want to retrieve field information about, e.g. 'node'
+ *   for node types.
+ * @param $field_info
+ *   One of the field information arrays returned by fieldtool_fields().
+ *
+ * @return
+ *   An string representing the path to the (sub)field from the root field,
+ *   in the usual PHP variable notation, so you getter/setter callbacks can
+ *   access the value via eval('return $object->'.$path).
+ */
+function fieldtool_path($entity_type, $field_info) {
+  $path = array();
+  while($parent = fieldtool_get_parent($entity_type, $field_info)) {
+    if (!$field_info['virtual']){
+      // Strip any helpful '_%_' delta placeholders in names
+      $parent['name'] = str_replace('_%_', '_', $parent['name']);
+      $field_info['name'] = str_replace('_%_', '_', $field_info['name']);
+      $type = is_array($parent['fields']) ? 'array' : 'object';
+      $bit = array(
+        'type' => $type,
+        'name' => preg_replace('/^'. $parent['name'] .'_/', '', $field_info['name']),
+        'multiple' => $field_info['multiple'],
+      );
+      array_unshift($path, $bit);
+    }
+    
+    $field_info = $parent;
+  }
+
+  // Root field. Last parent found that did not have a parent.
+  if (!$field_info['virtual']) {
+      $bit = array(
+        'type' => 'root',
+        'name' => $field_info['name'],
+        'multiple' => $field_info['multiple'],
+      );
+      array_unshift($path, $bit);
+  }
+  
+  $string = '';
+  foreach ($path as $i => $bit) {
+    if (($bit['type'] == 'array') && ($i > 0)) {
+      $string .= "['". $bit['name'] ."']". _fieldtool_multiple_placeholder($bit['multiple']);
+    }
+    elseif (($bit['type'] == 'object') && ($i > 0)) {
+      $string .= '->'. $bit['name']. _fieldtool_multiple_placeholder($bit['multiple']);
+    }
+    else {
+      $string .= $bit['name']. _fieldtool_multiple_placeholder($bit['multiple']);
+    }
+  }
+  
+  return $string;
+}
+
+/**
+ * Helper function for fieldtool_path().
+ */
+function _fieldtool_multiple_placeholder($multiple = FALSE) {
+  if ($multiple) {
+    return '[%]';
+  }
+  return '';
+}
+
+
Index: plugins/fieldtool/cck_link.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/fieldtool/plugins/fieldtool/cck_link.inc,v
retrieving revision 1.1
diff -u -p -r1.1 cck_link.inc
--- plugins/fieldtool/cck_link.inc	29 Jan 2010 01:19:13 -0000	1.1
+++ plugins/fieldtool/cck_link.inc	14 Feb 2010 01:49:36 -0000
@@ -20,6 +20,7 @@ function fieldtool_cck_link_fieldtool_cc
     'non-array value' => TRUE,
     'transformations slot property callback' => 'fieldtool_cck_link_transformations_slot_property',
   );
+  
   return array('cck field type' => $types);
 }
 
Index: plugins/fieldtool/fieldgroup.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/fieldtool/plugins/fieldtool/fieldgroup.inc,v
retrieving revision 1.2
diff -u -p -r1.2 fieldgroup.inc
--- plugins/fieldtool/fieldgroup.inc	12 Feb 2010 02:43:55 -0000	1.2
+++ plugins/fieldtool/fieldgroup.inc	14 Feb 2010 01:49:36 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: fieldgroup.inc,v 1.2 2010/02/12 02:43:55 mjd Exp $
+// $Id$
 /**
  * @file
  * Field Tool - Fieldgroup plugin
@@ -42,6 +42,7 @@ function fieldtool_fieldgroup_fieldtool_
       $node_fields[$group_field_name] = array(
         'label' => $group['label'] .' ('. $group_field_name .')',
         'stored' => TRUE,
+        'virtual' => TRUE,
         'cck field type' => 'fieldgroup',
         'name' => $group_field_name,
         'node types' => array($type),
Index: plugins/fieldtool/location.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/fieldtool/plugins/fieldtool/location.inc,v
retrieving revision 1.2
diff -u -p -r1.2 location.inc
--- plugins/fieldtool/location.inc	8 Feb 2010 03:17:30 -0000	1.2
+++ plugins/fieldtool/location.inc	14 Feb 2010 01:49:36 -0000
@@ -3,7 +3,10 @@
 /**
  * @file
  * Field Tool - Location plugin
+ *
  * Location module field handler for Field Tool module.
+ * Tested with Location 6.x-3.1-rc1
+ * Supports: location_node, location_fax, location_phone
  *
  * Copyright 2009 Matthew Davidson.
  *
@@ -38,27 +41,12 @@ function fieldtool_location_fieldtool_fi
     }
   }
   
-  $verbatim_getter_callback = array(
-    'function' => 'fieldtool_field_verbatim_get',
-    'file' => 'fieldtool.module',
-    'path' => drupal_get_path('module', 'fieldtool'),
-  );
-  $verbatim_setter_callback = array(
-    'function' => 'fieldtool_field_verbatim_set',
-    'file' => 'fieldtool.module',
-    'path' => drupal_get_path('module', 'fieldtool'),
-  );
-
   $node_fields = array();
   
   // Low-level setting of all locations
-  $node_fields['location']['label'] = t('Locations');
-  $node_fields['location']['stored'] = TRUE;
-  $node_fields['location']['getter callback'] = $verbatim_getter_callback;
-  $node_fields['location']['setter callback'] = $verbatim_setter_callback;
-  $node_fields['location']['export callback'] = $verbatim_getter_callback;
-  $node_fields['location']['import callback'] = 'fieldtool_field_location_import';
-  $node_fields['location']['node types'] = $node_types;
+  $node_fields['locations']['label'] = t('Locations');
+  $node_fields['locations']['node types'] = $node_types;
+  $node_fields['locations']['multiple'] = TRUE;
 
 
   $location_fields = array(
@@ -80,98 +68,12 @@ function fieldtool_location_fieldtool_fi
   );
 
   foreach ($location_fields as $field) {
-    $node_fields['location_'. $field]['label'] = t('Location');
-    $node_fields['location_'. $field]['stored'] = TRUE;
-    $node_fields['location_'. $field]['getter callback'] = 'fieldtool_field_location_value_get';
-    $node_fields['location_'. $field]['setter callback'] = 'fieldtool_field_location_value_set';
-    $node_fields['location_'. $field]['export callback'] = 'fieldtool_field_location_value_export';
-    $node_fields['location_'. $field]['import callback'] = 'fieldtool_field_location_value_import';
-    $node_fields['location_'. $field]['node types'] = $node_types;
-    $node_fields['location']['fields'][] = 'location_'. $field;
+    $node_fields['locations_'. $field]['label'] = t('Location '. ucwords(str_replace('_', ' ', $field)));
+    $node_fields['locations_'. $field]['node types'] = $node_types;
+    $node_fields['locations']['fields'][] = 'locations_'. $field;
   }
 
   return array('node' => $node_fields);
 }
 
-/**
- * Location value itemization callback.
- */
-function fieldtool_location_value_itemize($field_info, $value, $type = NULL) {
-  if (is_numeric($value)) {
-    return location_load_location($value);
-  }
-  elseif (is_array($value)) {
-    return $value;
-  }
-}
-
-/**
- * Work out whether the imported value is a single item or array of items
- */
-function fieldtool_field_location_import(&$node, $field_name, $value, $field_info) {
-  $locations = array();
-  if (is_array($value)) {
-    if (array_key_exists($value['lid'])) { // if it's a single location
-      $locations[0] = fieldtool_location_value_itemize($field_info, $value, $node->type);
-    }
-    else {
-      foreach ($value as $location) { // an array of locations
-        if ($location = fieldtool_location_value_itemize($field_info, $location, $node->type)) {
-          $locations[] = $location;
-        }
-      }
-    }
-  }
-  elseif (is_numeric($value)) {
-    $locations = array(fieldtool_location_value_itemize($field_info, $value, $node->type));
-  }
-  fieldtool_field_verbatim_set($node, 'location', $locations, $field_info);
-}
-
-
-/**
- * Get an array of values for a sub-field.
- * 
- * i.e. fieldtool_field_location_value_get($node, 'location-address', $field_info)
- * in a node with two locations will return array($node->locations[0]['address'], $node->locations[1]['address'])
- */
-function fieldtool_field_location_value_get($node, $field_name, $field_info) {
-  $key = fieldtool_location_key($field_name);
-  $value = array();
-  foreach ($node->locations as $i => $location) {
-    $value[$i] = $location[$key];
-  }
-  return $value;
-}
-
-/**
- * Takes an array as output by fieldtool_field_location_value_get().
- */
-function fieldtool_field_location_value_set(&$node, $field_name, $values, $field_info) {
-  $key = fieldtool_location_key($field_name);
-  foreach ($values as $i => $value) {
-    $node->locations[$i][$key] = $value;
-  }
-}
 
-function fieldtool_field_location_value_export($node, $field_name, $field_info) {
-  return fieldtool_field_location_value_get($node, $field_name, $field_info);
-}
-
-function fieldtool_field_location_value_import(&$node, $field_name, $values, $field_info) {
-  if (is_array($values)) {
-    fieldtool_field_location_value_set(&$node, $field_name, $values, $field_info);
-  }
-  elseif (is_scalar($values)) { // assume it's a node with a single location
-    $key = fieldtool_location_key($field_name);
-    $node->locations[0][$key] = $values;
-  }
-}
-
-
-/**
- * Get a location subfield's array key from one of our pseudo-field-names
- */
-function fieldtool_location_key($field_name) {
-  return preg_replace('/^location_/', '', $field_name);
-}
Index: plugins/fieldtool/node_cck.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/fieldtool/plugins/fieldtool/node_cck.inc,v
retrieving revision 1.3
diff -u -p -r1.3 node_cck.inc
--- plugins/fieldtool/node_cck.inc	2 Jul 2009 10:34:13 -0000	1.3
+++ plugins/fieldtool/node_cck.inc	14 Feb 2010 01:49:36 -0000
@@ -33,6 +33,7 @@ function fieldtool_node_cck_fieldtool_fi
           )),
           'stored' => TRUE,
           'cck field type' => $field['type'],
+          'multiple' => $field['multiple'],
         );
         if (isset($supported_field_types[$field['type']])) {
           $node_fields[$field_name] += $supported_field_types[$field['type']];
@@ -163,3 +164,21 @@ function fieldtool_node_cck_field_set(&$
 function fieldtool_node_cck_field_single_set(&$node, $field_name, $value, $field_info) {
   fieldtool_node_cck_field_set($node, $field_name, array($value), $field_info);
 }
+
+/**
+ * Common CCK value extraction callback that retrieves the value verbatim from
+ * the 'value' key of a node's CCK field. CCK field type info hooks can use
+ * this callback to avoid code duplication.
+ */
+function fieldtool_cck_verbatim_value_extract($field_info, $item) {
+  return $item['value'];
+}
+
+/**
+ * Common CCK value itemization callback that sets the value verbatim to the
+ * 'value' key of a node's CCK field. CCK field type info hooks can use this
+ * callback to avoid code duplication.
+ */
+function fieldtool_cck_verbatim_value_itemize($field_info, $value) {
+  return array('value' => $value);
+}
Index: plugins/fieldtool/taxonomy.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/fieldtool/plugins/fieldtool/taxonomy.inc,v
retrieving revision 1.1
diff -u -p -r1.1 taxonomy.inc
--- plugins/fieldtool/taxonomy.inc	4 Feb 2010 04:39:32 -0000	1.1
+++ plugins/fieldtool/taxonomy.inc	14 Feb 2010 01:49:37 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: taxonomy.inc,v 1.1 2010/02/04 04:39:32 mjd Exp $
+// $Id$
 /**
  * @file
  * Field Tool - Taxonomy plugin
@@ -44,6 +44,7 @@ function fieldtool_taxonomy_fieldtool_fi
   foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) {
     $node_fields['taxonomy_'. $vid]['label'] = $vocabulary->name;
     $node_fields['taxonomy_'. $vid]['stored'] = TRUE;
+    $node_fields['taxonomy_'. $vid]['virtual'] = TRUE;
     $node_fields['taxonomy_'. $vid]['taxonomy vid'] = $vid;
     $node_fields['taxonomy_'. $vid]['weight'] = $vocabulary->weight;
     $node_fields['taxonomy_'. $vid]['getter callback'] = 'fieldtool_field_taxonomy_get';
