commit 1008765a7e29a407fdc12344a89a68ebb0790dd4
Author: Damien Tournoud <damien@commerceguys.com>
Date:   Fri Apr 13 12:15:08 2012 +0200

    Transform providers into ctools plugins and allow selection of the provider in each field.

diff --git a/provider/Tree_Provider_NestedSet.inc b/provider/Tree_Provider_NestedSet.inc
new file mode 100644
index 0000000..b8426dd
--- /dev/null
+++ b/provider/Tree_Provider_NestedSet.inc
@@ -0,0 +1,6 @@
+<?php
+$plugin = array(
+  'title' => t('Nested set'),
+  'class' => 'Tree_Provider_NestedSet',
+  'storages' => array('Tree_Storage_SQL'),
+);
diff --git a/provider/Tree_Provider_Simple.inc b/provider/Tree_Provider_Simple.inc
new file mode 100644
index 0000000..891d7f9
--- /dev/null
+++ b/provider/Tree_Provider_Simple.inc
@@ -0,0 +1,5 @@
+<?php
+$plugin = array(
+  'title' => t('Simple'),
+  'class' => 'Tree_Provider_Simple',
+);
diff --git a/tree.info b/tree.info
index 3ddf197..d0d3bab 100644
--- a/tree.info
+++ b/tree.info
@@ -2,6 +2,8 @@ name = Tree
 description = "Provides support for storing tree datastructures."
 core = 7.x
 
+dependencies[] = ctools
+
 ; Providers.
 files[] = tree.provider.inc
 files[] = provider/Tree_Provider_Simple.class.php
diff --git a/tree.module b/tree.module
index b3d9bbc..d698d87 100644
--- a/tree.module
+++ b/tree.module
@@ -1 +1,55 @@
 <?php
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function tree_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'tree') {
+    return $plugin;
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_type().
+ */
+function tree_ctools_plugin_type() {
+  $plugins['provider'] = array(
+    'classes' => array('class'),
+  );
+  $plugins['storage'] = array(
+    'classes' => array('class'),
+  );
+  return $plugins;
+}
+
+/**
+ * Return the tree providers usable on a given storage.
+ */
+function tree_get_providers($storage = NULL) {
+  ctools_include('plugins');
+  $handlers = ctools_get_plugins('tree', 'provider');
+  uasort($handlers, 'ctools_plugin_sort');
+
+  if (!empty($storage)) {
+    $storage_reflection = new ReflectionClass($storage);
+  }
+
+  $output = array();
+  foreach ($handlers as $plugin => $plugin_info) {
+    $valid = FALSE;
+    if (empty($storage) || empty($plugin_info['storages'])) {
+      $valid = TRUE;
+    }
+    else {
+      foreach ($plugin_info['storages'] as $provider_storage) {
+        if ($storage_reflection->isSubclassOf($provider_storage)) {
+          $valid = TRUE;
+        }
+      }
+    }
+    if ($valid) {
+      $output[$plugin] = $plugin_info;
+    }
+  }
+  return $output;
+}
diff --git a/treefield/entityreference/behavior/TreeFieldEntityReferenceBehavior.class.php b/treefield/entityreference/behavior/TreeFieldEntityReferenceBehavior.class.php
index 88047f3..40d56fe 100644
--- a/treefield/entityreference/behavior/TreeFieldEntityReferenceBehavior.class.php
+++ b/treefield/entityreference/behavior/TreeFieldEntityReferenceBehavior.class.php
@@ -8,6 +8,24 @@ class TreeFieldEntityReferenceBehavior extends EntityReference_BehaviorHandler_A
   protected $providers = array();
   protected $storages = array();
 
+  public function settingsForm($field, $instance) {
+    $plugins = tree_get_providers('Tree_Storage_SQL_Field');
+    $options = array();
+    foreach ($plugins as $plugin_name => $plugin_info) {
+      $options[$plugin_name] = $plugin_info['title'];
+    }
+
+    $form['provider'] = array(
+      '#title' => t('Provider'),
+      '#type' => 'select',
+      '#required' => TRUE,
+      '#multiple' => FALSE,
+      '#size' => 1,
+      '#options' => $options,
+    );
+    return $form;
+  }
+
   public function storage($field) {
     if (!isset($this->storages[$field['field_name']])) {
       // @todo: Currently hardcoded. We should have two implementation here:
@@ -19,8 +37,8 @@ class TreeFieldEntityReferenceBehavior extends EntityReference_BehaviorHandler_A
 
   public function provider($field) {
     if (!isset($this->providers[$field['field_name']])) {
-      // @todo: Currently hardcoded, make it onfigurable.
-      $provider = new Tree_Provider_NestedSet($this->storage($field));
+      $provider_name = !empty($field['settings']['handler_settings']['behaviors']['treefield_sql']['provider']) ? $field['settings']['handler_settings']['behaviors']['treefield_sql']['provider'] : 'Tree_Provider_Simple';
+      $provider = new $provider_name($this->storage($field));
 
       // Create the schema of the provider.
       // @todo: Move somewhere else.
diff --git a/treefield/views/treefield_views_handler_field_draggable.inc b/treefield/views/treefield_views_handler_field_draggable.inc
index 95c849f..7111632 100644
--- a/treefield/views/treefield_views_handler_field_draggable.inc
+++ b/treefield/views/treefield_views_handler_field_draggable.inc
@@ -3,9 +3,13 @@
 class treefield_views_handler_field_draggable extends views_handler_field {
 
   function post_execute(&$values) {
+    // Compute the depth of each item.
     // @todo: we need a depth field in the database.
-    $storage = new Tree_Storage_SQL_Field(Database::getConnection(), $this->definition['field api']);
-    $provider = new Tree_Provider_NestedSet($storage);
+    $field = field_info_field($this->definition['field api']);
+    $behaviors = entityreference_get_behavior_handlers($field);
+
+    $storage = $behaviors['tree']->storage($field);
+    $provider = $behaviors['tree']->provider($field);
     $column_map = $storage->getColumnMap();
     foreach ($values as $row_index => $row) {
       // Build an item.
