[evolution] Convert ETreeModel to an interface.



commit 69de51a15ab85e4dca9fed93a1e03644b0e6a840
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Jun 15 14:25:16 2013 -0400

    Convert ETreeModel to an interface.
    
    This commit does a number of things which I could not subdivide into
    smaller commits.
    
    * Converts ETreeModel to an interface, implemented by MessageList.
    
    * Drops ETreeMemory and ETreeMemoryCallbacks, which were ETreeModel
      subclasses.  Their functionality is subsumed by MessageList.
    
    * MessageList drops its public ETreeModel pointer, since MessageList
      now implements ETreeModel as an interface.
    
    * Adds message_list_set_expanded_default(), which takes over for
      e_tree_memory_set_expanded_default().

 .../evolution-util/evolution-util-docs.sgml        |    2 -
 .../evolution-util/evolution-util-sections.txt     |   60 +-
 doc/reference/evolution-util/evolution-util.types  |    1 -
 e-util/Makefile.am                                 |    4 -
 e-util/e-tree-memory-callbacks.c                   |  314 -----
 e-util/e-tree-memory-callbacks.h                   |  182 ---
 e-util/e-tree-memory.c                             |  356 -----
 e-util/e-tree-memory.h                             |   93 --
 e-util/e-tree-model.c                              |  286 ++---
 e-util/e-tree-model.h                              |   33 +-
 e-util/e-util.h                                    |    2 -
 mail/message-list.c                                | 1465 +++++++++++---------
 mail/message-list.h                                |    5 +-
 modules/settings/e-settings-message-list.c         |    4 +-
 14 files changed, 950 insertions(+), 1857 deletions(-)
---
diff --git a/doc/reference/evolution-util/evolution-util-docs.sgml 
b/doc/reference/evolution-util/evolution-util-docs.sgml
index d0e5160..155468e 100644
--- a/doc/reference/evolution-util/evolution-util-docs.sgml
+++ b/doc/reference/evolution-util/evolution-util-docs.sgml
@@ -145,8 +145,6 @@
     <xi:include href="xml/e-table-utils.xml"/>
     <xi:include href="xml/e-table-without.xml"/>
     <xi:include href="xml/e-tree.xml"/>
-    <xi:include href="xml/e-tree-memory-callbacks.xml"/>
-    <xi:include href="xml/e-tree-memory.xml"/>
     <xi:include href="xml/e-tree-model.xml"/>
     <xi:include href="xml/e-tree-selection-model.xml"/>
     <xi:include href="xml/e-tree-table-adapter.xml"/>
diff --git a/doc/reference/evolution-util/evolution-util-sections.txt 
b/doc/reference/evolution-util/evolution-util-sections.txt
index 2cb2911..2e8c9d2 100644
--- a/doc/reference/evolution-util/evolution-util-sections.txt
+++ b/doc/reference/evolution-util/evolution-util-sections.txt
@@ -4281,60 +4281,6 @@ ETreePrivate
 </SECTION>
 
 <SECTION>
-<FILE>e-tree-memory</FILE>
-<TITLE>ETreeMemory</TITLE>
-ETreeMemory
-e_tree_memory_node_insert
-e_tree_memory_node_remove
-e_tree_memory_freeze
-e_tree_memory_thaw
-e_tree_memory_set_expanded_default
-e_tree_memory_node_get_data
-e_tree_memory_node_set_data
-<SUBSECTION Standard>
-E_TREE_MEMORY
-E_IS_TREE_MEMORY
-E_TYPE_TREE_MEMORY
-E_TREE_MEMORY_CLASS
-E_IS_TREE_MEMORY_CLASS
-E_TREE_MEMORY_GET_CLASS
-ETreeMemoryClass
-e_tree_memory_get_type
-<SUBSECTION Private>
-ETreeMemoryPrivate
-</SECTION>
-
-<SECTION>
-<FILE>e-tree-memory-callbacks</FILE>
-<TITLE>ETreeMemoryCallbacks</TITLE>
-ETreeMemoryCallbacks
-ETreeMemoryCallbacksIconAtFn
-ETreeMemoryCallbacksColumnCountFn
-ETreeMemoryCallbacksHasSaveIdFn
-ETreeMemoryCallbacksGetSaveIdFn
-ETreeMemoryCallbacksHasGetNodeByIdFn
-ETreeMemoryCallbacksGetNodeByIdFn
-ETreeMemoryCallbacksValueAtFn
-ETreeMemoryCallbacksSetValueAtFn
-ETreeMemoryCallbacksIsEditableFn
-ETreeMemoryCallbacksDuplicateValueFn
-ETreeMemoryCallbacksFreeValueFn
-ETreeMemoryCallbacksInitializeValueFn
-ETreeMemoryCallbacksValueIsEmptyFn
-ETreeMemoryCallbacksValueToStringFn
-e_tree_memory_callbacks_new
-<SUBSECTION Standard>
-E_TREE_MEMORY_CALLBACKS
-E_IS_TREE_MEMORY_CALLBACKS
-E_TYPE_TREE_MEMORY_CALLBACKS
-E_TREE_MEMORY_CALLBACKS_CLASS
-E_IS_TREE_MEMORY_CALLBACKS_CLASS
-E_TREE_MEMORY_CALLBACKS_GET_CLASS
-ETreeMemoryCallbacksClass
-e_tree_memory_callbacks_get_type
-</SECTION>
-
-<SECTION>
 <FILE>e-tree-model</FILE>
 <TITLE>ETreeModel</TITLE>
 ETreeModel
@@ -4377,10 +4323,8 @@ e_tree_model_node_deleted
 E_TREE_MODEL
 E_IS_TREE_MODEL
 E_TYPE_TREE_MODEL
-E_TREE_MODEL_CLASS
-E_IS_TREE_MODEL_CLASS
-E_TREE_MODEL_GET_CLASS
-ETreeModelClass
+E_TREE_MODEL_GET_INTERFACE
+ETreeModelInterface
 e_tree_model_get_type
 </SECTION>
 
diff --git a/doc/reference/evolution-util/evolution-util.types 
b/doc/reference/evolution-util/evolution-util.types
index 68ed3eb..bc64175 100644
--- a/doc/reference/evolution-util/evolution-util.types
+++ b/doc/reference/evolution-util/evolution-util.types
@@ -154,7 +154,6 @@ e_text_get_type
 e_text_model_get_type
 e_timezone_dialog_get_type
 e_tree_get_type
-e_tree_memory_get_type
 e_tree_model_generator_get_type
 e_tree_model_get_type
 e_tree_selection_model_get_type
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index e0e4bf0..3990c88 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -293,8 +293,6 @@ evolution_util_include_HEADERS =  \
        e-text-model.h \
        e-text.h \
        e-timezone-dialog.h \
-       e-tree-memory-callbacks.h \
-       e-tree-memory.h \
        e-tree-model-generator.h \
        e-tree-model.h \
        e-tree-selection-model.h \
@@ -538,8 +536,6 @@ libevolution_util_la_SOURCES = \
        e-text-model.c \
        e-text.c \
        e-timezone-dialog.c \
-       e-tree-memory-callbacks.c \
-       e-tree-memory.c \
        e-tree-model-generator.c \
        e-tree-model.c \
        e-tree-selection-model.c \
diff --git a/e-util/e-tree-model.c b/e-util/e-tree-model.c
index d469d23..f9bf28a 100644
--- a/e-util/e-tree-model.c
+++ b/e-util/e-tree-model.c
@@ -1,4 +1,6 @@
 /*
+ * e-tree-model.c
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -12,37 +14,10 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  *
- *
- * Authors:
- *             Chris Lahey  <clahey ximian com>
- *             Chris Toshok <toshok ximian com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include "e-tree-model.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <gtk/gtk.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
-
-#include "e-marshal.h"
-#include "e-xml-utils.h"
-
-#define d(x)
-
-G_DEFINE_TYPE (ETreeModel, e_tree_model, G_TYPE_OBJECT)
-
 enum {
        PRE_CHANGE,
        NODE_CHANGED,
@@ -54,69 +29,63 @@ enum {
        LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL] = {0, };
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_INTERFACE (ETreeModel, e_tree_model, G_TYPE_OBJECT)
 
 static void
-e_tree_model_class_init (ETreeModelClass *class)
+e_tree_model_default_init (ETreeModelInterface *interface)
 {
-       GObjectClass *object_class = G_OBJECT_CLASS (class);
-
        signals[PRE_CHANGE] = g_signal_new (
                "pre_change",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, pre_change),
-               (GSignalAccumulator) NULL, NULL,
-               g_cclosure_marshal_VOID__VOID,
+               G_STRUCT_OFFSET (ETreeModelInterface, pre_change),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 0);
 
        signals[REBUILT] = g_signal_new (
                "rebuilt",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, rebuilt),
-               (GSignalAccumulator) NULL, NULL,
-               g_cclosure_marshal_VOID__VOID,
+               G_STRUCT_OFFSET (ETreeModelInterface, rebuilt),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 0);
 
        signals[NODE_CHANGED] = g_signal_new (
                "node_changed",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, node_changed),
-               (GSignalAccumulator) NULL, NULL,
-               g_cclosure_marshal_VOID__POINTER,
+               G_STRUCT_OFFSET (ETreeModelInterface, node_changed),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 1,
                G_TYPE_POINTER);
 
        signals[NODE_DATA_CHANGED] = g_signal_new (
                "node_data_changed",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, node_data_changed),
-               (GSignalAccumulator) NULL, NULL,
-               g_cclosure_marshal_VOID__POINTER,
+               G_STRUCT_OFFSET (ETreeModelInterface, node_data_changed),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 1,
                G_TYPE_POINTER);
 
        signals[NODE_INSERTED] = g_signal_new (
                "node_inserted",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, node_inserted),
-               (GSignalAccumulator) NULL, NULL,
-               e_marshal_VOID__POINTER_POINTER,
+               G_STRUCT_OFFSET (ETreeModelInterface, node_inserted),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 2,
                G_TYPE_POINTER,
                G_TYPE_POINTER);
 
        signals[NODE_REMOVED] = g_signal_new (
                "node_removed",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, node_removed),
-               (GSignalAccumulator) NULL, NULL,
-               e_marshal_VOID__POINTER_POINTER_INT,
+               G_STRUCT_OFFSET (ETreeModelInterface, node_removed),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 3,
                G_TYPE_POINTER,
                G_TYPE_POINTER,
@@ -124,23 +93,14 @@ e_tree_model_class_init (ETreeModelClass *class)
 
        signals[NODE_DELETED] = g_signal_new (
                "node_deleted",
-               G_TYPE_FROM_CLASS (object_class),
+               G_TYPE_FROM_INTERFACE (interface),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ETreeModelClass, node_deleted),
-               (GSignalAccumulator) NULL, NULL,
-               g_cclosure_marshal_VOID__POINTER,
+               G_STRUCT_OFFSET (ETreeModelInterface, node_deleted),
+               NULL, NULL, NULL,
                G_TYPE_NONE, 1,
                G_TYPE_POINTER);
 }
 
-static void
-e_tree_model_init (ETreeModel *tree_model)
-{
-       /* nothing to do */
-}
-
-/* signals */
-
 /**
  * e_tree_model_pre_change:
  * @tree_model:
@@ -272,14 +232,14 @@ e_tree_model_node_deleted (ETreeModel *tree_model,
 ETreePath
 e_tree_model_get_root (ETreeModel *tree_model)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_root != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_root != NULL, NULL);
 
-       return class->get_root (tree_model);
+       return interface->get_root (tree_model);
 }
 
 /**
@@ -295,14 +255,14 @@ ETreePath
 e_tree_model_node_get_parent (ETreeModel *tree_model,
                               ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_parent != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_parent != NULL, NULL);
 
-       return class->get_parent (tree_model, path);
+       return interface->get_parent (tree_model, path);
 }
 
 /**
@@ -318,14 +278,14 @@ ETreePath
 e_tree_model_node_get_first_child (ETreeModel *tree_model,
                                    ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_first_child != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_first_child != NULL, NULL);
 
-       return class->get_first_child (tree_model, path);
+       return interface->get_first_child (tree_model, path);
 }
 
 /**
@@ -341,14 +301,14 @@ ETreePath
 e_tree_model_node_get_next (ETreeModel *tree_model,
                             ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_next != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_next != NULL, NULL);
 
-       return class->get_next (tree_model, path);
+       return interface->get_next (tree_model, path);
 }
 
 /**
@@ -364,14 +324,14 @@ gboolean
 e_tree_model_node_is_root (ETreeModel *tree_model,
                            ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->is_root != NULL, FALSE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->is_root != NULL, FALSE);
 
-       return class->is_root (tree_model, path);
+       return interface->is_root (tree_model, path);
 }
 
 /**
@@ -387,29 +347,29 @@ gboolean
 e_tree_model_node_is_expandable (ETreeModel *tree_model,
                                  ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE);
        g_return_val_if_fail (path != NULL, FALSE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->is_expandable != NULL, FALSE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->is_expandable != NULL, FALSE);
 
-       return class->is_expandable (tree_model, path);
+       return interface->is_expandable (tree_model, path);
 }
 
 guint
 e_tree_model_node_get_n_children (ETreeModel *tree_model,
                                   ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_n_children != NULL, 0);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_n_children != NULL, 0);
 
-       return class->get_n_children (tree_model, path);
+       return interface->get_n_children (tree_model, path);
 }
 
 /**
@@ -425,14 +385,14 @@ guint
 e_tree_model_node_depth (ETreeModel *tree_model,
                          ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->depth != NULL, 0);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->depth != NULL, 0);
 
-       return class->depth (tree_model, path);
+       return interface->depth (tree_model, path);
 }
 
 /**
@@ -448,14 +408,14 @@ GdkPixbuf *
 e_tree_model_icon_at (ETreeModel *tree_model,
                       ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->icon_at != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->icon_at != NULL, NULL);
 
-       return class->icon_at (tree_model, path);
+       return interface->icon_at (tree_model, path);
 }
 
 /**
@@ -469,14 +429,14 @@ e_tree_model_icon_at (ETreeModel *tree_model,
 gboolean
 e_tree_model_get_expanded_default (ETreeModel *tree_model)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_expanded_default != NULL, FALSE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_expanded_default != NULL, FALSE);
 
-       return class->get_expanded_default (tree_model);
+       return interface->get_expanded_default (tree_model);
 }
 
 /**
@@ -490,14 +450,14 @@ e_tree_model_get_expanded_default (ETreeModel *tree_model)
 gint
 e_tree_model_column_count (ETreeModel *tree_model)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->column_count != NULL, 0);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->column_count != NULL, 0);
 
-       return class->column_count (tree_model);
+       return interface->column_count (tree_model);
 }
 
 /**
@@ -511,14 +471,14 @@ e_tree_model_column_count (ETreeModel *tree_model)
 gboolean
 e_tree_model_has_save_id (ETreeModel *tree_model)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->has_save_id != NULL, FALSE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->has_save_id != NULL, FALSE);
 
-       return class->has_save_id (tree_model);
+       return interface->has_save_id (tree_model);
 }
 
 /**
@@ -534,14 +494,14 @@ gchar *
 e_tree_model_get_save_id (ETreeModel *tree_model,
                           ETreePath path)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_save_id != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_save_id != NULL, NULL);
 
-       return class->get_save_id (tree_model, path);
+       return interface->get_save_id (tree_model, path);
 }
 
 /**
@@ -555,14 +515,14 @@ e_tree_model_get_save_id (ETreeModel *tree_model,
 gboolean
 e_tree_model_has_get_node_by_id (ETreeModel *tree_model)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->has_get_node_by_id != NULL, FALSE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->has_get_node_by_id != NULL, FALSE);
 
-       return class->has_get_node_by_id (tree_model);
+       return interface->has_get_node_by_id (tree_model);
 }
 
 /**
@@ -581,14 +541,14 @@ ETreePath
 e_tree_model_get_node_by_id (ETreeModel *tree_model,
                              const gchar *save_id)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->get_node_by_id != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->get_node_by_id != NULL, NULL);
 
-       return class->get_node_by_id (tree_model, save_id);
+       return interface->get_node_by_id (tree_model, save_id);
 }
 
 /**
@@ -616,14 +576,14 @@ e_tree_model_sort_value_at (ETreeModel *tree_model,
                             ETreePath path,
                             gint col)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->sort_value_at != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->sort_value_at != NULL, NULL);
 
-       return class->sort_value_at (tree_model, path, col);
+       return interface->sort_value_at (tree_model, path, col);
 }
 
 /**
@@ -650,14 +610,14 @@ e_tree_model_value_at (ETreeModel *tree_model,
                        ETreePath path,
                        gint col)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->value_at != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->value_at != NULL, NULL);
 
-       return class->value_at (tree_model, path, col);
+       return interface->value_at (tree_model, path, col);
 }
 
 void
@@ -666,14 +626,14 @@ e_tree_model_set_value_at (ETreeModel *tree_model,
                            gint col,
                            gconstpointer val)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_if_fail (E_IS_TREE_MODEL (tree_model));
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_if_fail (class->set_value_at != NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_if_fail (interface->set_value_at != NULL);
 
-       class->set_value_at (tree_model, path, col, val);
+       interface->set_value_at (tree_model, path, col, val);
 }
 
 /**
@@ -690,14 +650,14 @@ e_tree_model_node_is_editable (ETreeModel *tree_model,
                                ETreePath path,
                                gint col)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->is_editable != NULL, FALSE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->is_editable != NULL, FALSE);
 
-       return class->is_editable (tree_model, path, col);
+       return interface->is_editable (tree_model, path, col);
 }
 
 /**
@@ -714,14 +674,14 @@ e_tree_model_duplicate_value (ETreeModel *tree_model,
                               gint col,
                               gconstpointer value)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->duplicate_value != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->duplicate_value != NULL, NULL);
 
-       return class->duplicate_value (tree_model, col, value);
+       return interface->duplicate_value (tree_model, col, value);
 }
 
 /**
@@ -738,14 +698,14 @@ e_tree_model_free_value (ETreeModel *tree_model,
                          gint col,
                          gpointer value)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_if_fail (E_IS_TREE_MODEL (tree_model));
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_if_fail (class->free_value != NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_if_fail (interface->free_value != NULL);
 
-       class->free_value (tree_model, col, value);
+       interface->free_value (tree_model, col, value);
 }
 
 /**
@@ -761,14 +721,14 @@ gpointer
 e_tree_model_initialize_value (ETreeModel *tree_model,
                                gint col)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->initialize_value != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->initialize_value != NULL, NULL);
 
-       return class->initialize_value (tree_model, col);
+       return interface->initialize_value (tree_model, col);
 }
 
 /**
@@ -785,14 +745,14 @@ e_tree_model_value_is_empty (ETreeModel *tree_model,
                              gint col,
                              gconstpointer value)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), TRUE);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->value_is_empty != NULL, TRUE);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->value_is_empty != NULL, TRUE);
 
-       return class->value_is_empty (tree_model, col, value);
+       return interface->value_is_empty (tree_model, col, value);
 }
 
 /**
@@ -809,14 +769,14 @@ e_tree_model_value_to_string (ETreeModel *tree_model,
                               gint col,
                               gconstpointer value)
 {
-       ETreeModelClass *class;
+       ETreeModelInterface *interface;
 
        g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL);
 
-       class = E_TREE_MODEL_GET_CLASS (tree_model);
-       g_return_val_if_fail (class->value_to_string != NULL, NULL);
+       interface = E_TREE_MODEL_GET_INTERFACE (tree_model);
+       g_return_val_if_fail (interface->value_to_string != NULL, NULL);
 
-       return class->value_to_string (tree_model, col, value);
+       return interface->value_to_string (tree_model, col, value);
 }
 
 /**
diff --git a/e-util/e-tree-model.h b/e-util/e-tree-model.h
index 431f93e..bdbf64c 100644
--- a/e-util/e-tree-model.h
+++ b/e-util/e-tree-model.h
@@ -1,4 +1,5 @@
 /*
+ * e-tree-model.h
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -13,13 +14,6 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  *
- *
- * Authors:
- *             Chris Lahey <clahey ximian com>
- *             Chris Toshok <toshok ximian com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
@@ -37,40 +31,27 @@
 #define E_TREE_MODEL(obj) \
        (G_TYPE_CHECK_INSTANCE_CAST \
        ((obj), E_TYPE_TREE_MODEL, ETreeModel))
-#define E_TREE_MODEL_CLASS(cls) \
-       (G_TYPE_CHECK_CLASS_CAST \
-       ((cls), E_TYPE_TREE_MODEL, ETreeModelClass))
 #define E_IS_TREE_MODEL(obj) \
        (G_TYPE_CHECK_INSTANCE_TYPE \
        ((obj), E_TYPE_TREE_MODEL))
-#define E_IS_TREE_MODEL_CLASS(cls) \
-       (G_TYPE_CHECK_CLASS_TYPE \
-       ((cls), E_TYPE_TREE_MODEL))
-#define E_TREE_MODEL_GET_CLASS(obj) \
-       (G_TYPE_INSTANCE_GET_CLASS \
-       ((obj), E_TYPE_TREE_MODEL, ETreeModelClass))
+#define E_TREE_MODEL_GET_INTERFACE(obj) \
+       (G_TYPE_INSTANCE_GET_INTERFACE \
+       ((obj), E_TYPE_TREE_MODEL, ETreeModelInterface))
 
 G_BEGIN_DECLS
 
 typedef gpointer ETreePath;
 
 typedef struct _ETreeModel ETreeModel;
-typedef struct _ETreeModelClass ETreeModelClass;
+typedef struct _ETreeModelInterface ETreeModelInterface;
 
 typedef gboolean       (*ETreePathFunc)        (ETreeModel *tree_model,
                                                 ETreePath path,
                                                 gpointer data);
 
-struct _ETreeModel {
-       GObject parent;
-};
+struct _ETreeModelInterface {
+       GTypeInterface parent_class;
 
-struct _ETreeModelClass {
-       GObjectClass parent_class;
-
-       /*
-        * Virtual methods
-        */
        ETreePath       (*get_root)             (ETreeModel *tree_model);
 
        ETreePath       (*get_parent)           (ETreeModel *tree_model,
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 40a0e14..c21add2 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -209,8 +209,6 @@
 #include <e-util/e-text-model.h>
 #include <e-util/e-text.h>
 #include <e-util/e-timezone-dialog.h>
-#include <e-util/e-tree-memory-callbacks.h>
-#include <e-util/e-tree-memory.h>
 #include <e-util/e-tree-model-generator.h>
 #include <e-util/e-tree-model.h>
 #include <e-util/e-tree-selection-model.h>
diff --git a/mail/message-list.c b/mail/message-list.c
index b0fd942..ae7e351 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -102,6 +102,7 @@ struct _MessageListPrivate {
        struct _MLSelection clipboard;
        gboolean destroyed;
 
+       gboolean expanded_default;
        gboolean group_by_threads;
        gboolean show_deleted;
        gboolean thread_latest;
@@ -111,6 +112,12 @@ struct _MessageListPrivate {
        GtkTargetList *copy_target_list;
        GtkTargetList *paste_target_list;
 
+       /* XXX Not sure if we really need a separate frozen counter
+        *     for the tree model but the old ETreeMemory class had
+        *     its own frozen counter so we preserve it here. */
+       GNode *tree_model_root;
+       gint tree_model_frozen;
+
        /* This aids in automatic message selection. */
        time_t newest_read_date;
        const gchar *newest_read_uid;
@@ -165,6 +172,8 @@ enum {
 /* Forward Declarations */
 static void    message_list_selectable_init
                                        (ESelectableInterface *interface);
+static void    message_list_tree_model_init
+                                       (ETreeModelInterface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (
        MessageList,
@@ -174,7 +183,10 @@ G_DEFINE_TYPE_WITH_CODE (
                E_TYPE_EXTENSIBLE, NULL)
        G_IMPLEMENT_INTERFACE (
                E_TYPE_SELECTABLE,
-               message_list_selectable_init))
+               message_list_selectable_init)
+       G_IMPLEMENT_INTERFACE (
+               E_TYPE_TREE_MODEL,
+               message_list_tree_model_init))
 
 static struct {
        const gchar *target;
@@ -238,18 +250,16 @@ enum {
 
 static void    on_cursor_activated_cmd         (ETree *tree,
                                                 gint row,
-                                                ETreePath path,
+                                                GNode *node,
                                                 gpointer user_data);
 static void    on_selection_changed_cmd        (ETree *tree,
                                                 MessageList *message_list);
 static gint    on_click                        (ETree *tree,
                                                 gint row,
-                                                ETreePath path,
+                                                GNode *node,
                                                 gint col,
                                                 GdkEvent *event,
                                                 MessageList *message_list);
-static gchar * filter_date                     (time_t date);
-static gchar * filter_size                     (gint size);
 
 static void    mail_regen_list                 (MessageList *message_list,
                                                 const gchar *search,
@@ -257,7 +267,7 @@ static void mail_regen_list                 (MessageList *message_list,
 static void    mail_regen_cancel               (MessageList *message_list);
 
 static void    clear_info                      (gchar *key,
-                                                ETreePath *node,
+                                                GNode *node,
                                                 MessageList *message_list);
 
 enum {
@@ -268,6 +278,15 @@ enum {
 
 static guint signals[LAST_SIGNAL] = {0, };
 
+static const gchar *status_map[] = {
+       N_("Unseen"),
+       N_("Seen"),
+       N_("Answered"),
+       N_("Forwarded"),
+       N_("Multiple Unseen Messages"),
+       N_("Multiple Messages"),
+};
+
 static const gchar *status_icons[] = {
        "mail-unread",
        "mail-read",
@@ -277,6 +296,16 @@ static const gchar *status_icons[] = {
        "stock_mail-open-multiple"
 };
 
+static const gchar *score_map[] = {
+       N_("Lowest"),
+       N_("Lower"),
+       N_("Low"),
+       N_("Normal"),
+       N_("High"),
+       N_("Higher"),
+       N_("Highest"),
+};
+
 static const gchar *score_icons[] = {
        "stock_score-lowest",
        "stock_score-lower",
@@ -406,6 +435,96 @@ message_list_ref_regen_data (MessageList *message_list)
        return regen_data;
 }
 
+static void
+message_list_tree_model_freeze (MessageList *message_list)
+{
+       if (message_list->priv->tree_model_frozen == 0)
+               e_tree_model_pre_change (E_TREE_MODEL (message_list));
+
+       message_list->priv->tree_model_frozen++;
+}
+
+static void
+message_list_tree_model_thaw (MessageList *message_list)
+{
+       if (message_list->priv->tree_model_frozen > 0)
+               message_list->priv->tree_model_frozen--;
+
+       if (message_list->priv->tree_model_frozen == 0)
+               e_tree_model_node_changed (
+                       E_TREE_MODEL (message_list),
+                       message_list->priv->tree_model_root);
+}
+
+static GNode *
+message_list_tree_model_insert (MessageList *message_list,
+                                GNode *parent,
+                                gint position,
+                                gpointer data)
+{
+       ETreeModel *tree_model;
+       GNode *node;
+       gboolean tree_model_frozen;
+
+       if (parent == NULL)
+               g_return_val_if_fail (
+                       message_list->priv->tree_model_root == NULL, NULL);
+
+       tree_model = E_TREE_MODEL (message_list);
+       tree_model_frozen = (message_list->priv->tree_model_frozen > 0);
+
+       if (!tree_model_frozen)
+               e_tree_model_pre_change (tree_model);
+
+       node = g_node_new (data);
+
+       if (parent != NULL) {
+               g_node_insert (parent, position, node);
+               if (!tree_model_frozen)
+                       e_tree_model_node_inserted (tree_model, parent, node);
+       } else {
+               message_list->priv->tree_model_root = node;
+               if (!tree_model_frozen)
+                       e_tree_model_node_changed (tree_model, node);
+       }
+
+       return node;
+}
+
+static void
+message_list_tree_model_remove (MessageList *message_list,
+                                GNode *node)
+{
+       ETreeModel *tree_model;
+       GNode *parent = node->parent;
+       gboolean tree_model_frozen;
+       gint old_position = 0;
+
+       g_return_if_fail (node != NULL);
+
+       tree_model = E_TREE_MODEL (message_list);
+       tree_model_frozen = (message_list->priv->tree_model_frozen > 0);
+
+       if (!tree_model_frozen) {
+               e_tree_model_pre_change (tree_model);
+               old_position = g_node_child_position (parent, node);
+       }
+
+       g_node_unlink (node);
+
+       if (!tree_model_frozen)
+               e_tree_model_node_removed (
+                       tree_model, parent, node, old_position);
+
+       g_node_destroy (node);
+
+       if (node == message_list->priv->tree_model_root)
+               message_list->priv->tree_model_root = NULL;
+
+       if (!tree_model_frozen)
+               e_tree_model_node_deleted (tree_model, node);
+}
+
 static gint
 address_compare (gconstpointer address1,
                  gconstpointer address2,
@@ -442,16 +561,12 @@ filter_size (gint size)
 /* Gets the uid of the message displayed at a given view row */
 static const gchar *
 get_message_uid (MessageList *message_list,
-                 ETreePath node)
+                 GNode *node)
 {
-       CamelMessageInfo *info;
-
        g_return_val_if_fail (node != NULL, NULL);
-       info = e_tree_memory_node_get_data (E_TREE_MEMORY (message_list->model), node);
-       /* correct me if I'm wrong, but this should never be NULL, should it? */
-       g_return_val_if_fail (info != NULL, NULL);
+       g_return_val_if_fail (node->data != NULL, NULL);
 
-       return camel_message_info_uid (info);
+       return camel_message_info_uid (node->data);
 }
 
 /* Gets the CamelMessageInfo for the message displayed at the given
@@ -459,15 +574,12 @@ get_message_uid (MessageList *message_list,
  */
 static CamelMessageInfo *
 get_message_info (MessageList *message_list,
-                  ETreePath node)
+                  GNode *node)
 {
-       CamelMessageInfo *info;
-
        g_return_val_if_fail (node != NULL, NULL);
-       info = e_tree_memory_node_get_data (E_TREE_MEMORY (message_list->model), node);
-       g_return_val_if_fail (info != NULL, NULL);
+       g_return_val_if_fail (node->data != NULL, NULL);
 
-       return info;
+       return node->data;
 }
 
 static const gchar *
@@ -558,14 +670,14 @@ clear_selection (MessageList *message_list,
        g_clear_object (&selection->folder);
 }
 
-static ETreePath
+static GNode *
 ml_search_forward (MessageList *message_list,
                    gint start,
                    gint end,
                    guint32 flags,
                    guint32 mask)
 {
-       ETreePath path;
+       GNode *node;
        gint row;
        CamelMessageInfo *info;
        ETreeTableAdapter *etta;
@@ -573,24 +685,24 @@ ml_search_forward (MessageList *message_list,
        etta = e_tree_get_table_adapter (E_TREE (message_list));
 
        for (row = start; row <= end; row++) {
-               path = e_tree_table_adapter_node_at_row (etta, row);
-               if (path
-                   && (info = get_message_info (message_list, path))
+               node = e_tree_table_adapter_node_at_row (etta, row);
+               if (node != NULL
+                   && (info = get_message_info (message_list, node))
                    && (camel_message_info_flags (info) & mask) == flags)
-                       return path;
+                       return node;
        }
 
        return NULL;
 }
 
-static ETreePath
+static GNode *
 ml_search_backward (MessageList *message_list,
                     gint start,
                     gint end,
                     guint32 flags,
                     guint32 mask)
 {
-       ETreePath path;
+       GNode *node;
        gint row;
        CamelMessageInfo *info;
        ETreeTableAdapter *etta;
@@ -598,23 +710,23 @@ ml_search_backward (MessageList *message_list,
        etta = e_tree_get_table_adapter (E_TREE (message_list));
 
        for (row = start; row >= end; row--) {
-               path = e_tree_table_adapter_node_at_row (etta, row);
-               if (path
-                   && (info = get_message_info (message_list, path))
+               node = e_tree_table_adapter_node_at_row (etta, row);
+               if (node != NULL
+                   && (info = get_message_info (message_list, node))
                    && (camel_message_info_flags (info) & mask) == flags)
-                       return path;
+                       return node;
        }
 
        return NULL;
 }
 
-static ETreePath
+static GNode *
 ml_search_path (MessageList *message_list,
                 MessageListSelectDirection direction,
                 guint32 flags,
                 guint32 mask)
 {
-       ETreePath node;
+       GNode *node;
        gint row, count;
        ETreeTableAdapter *etta;
 
@@ -649,8 +761,8 @@ ml_search_path (MessageList *message_list,
 }
 
 static void
-select_path (MessageList *message_list,
-             ETreePath path)
+select_node (MessageList *message_list,
+             GNode *node)
 {
        ETree *tree;
        ETreeTableAdapter *etta;
@@ -663,9 +775,9 @@ select_path (MessageList *message_list,
        g_free (message_list->cursor_uid);
        message_list->cursor_uid = NULL;
 
-       e_tree_table_adapter_show_node (etta, path);
-       e_tree_set_cursor (tree, path);
-       e_tree_selection_model_select_single_path (etsm, path);
+       e_tree_table_adapter_show_node (etta, node);
+       e_tree_set_cursor (tree, node);
+       e_tree_selection_model_select_single_path (etsm, node);
 }
 
 /**
@@ -693,11 +805,11 @@ message_list_select (MessageList *message_list,
                      guint32 flags,
                      guint32 mask)
 {
-       ETreePath path;
+       GNode *node;
 
-       path = ml_search_path (message_list, direction, flags, mask);
-       if (path) {
-               select_path (message_list, path);
+       node = ml_search_path (message_list, direction, flags, mask);
+       if (node != NULL) {
+               select_node (message_list, node);
 
                /* This function is usually called in response to a key
                 * press, so grab focus if the message list is visible. */
@@ -743,7 +855,7 @@ message_list_select_uid (MessageList *message_list,
 {
        MessageListPrivate *priv;
        GHashTable *uid_nodemap;
-       ETreePath node = NULL;
+       GNode *node = NULL;
        RegenData *regen_data = NULL;
 
        g_return_if_fail (IS_MESSAGE_LIST (message_list));
@@ -788,7 +900,7 @@ message_list_select_uid (MessageList *message_list,
 
        if (node) {
                ETree *tree;
-               ETreePath old_cur;
+               GNode *old_cur;
 
                tree = E_TREE (message_list);
                old_cur = e_tree_get_cursor (tree);
@@ -814,10 +926,12 @@ message_list_select_uid (MessageList *message_list,
 void
 message_list_select_next_thread (MessageList *message_list)
 {
-       ETreePath node;
+       GNode *node;
        ETreeTableAdapter *etta;
        gint i, count, row;
 
+       g_return_if_fail (IS_MESSAGE_LIST (message_list));
+
        etta = e_tree_get_table_adapter (E_TREE (message_list));
 
        if (!message_list->cursor_uid
@@ -832,9 +946,8 @@ message_list_select_next_thread (MessageList *message_list)
        /* find the next node which has a root parent (i.e. toplevel node) */
        for (i = row + 1; i < count - 1; i++) {
                node = e_tree_table_adapter_node_at_row (etta, i);
-               if (node
-                   && e_tree_model_node_is_root (message_list->model, e_tree_model_node_get_parent 
(message_list->model, node))) {
-                       select_path (message_list, node);
+               if (node != NULL && G_NODE_IS_ROOT (node->parent)) {
+                       select_node (message_list, node);
                        return;
                }
        }
@@ -843,11 +956,13 @@ message_list_select_next_thread (MessageList *message_list)
 void
 message_list_select_prev_thread (MessageList *message_list)
 {
-       ETreePath node;
+       GNode *node;
        ETreeTableAdapter *etta;
        gint i, row;
        gboolean skip_first;
 
+       g_return_if_fail (IS_MESSAGE_LIST (message_list));
+
        etta = e_tree_get_table_adapter (E_TREE (message_list));
 
        if (!message_list->cursor_uid
@@ -859,21 +974,18 @@ message_list_select_prev_thread (MessageList *message_list)
                return;
 
        /* skip first found if in the middle of the thread */
-       skip_first = !e_tree_model_node_is_root (
-               message_list->model,
-               e_tree_model_node_get_parent (message_list->model, node));
+       skip_first = !G_NODE_IS_ROOT (node->parent);
 
        /* find the previous node which has a root parent (i.e. toplevel node) */
        for (i = row - 1; i >= 0; i--) {
                node = e_tree_table_adapter_node_at_row (etta, i);
-               if (node
-                   && e_tree_model_node_is_root (message_list->model, e_tree_model_node_get_parent 
(message_list->model, node))) {
+               if (node != NULL && G_NODE_IS_ROOT (node->parent)) {
                        if (skip_first) {
                                skip_first = FALSE;
                                continue;
                        }
 
-                       select_path (message_list, node);
+                       select_node (message_list, node);
                        return;
                }
        }
@@ -915,20 +1027,20 @@ typedef struct thread_select_info {
 } thread_select_info_t;
 
 static gboolean
-select_node (ETreeModel *model,
-             ETreePath path,
-             gpointer user_data)
+select_thread_node (ETreeModel *model,
+                    GNode *node,
+                    gpointer user_data)
 {
        thread_select_info_t *tsi = (thread_select_info_t *) user_data;
 
-       g_ptr_array_add (tsi->paths, path);
+       g_ptr_array_add (tsi->paths, node);
+
        return FALSE; /*not done yet */
 }
 
 static void
 select_thread (MessageList *message_list,
-               void (*selector) (ETreePath,
-                                 gpointer))
+               ETreeForeachFunc selector)
 {
        ETree *tree;
        ETreeSelectionModel *etsm;
@@ -952,19 +1064,21 @@ thread_select_foreach (ETreePath path,
                        gpointer user_data)
 {
        thread_select_info_t *tsi = (thread_select_info_t *) user_data;
-       ETreeModel *model = tsi->message_list->model;
-       ETreePath node, last;
+       ETreeModel *tree_model;
+       GNode *last, *node = path;
 
-       node = path;
+       tree_model = E_TREE_MODEL (tsi->message_list);
 
        do {
                last = node;
-               node = e_tree_model_node_get_parent (model, node);
-       } while (!e_tree_model_node_is_root (model, node));
+               node = node->parent;
+       } while (!G_NODE_IS_ROOT (node));
 
        g_ptr_array_add (tsi->paths, last);
 
-       e_tree_model_node_traverse (model, last, select_node, tsi);
+       e_tree_model_node_traverse (
+               tree_model, last,
+               (ETreePathFunc) select_thread_node, tsi);
 }
 
 /**
@@ -984,9 +1098,13 @@ subthread_select_foreach (ETreePath path,
                           gpointer user_data)
 {
        thread_select_info_t *tsi = (thread_select_info_t *) user_data;
-       ETreeModel *model = tsi->message_list->model;
+       ETreeModel *tree_model;
+
+       tree_model = E_TREE_MODEL (tsi->message_list);
 
-       e_tree_model_node_traverse (model, path, select_node, tsi);
+       e_tree_model_node_traverse (
+               tree_model, path,
+               (ETreePathFunc) select_thread_node, tsi);
 }
 
 /**
@@ -1076,342 +1194,40 @@ message_list_paste (MessageList *message_list)
                GDK_CURRENT_TIME);
 }
 
-/*
- * SimpleTableModel::col_count
- */
-static gint
-ml_column_count (ETreeModel *etm,
-                 gpointer data)
-{
-       return COL_LAST;
-}
-
-/*
- * SimpleTableModel::has_save_id
- */
-static gboolean
-ml_has_save_id (ETreeModel *etm,
-                gpointer data)
-{
-       return TRUE;
-}
-
-/*
- * SimpleTableModel::get_save_id
- */
-static gchar *
-ml_get_save_id (ETreeModel *etm,
-                ETreePath path,
-                gpointer data)
-{
-       CamelMessageInfo *info;
-
-       if (e_tree_model_node_is_root (etm, path))
-               return g_strdup ("root");
-
-       /* Note: etable can ask for the save_id while we're clearing it,
-        * which is the only time data should be null */
-       info = e_tree_memory_node_get_data (E_TREE_MEMORY (etm), path);
-       if (info == NULL)
-               return NULL;
-
-       return g_strdup (camel_message_info_uid (info));
-}
-
-/*
- * SimpleTableModel::has_save_id
- */
-static gboolean
-ml_has_get_node_by_id (ETreeModel *etm,
-                       gpointer data)
-{
-       return TRUE;
-}
-
-/*
- * SimpleTableModel::get_save_id
- */
-static ETreePath
-ml_get_node_by_id (ETreeModel *etm,
-                   const gchar *save_id,
-                   gpointer data)
-{
-       MessageList *message_list;
-
-       message_list = data;
-
-       if (!strcmp (save_id, "root"))
-               return e_tree_model_get_root (etm);
-
-       return g_hash_table_lookup (message_list->uid_nodemap, save_id);
-}
-
-static gpointer
-ml_duplicate_value (ETreeModel *etm,
-                    gint col,
-                    gconstpointer value,
-                    gpointer data)
-{
-       switch (col) {
-       case COL_MESSAGE_STATUS:
-       case COL_FLAGGED:
-       case COL_SCORE:
-       case COL_ATTACHMENT:
-       case COL_DELETED:
-       case COL_UNREAD:
-       case COL_SENT:
-       case COL_RECEIVED:
-       case COL_SIZE:
-       case COL_FOLLOWUP_FLAG_STATUS:
-       case COL_FOLLOWUP_DUE_BY:
-               return (gpointer) value;
-
-       case COL_FROM:
-       case COL_SUBJECT:
-       case COL_TO:
-       case COL_SENDER:
-       case COL_RECIPIENTS:
-       case COL_MIXED_SENDER:
-       case COL_MIXED_RECIPIENTS:
-       case COL_FOLLOWUP_FLAG:
-       case COL_LOCATION:
-       case COL_LABELS:
-               return g_strdup (value);
-       default:
-               g_warning ("This shouldn't be reached\n");
-       }
-       return NULL;
-}
-
-static void
-ml_free_value (ETreeModel *etm,
-               gint col,
-               gpointer value,
-               gpointer data)
-{
-       switch (col) {
-       case COL_MESSAGE_STATUS:
-       case COL_FLAGGED:
-       case COL_SCORE:
-       case COL_ATTACHMENT:
-       case COL_DELETED:
-       case COL_UNREAD:
-       case COL_SENT:
-       case COL_RECEIVED:
-       case COL_SIZE:
-       case COL_FOLLOWUP_FLAG_STATUS:
-       case COL_FOLLOWUP_DUE_BY:
-       case COL_FROM_NORM:
-       case COL_SUBJECT_NORM:
-       case COL_TO_NORM:
-       case COL_SUBJECT_TRIMMED:
-       case COL_COLOUR:
-               break;
-
-       case COL_FROM:
-       case COL_SUBJECT:
-       case COL_TO:
-       case COL_FOLLOWUP_FLAG:
-       case COL_LOCATION:
-       case COL_SENDER:
-       case COL_RECIPIENTS:
-       case COL_MIXED_SENDER:
-       case COL_MIXED_RECIPIENTS:
-       case COL_LABELS:
-               g_free (value);
-               break;
-       default:
-               g_warning ("%s: This shouldn't be reached (col:%d)", G_STRFUNC, col);
-       }
-}
-
-static gpointer
-ml_initialize_value (ETreeModel *etm,
-                     gint col,
-                     gpointer data)
-{
-       switch (col) {
-       case COL_MESSAGE_STATUS:
-       case COL_FLAGGED:
-       case COL_SCORE:
-       case COL_ATTACHMENT:
-       case COL_DELETED:
-       case COL_UNREAD:
-       case COL_SENT:
-       case COL_RECEIVED:
-       case COL_SIZE:
-       case COL_FOLLOWUP_FLAG_STATUS:
-       case COL_FOLLOWUP_DUE_BY:
-               return NULL;
-
-       case COL_FROM:
-       case COL_SUBJECT:
-       case COL_TO:
-       case COL_FOLLOWUP_FLAG:
-       case COL_LOCATION:
-       case COL_SENDER:
-       case COL_RECIPIENTS:
-       case COL_MIXED_SENDER:
-       case COL_MIXED_RECIPIENTS:
-       case COL_LABELS:
-               return g_strdup ("");
-       default:
-               g_warning ("This shouldn't be reached\n");
-       }
-
-       return NULL;
-}
-
-static gboolean
-ml_value_is_empty (ETreeModel *etm,
-                   gint col,
-                   gconstpointer value,
-                   gpointer data)
-{
-       switch (col) {
-       case COL_MESSAGE_STATUS:
-       case COL_FLAGGED:
-       case COL_SCORE:
-       case COL_ATTACHMENT:
-       case COL_DELETED:
-       case COL_UNREAD:
-       case COL_SENT:
-       case COL_RECEIVED:
-       case COL_SIZE:
-       case COL_FOLLOWUP_FLAG_STATUS:
-       case COL_FOLLOWUP_DUE_BY:
-               return value == NULL;
-
-       case COL_FROM:
-       case COL_SUBJECT:
-       case COL_TO:
-       case COL_FOLLOWUP_FLAG:
-       case COL_LOCATION:
-       case COL_SENDER:
-       case COL_RECIPIENTS:
-       case COL_MIXED_SENDER:
-       case COL_MIXED_RECIPIENTS:
-       case COL_LABELS:
-               return !(value && *(gchar *) value);
-       default:
-               g_warning ("This shouldn't be reached\n");
-               return FALSE;
-       }
-}
-
-static const gchar *status_map[] = {
-       N_("Unseen"),
-       N_("Seen"),
-       N_("Answered"),
-       N_("Forwarded"),
-       N_("Multiple Unseen Messages"),
-       N_("Multiple Messages"),
-};
-
-static const gchar *score_map[] = {
-       N_("Lowest"),
-       N_("Lower"),
-       N_("Low"),
-       N_("Normal"),
-       N_("High"),
-       N_("Higher"),
-       N_("Highest"),
-};
-
-static gchar *
-ml_value_to_string (ETreeModel *etm,
-                    gint col,
-                    gconstpointer value,
-                    gpointer data)
-{
-       guint i;
-
-       switch (col) {
-       case COL_MESSAGE_STATUS:
-               i = GPOINTER_TO_UINT (value);
-               if (i > 5)
-                       return g_strdup ("");
-               return g_strdup (_(status_map[i]));
-
-       case COL_SCORE:
-               i = GPOINTER_TO_UINT (value) + 3;
-               if (i > 6)
-                       i = 3;
-               return g_strdup (_(score_map[i]));
-
-       case COL_ATTACHMENT:
-       case COL_FLAGGED:
-       case COL_DELETED:
-       case COL_UNREAD:
-       case COL_FOLLOWUP_FLAG_STATUS:
-               return g_strdup_printf ("%u", GPOINTER_TO_UINT (value));
-
-       case COL_SENT:
-       case COL_RECEIVED:
-       case COL_FOLLOWUP_DUE_BY:
-               return filter_date (GPOINTER_TO_INT (value));
-
-       case COL_SIZE:
-               return filter_size (GPOINTER_TO_INT (value));
-
-       case COL_FROM:
-       case COL_SUBJECT:
-       case COL_TO:
-       case COL_FOLLOWUP_FLAG:
-       case COL_LOCATION:
-       case COL_SENDER:
-       case COL_RECIPIENTS:
-       case COL_MIXED_SENDER:
-       case COL_MIXED_RECIPIENTS:
-       case COL_LABELS:
-               return g_strdup (value);
-       default:
-               g_warning ("This shouldn't be reached\n");
-               return NULL;
-       }
-}
-
-static GdkPixbuf *
-ml_tree_icon_at (ETreeModel *etm,
-                 ETreePath path,
-                 gpointer model_data)
-{
-       /* we dont really need an icon ... */
-       return NULL;
-}
-
 static void
 for_node_and_subtree_if_collapsed (MessageList *message_list,
-                                   ETreePath node,
+                                   GNode *node,
                                    CamelMessageInfo *mi,
                                    ETreePathFunc func,
                                    gpointer data)
 {
-       ETreeModel *etm = message_list->model;
-       ETreePath child;
+       ETreeModel *tree_model;
+       GNode *child;
+
+       tree_model = E_TREE_MODEL (message_list);
 
        func (NULL, (ETreePath) mi, data);
 
        if (!node)
                return;
 
-       child = e_tree_model_node_get_first_child (etm, node);
+       child = g_node_first_child (node);
        if (child && !e_tree_node_is_expanded (E_TREE (message_list), node))
-               e_tree_model_node_traverse (etm, node, func, data);
+               e_tree_model_node_traverse (tree_model, node, func, data);
 }
 
 static gboolean
 unread_foreach (ETreeModel *etm,
-                ETreePath node,
+                ETreePath path,
                 gpointer data)
 {
        gboolean *saw_unread = data;
        CamelMessageInfo *info;
 
        if (!etm)
-               info = (CamelMessageInfo *) node;
+               info = (CamelMessageInfo *) path;
        else
-               info = e_tree_memory_node_get_data ((ETreeMemory *) etm, node);
+               info = ((GNode *) path)->data;
        g_return_val_if_fail (info != NULL, FALSE);
 
        if (!(camel_message_info_flags (info) & CAMEL_MESSAGE_SEEN))
@@ -1427,7 +1243,7 @@ struct LatestData {
 
 static gboolean
 latest_foreach (ETreeModel *etm,
-                ETreePath node,
+                ETreePath path,
                 gpointer data)
 {
        struct LatestData *ld = data;
@@ -1435,9 +1251,9 @@ latest_foreach (ETreeModel *etm,
        time_t date;
 
        if (!etm)
-               info = (CamelMessageInfo *) node;
+               info = (CamelMessageInfo *) path;
        else
-               info = e_tree_memory_node_get_data ((ETreeMemory *) etm, node);
+               info = ((GNode *) path)->data;
        g_return_val_if_fail (info != NULL, FALSE);
 
        date = ld->sent ? camel_message_info_date_sent (info)
@@ -1514,7 +1330,7 @@ add_label_if_known (struct LabelsData *ld,
 
 static gboolean
 add_all_labels_foreach (ETreeModel *etm,
-                        ETreePath node,
+                        ETreePath path,
                         gpointer data)
 {
        struct LabelsData *ld = data;
@@ -1524,9 +1340,9 @@ add_all_labels_foreach (ETreeModel *etm,
        const CamelFlag *flag;
 
        if (!etm)
-               msg_info = (CamelMessageInfo *) node;
+               msg_info = (CamelMessageInfo *) path;
        else
-               msg_info = e_tree_memory_node_get_data ((ETreeMemory *) etm, node);
+               msg_info = ((GNode *) path)->data;
        g_return_val_if_fail (msg_info != NULL, FALSE);
 
        for (flag = camel_message_info_user_flags (msg_info); flag; flag = flag->next)
@@ -1609,7 +1425,7 @@ get_trimmed_subject (CamelMessageInfo *info)
 
 static gpointer
 ml_tree_value_at_ex (ETreeModel *etm,
-                     ETreePath path,
+                     GNode *node,
                      gint col,
                      CamelMessageInfo *msg_info,
                      MessageList *message_list)
@@ -1697,7 +1513,7 @@ ml_tree_value_at_ex (ETreeModel *etm,
                ld.sent = TRUE;
                ld.latest = 0;
 
-               for_node_and_subtree_if_collapsed (message_list, path, msg_info, latest_foreach, &ld);
+               for_node_and_subtree_if_collapsed (message_list, node, msg_info, latest_foreach, &ld);
 
                return GINT_TO_POINTER (ld.latest);
        }
@@ -1706,7 +1522,7 @@ ml_tree_value_at_ex (ETreeModel *etm,
                ld.sent = FALSE;
                ld.latest = 0;
 
-               for_node_and_subtree_if_collapsed (message_list, path, msg_info, latest_foreach, &ld);
+               for_node_and_subtree_if_collapsed (message_list, node, msg_info, latest_foreach, &ld);
 
                return GINT_TO_POINTER (ld.latest);
        }
@@ -1722,7 +1538,7 @@ ml_tree_value_at_ex (ETreeModel *etm,
        case COL_UNREAD: {
                gboolean saw_unread = FALSE;
 
-               for_node_and_subtree_if_collapsed (message_list, path, msg_info, unread_foreach, &saw_unread);
+               for_node_and_subtree_if_collapsed (message_list, node, msg_info, unread_foreach, &saw_unread);
 
                return GINT_TO_POINTER (saw_unread);
        }
@@ -1747,7 +1563,7 @@ ml_tree_value_at_ex (ETreeModel *etm,
                        ld.store = e_mail_ui_session_get_label_store (
                                E_MAIL_UI_SESSION (session));
                        ld.labels_tag2iter = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
(GDestroyNotify) gtk_tree_iter_free);
-                       for_node_and_subtree_if_collapsed (message_list, path, msg_info, 
add_all_labels_foreach, &ld);
+                       for_node_and_subtree_if_collapsed (message_list, node, msg_info, 
add_all_labels_foreach, &ld);
 
                        if (g_hash_table_size (ld.labels_tag2iter) == 1) {
                                GHashTableIter iter;
@@ -1833,7 +1649,7 @@ ml_tree_value_at_ex (ETreeModel *etm,
                ld.store = e_mail_ui_session_get_label_store (
                        E_MAIL_UI_SESSION (session));
                ld.labels_tag2iter = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) 
gtk_tree_iter_free);
-               for_node_and_subtree_if_collapsed (message_list, path, msg_info, add_all_labels_foreach, &ld);
+               for_node_and_subtree_if_collapsed (message_list, node, msg_info, add_all_labels_foreach, &ld);
 
                if (g_hash_table_size (ld.labels_tag2iter) > 0) {
                        GHashTableIter iter;
@@ -1865,69 +1681,6 @@ ml_tree_value_at_ex (ETreeModel *etm,
        }
 }
 
-static gpointer
-ml_tree_value_at (ETreeModel *etm,
-                  ETreePath path,
-                  gint col,
-                  gpointer model_data)
-{
-       MessageList *message_list = model_data;
-       CamelMessageInfo *msg_info;
-
-       if (e_tree_model_node_is_root (etm, path))
-               return NULL;
-
-       /* retrieve the message information array */
-       msg_info = e_tree_memory_node_get_data (E_TREE_MEMORY (etm), path);
-       g_return_val_if_fail (msg_info != NULL, NULL);
-
-       return ml_tree_value_at_ex (etm, path, col, msg_info, message_list);
-}
-
-static gpointer
-ml_tree_sort_value_at (ETreeModel *etm,
-                       ETreePath path,
-                       gint col,
-                       gpointer model_data)
-{
-       MessageList *message_list = model_data;
-       struct LatestData ld;
-
-       if (!(col == COL_SENT || col == COL_RECEIVED))
-               return ml_tree_value_at (etm, path, col, model_data);
-
-       if (e_tree_model_node_is_root (etm, path))
-               return NULL;
-
-       ld.sent = (col == COL_SENT);
-       ld.latest = 0;
-
-       latest_foreach (etm, path, &ld);
-       if (message_list->priv->thread_latest)
-               e_tree_model_node_traverse (etm, path, latest_foreach, &ld);
-
-       return GINT_TO_POINTER (ld.latest);
-}
-
-static void
-ml_tree_set_value_at (ETreeModel *etm,
-                      ETreePath path,
-                      gint col,
-                      gconstpointer val,
-                      gpointer model_data)
-{
-       g_warning ("This shouldn't be reached\n");
-}
-
-static gboolean
-ml_tree_is_cell_editable (ETreeModel *etm,
-                          ETreePath path,
-                          gint col,
-                          gpointer model_data)
-{
-       return FALSE;
-}
-
 static gchar *
 filter_date (time_t date)
 {
@@ -2302,7 +2055,7 @@ ml_selection_received (GtkWidget *widget,
 static void
 ml_tree_drag_data_get (ETree *tree,
                        gint row,
-                       ETreePath path,
+                       GNode *node,
                        gint col,
                        GdkDragContext *context,
                        GtkSelectionData *data,
@@ -2434,7 +2187,7 @@ ml_drop_action (struct _drop_msg *m)
 static void
 ml_tree_drag_data_received (ETree *tree,
                             gint row,
-                            ETreePath path,
+                            GNode *node,
                             gint col,
                             GdkDragContext *context,
                             gint x,
@@ -2629,82 +2382,6 @@ message_list_set_session (MessageList *message_list,
 }
 
 static void
-message_list_init (MessageList *message_list)
-{
-       MessageListPrivate *p;
-       GtkTargetList *target_list;
-       GdkAtom matom;
-
-       message_list->priv = MESSAGE_LIST_GET_PRIVATE (message_list);
-
-       /* FIXME This should be a GTypeInterface. */
-       message_list->model = e_tree_memory_callbacks_new (
-               ml_tree_icon_at,
-
-               ml_column_count,
-
-               ml_has_save_id,
-               ml_get_save_id,
-
-               ml_has_get_node_by_id,
-               ml_get_node_by_id,
-
-               ml_tree_sort_value_at,
-               ml_tree_value_at,
-               ml_tree_set_value_at,
-               ml_tree_is_cell_editable,
-
-               ml_duplicate_value,
-               ml_free_value,
-               ml_initialize_value,
-               ml_value_is_empty,
-               ml_value_to_string,
-
-               message_list);
-
-       message_list->normalised_hash = g_hash_table_new_full (
-               g_str_hash, g_str_equal,
-               (GDestroyNotify) NULL,
-               (GDestroyNotify) e_poolv_destroy);
-
-       message_list->uid_nodemap = g_hash_table_new (g_str_hash, g_str_equal);
-
-       message_list->cursor_uid = NULL;
-       message_list->last_sel_single = FALSE;
-
-       g_mutex_init (&message_list->priv->regen_lock);
-
-       /* TODO: Should this only get the selection if we're realised? */
-       p = message_list->priv;
-       p->invisible = gtk_invisible_new ();
-       p->destroyed = FALSE;
-       g_object_ref_sink (p->invisible);
-       p->any_row_changed = FALSE;
-
-       matom = gdk_atom_intern ("x-uid-list", FALSE);
-       gtk_selection_add_target (p->invisible, GDK_SELECTION_CLIPBOARD, matom, 0);
-       gtk_selection_add_target (p->invisible, GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 2);
-
-       g_signal_connect (
-               p->invisible, "selection_get",
-               G_CALLBACK (ml_selection_get), message_list);
-       g_signal_connect (
-               p->invisible, "selection_clear_event",
-               G_CALLBACK (ml_selection_clear_event), message_list);
-       g_signal_connect (
-               p->invisible, "selection_received",
-               G_CALLBACK (ml_selection_received), message_list);
-
-       /* FIXME This is currently unused. */
-       target_list = gtk_target_list_new (NULL, 0);
-       message_list->priv->copy_target_list = target_list;
-
-       /* FIXME This is currently unused. */
-       target_list = gtk_target_list_new (NULL, 0);
-       message_list->priv->paste_target_list = target_list;
-}
-
-static void
 message_list_set_property (GObject *object,
                            guint property_id,
                            const GValue *value,
@@ -2861,7 +2538,6 @@ message_list_dispose (GObject *object)
        g_clear_object (&priv->invisible);
 
        g_clear_object (&message_list->extras);
-       g_clear_object (&message_list->model);
 
        if (message_list->idle_id > 0) {
                g_source_remove (message_list->idle_id);
@@ -2895,6 +2571,9 @@ message_list_finalize (GObject *object)
 
        clear_selection (message_list, &message_list->priv->clipboard);
 
+       if (message_list->priv->tree_model_root != NULL)
+               g_node_destroy (message_list->priv->tree_model_root);
+
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (message_list_parent_class)->finalize (object);
 }
@@ -2929,6 +2608,395 @@ message_list_selectable_select_all (ESelectable *selectable)
        message_list_select_all (MESSAGE_LIST (selectable));
 }
 
+static ETreePath
+message_list_get_root (ETreeModel *tree_model)
+{
+       MessageList *message_list = MESSAGE_LIST (tree_model);
+
+       return message_list->priv->tree_model_root;
+}
+
+static ETreePath
+message_list_get_parent (ETreeModel *tree_model,
+                         ETreePath path)
+{
+       return ((GNode *) path)->parent;
+}
+
+static ETreePath
+message_list_get_first_child (ETreeModel *tree_model,
+                              ETreePath path)
+{
+       return g_node_first_child ((GNode *) path);
+}
+
+static ETreePath
+message_list_get_next (ETreeModel *tree_model,
+                       ETreePath path)
+{
+       return g_node_next_sibling ((GNode *) path);
+}
+
+static gboolean
+message_list_is_root (ETreeModel *tree_model,
+                      ETreePath path)
+{
+       return G_NODE_IS_ROOT ((GNode *) path);
+}
+
+static gboolean
+message_list_is_expandable (ETreeModel *tree_model,
+                            ETreePath path)
+{
+       return (g_node_first_child ((GNode *) path) != NULL);
+}
+
+static guint
+message_list_get_n_children (ETreeModel *tree_model,
+                             ETreePath path)
+{
+       return g_node_n_children ((GNode *) path);
+}
+
+static guint
+message_list_depth (ETreeModel *tree_model,
+                    ETreePath path)
+{
+       return g_node_depth ((GNode *) path);
+}
+
+static GdkPixbuf *
+message_list_icon_at (ETreeModel *tree_model,
+                      ETreePath path)
+{
+       return NULL;
+}
+
+static gboolean
+message_list_get_expanded_default (ETreeModel *tree_model)
+{
+       MessageList *message_list = MESSAGE_LIST (tree_model);
+
+       return message_list->priv->expanded_default;
+}
+
+static gint
+message_list_column_count (ETreeModel *tree_model)
+{
+       return COL_LAST;
+}
+
+static gboolean
+message_list_has_save_id (ETreeModel *tree_model)
+{
+       return TRUE;
+}
+
+static gchar *
+message_list_get_save_id (ETreeModel *tree_model,
+                          ETreePath path)
+{
+       CamelMessageInfo *info;
+
+       if (G_NODE_IS_ROOT ((GNode *) path))
+               return g_strdup ("root");
+
+       /* Note: ETable can ask for the save_id while we're clearing
+        *       it, which is the only time info should be NULL. */
+       info = ((GNode *) path)->data;
+       if (info == NULL)
+               return NULL;
+
+       return g_strdup (camel_message_info_uid (info));
+}
+
+static gboolean
+message_list_has_get_node_by_id (ETreeModel *tree_model)
+{
+       return TRUE;
+}
+
+static ETreePath
+message_list_get_node_by_id (ETreeModel *tree_model,
+                             const gchar *save_id)
+{
+       MessageList *message_list;
+
+       message_list = MESSAGE_LIST (tree_model);
+
+       if (!strcmp (save_id, "root"))
+               return e_tree_model_get_root (tree_model);
+
+       return g_hash_table_lookup (message_list->uid_nodemap, save_id);
+}
+
+static gpointer
+message_list_sort_value_at (ETreeModel *tree_model,
+                            ETreePath path,
+                            gint col)
+{
+       MessageList *message_list;
+       struct LatestData ld;
+
+       message_list = MESSAGE_LIST (tree_model);
+
+       if (!(col == COL_SENT || col == COL_RECEIVED))
+               return e_tree_model_value_at (tree_model, path, col);
+
+       if (G_NODE_IS_ROOT ((GNode *) path))
+               return NULL;
+
+       ld.sent = (col == COL_SENT);
+       ld.latest = 0;
+
+       latest_foreach (tree_model, path, &ld);
+       if (message_list->priv->thread_latest)
+               e_tree_model_node_traverse (
+                       tree_model, path, latest_foreach, &ld);
+
+       return GINT_TO_POINTER (ld.latest);
+}
+
+static gpointer
+message_list_value_at (ETreeModel *tree_model,
+                       ETreePath path,
+                       gint col)
+{
+       MessageList *message_list;
+       CamelMessageInfo *msg_info;
+
+       message_list = MESSAGE_LIST (tree_model);
+
+       if (G_NODE_IS_ROOT ((GNode *) path))
+               return NULL;
+
+       /* retrieve the message information array */
+       msg_info = ((GNode *) path)->data;
+       g_return_val_if_fail (msg_info != NULL, NULL);
+
+       return ml_tree_value_at_ex (tree_model, path, col, msg_info, message_list);
+}
+
+static void
+message_list_set_value_at (ETreeModel *tree_model,
+                           ETreePath path,
+                           gint col,
+                           gconstpointer val)
+{
+       g_warn_if_reached ();
+}
+
+static gboolean
+message_list_is_editable (ETreeModel *tree_model,
+                          ETreePath path,
+                          gint col)
+{
+       return FALSE;
+}
+
+static gpointer
+message_list_duplicate_value (ETreeModel *tree_model,
+                              gint col,
+                              gconstpointer value)
+{
+       switch (col) {
+               case COL_MESSAGE_STATUS:
+               case COL_FLAGGED:
+               case COL_SCORE:
+               case COL_ATTACHMENT:
+               case COL_DELETED:
+               case COL_UNREAD:
+               case COL_SENT:
+               case COL_RECEIVED:
+               case COL_SIZE:
+               case COL_FOLLOWUP_FLAG_STATUS:
+               case COL_FOLLOWUP_DUE_BY:
+                       return (gpointer) value;
+
+               case COL_FROM:
+               case COL_SUBJECT:
+               case COL_TO:
+               case COL_SENDER:
+               case COL_RECIPIENTS:
+               case COL_MIXED_SENDER:
+               case COL_MIXED_RECIPIENTS:
+               case COL_FOLLOWUP_FLAG:
+               case COL_LOCATION:
+               case COL_LABELS:
+                       return g_strdup (value);
+
+               default:
+                       g_return_val_if_reached (NULL);
+       }
+}
+
+static void
+message_list_free_value (ETreeModel *tree_model,
+                         gint col,
+                         gpointer value)
+{
+       switch (col) {
+               case COL_MESSAGE_STATUS:
+               case COL_FLAGGED:
+               case COL_SCORE:
+               case COL_ATTACHMENT:
+               case COL_DELETED:
+               case COL_UNREAD:
+               case COL_SENT:
+               case COL_RECEIVED:
+               case COL_SIZE:
+               case COL_FOLLOWUP_FLAG_STATUS:
+               case COL_FOLLOWUP_DUE_BY:
+               case COL_FROM_NORM:
+               case COL_SUBJECT_NORM:
+               case COL_TO_NORM:
+               case COL_SUBJECT_TRIMMED:
+               case COL_COLOUR:
+                       break;
+
+               case COL_FROM:
+               case COL_SUBJECT:
+               case COL_TO:
+               case COL_FOLLOWUP_FLAG:
+               case COL_LOCATION:
+               case COL_SENDER:
+               case COL_RECIPIENTS:
+               case COL_MIXED_SENDER:
+               case COL_MIXED_RECIPIENTS:
+               case COL_LABELS:
+                       g_free (value);
+                       break;
+
+               default:
+                       g_warn_if_reached ();
+       }
+}
+
+static gpointer
+message_list_initialize_value (ETreeModel *tree_model,
+                               gint col)
+{
+       switch (col) {
+               case COL_MESSAGE_STATUS:
+               case COL_FLAGGED:
+               case COL_SCORE:
+               case COL_ATTACHMENT:
+               case COL_DELETED:
+               case COL_UNREAD:
+               case COL_SENT:
+               case COL_RECEIVED:
+               case COL_SIZE:
+               case COL_FOLLOWUP_FLAG_STATUS:
+               case COL_FOLLOWUP_DUE_BY:
+                       return NULL;
+
+               case COL_FROM:
+               case COL_SUBJECT:
+               case COL_TO:
+               case COL_FOLLOWUP_FLAG:
+               case COL_LOCATION:
+               case COL_SENDER:
+               case COL_RECIPIENTS:
+               case COL_MIXED_SENDER:
+               case COL_MIXED_RECIPIENTS:
+               case COL_LABELS:
+                       return g_strdup ("");
+
+               default:
+                       g_return_val_if_reached (NULL);
+       }
+}
+
+static gboolean
+message_list_value_is_empty (ETreeModel *tree_model,
+                             gint col,
+                             gconstpointer value)
+{
+       switch (col) {
+               case COL_MESSAGE_STATUS:
+               case COL_FLAGGED:
+               case COL_SCORE:
+               case COL_ATTACHMENT:
+               case COL_DELETED:
+               case COL_UNREAD:
+               case COL_SENT:
+               case COL_RECEIVED:
+               case COL_SIZE:
+               case COL_FOLLOWUP_FLAG_STATUS:
+               case COL_FOLLOWUP_DUE_BY:
+                       return value == NULL;
+
+               case COL_FROM:
+               case COL_SUBJECT:
+               case COL_TO:
+               case COL_FOLLOWUP_FLAG:
+               case COL_LOCATION:
+               case COL_SENDER:
+               case COL_RECIPIENTS:
+               case COL_MIXED_SENDER:
+               case COL_MIXED_RECIPIENTS:
+               case COL_LABELS:
+                       return !(value && *(gchar *) value);
+
+               default:
+                       g_return_val_if_reached (FALSE);
+       }
+}
+
+static gchar *
+message_list_value_to_string (ETreeModel *tree_model,
+                              gint col,
+                              gconstpointer value)
+{
+       guint ii;
+
+       switch (col) {
+               case COL_MESSAGE_STATUS:
+                       ii = GPOINTER_TO_UINT (value);
+                       if (ii > 5)
+                               return g_strdup ("");
+                       return g_strdup (_(status_map[ii]));
+
+               case COL_SCORE:
+                       ii = GPOINTER_TO_UINT (value) + 3;
+                       if (ii > 6)
+                               ii = 3;
+                       return g_strdup (_(score_map[ii]));
+
+               case COL_ATTACHMENT:
+               case COL_FLAGGED:
+               case COL_DELETED:
+               case COL_UNREAD:
+               case COL_FOLLOWUP_FLAG_STATUS:
+                       ii = GPOINTER_TO_UINT (value);
+                       return g_strdup_printf ("%u", ii);
+
+               case COL_SENT:
+               case COL_RECEIVED:
+               case COL_FOLLOWUP_DUE_BY:
+                       return filter_date (GPOINTER_TO_INT (value));
+
+               case COL_SIZE:
+                       return filter_size (GPOINTER_TO_INT (value));
+
+               case COL_FROM:
+               case COL_SUBJECT:
+               case COL_TO:
+               case COL_FOLLOWUP_FLAG:
+               case COL_LOCATION:
+               case COL_SENDER:
+               case COL_RECIPIENTS:
+               case COL_MIXED_SENDER:
+               case COL_MIXED_RECIPIENTS:
+               case COL_LABELS:
+                       return g_strdup (value);
+
+               default:
+                       g_return_val_if_reached (NULL);
+       }
+
+}
+
 static void
 message_list_class_init (MessageListClass *class)
 {
@@ -3062,6 +3130,86 @@ message_list_selectable_init (ESelectableInterface *interface)
 }
 
 static void
+message_list_tree_model_init (ETreeModelInterface *interface)
+{
+       interface->get_root = message_list_get_root;
+       interface->get_parent = message_list_get_parent;
+       interface->get_first_child = message_list_get_first_child;
+       interface->get_next = message_list_get_next;
+       interface->is_root = message_list_is_root;
+       interface->is_expandable = message_list_is_expandable;
+       interface->get_n_children = message_list_get_n_children;
+       interface->depth = message_list_depth;
+       interface->icon_at = message_list_icon_at;
+       interface->get_expanded_default = message_list_get_expanded_default;
+       interface->column_count = message_list_column_count;
+       interface->has_save_id = message_list_has_save_id;
+       interface->get_save_id = message_list_get_save_id;
+       interface->has_get_node_by_id = message_list_has_get_node_by_id;
+       interface->get_node_by_id = message_list_get_node_by_id;
+       interface->sort_value_at = message_list_sort_value_at;
+       interface->value_at = message_list_value_at;
+       interface->set_value_at = message_list_set_value_at;
+       interface->is_editable = message_list_is_editable;
+       interface->duplicate_value = message_list_duplicate_value;
+       interface->free_value = message_list_free_value;
+       interface->initialize_value = message_list_initialize_value;
+       interface->value_is_empty = message_list_value_is_empty;
+       interface->value_to_string = message_list_value_to_string;
+}
+
+static void
+message_list_init (MessageList *message_list)
+{
+       MessageListPrivate *p;
+       GtkTargetList *target_list;
+       GdkAtom matom;
+
+       message_list->priv = MESSAGE_LIST_GET_PRIVATE (message_list);
+
+       message_list->normalised_hash = g_hash_table_new_full (
+               g_str_hash, g_str_equal,
+               (GDestroyNotify) NULL,
+               (GDestroyNotify) e_poolv_destroy);
+
+       message_list->uid_nodemap = g_hash_table_new (g_str_hash, g_str_equal);
+
+       message_list->cursor_uid = NULL;
+       message_list->last_sel_single = FALSE;
+
+       g_mutex_init (&message_list->priv->regen_lock);
+
+       /* TODO: Should this only get the selection if we're realised? */
+       p = message_list->priv;
+       p->invisible = gtk_invisible_new ();
+       p->destroyed = FALSE;
+       g_object_ref_sink (p->invisible);
+       p->any_row_changed = FALSE;
+
+       matom = gdk_atom_intern ("x-uid-list", FALSE);
+       gtk_selection_add_target (p->invisible, GDK_SELECTION_CLIPBOARD, matom, 0);
+       gtk_selection_add_target (p->invisible, GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 2);
+
+       g_signal_connect (
+               p->invisible, "selection_get",
+               G_CALLBACK (ml_selection_get), message_list);
+       g_signal_connect (
+               p->invisible, "selection_clear_event",
+               G_CALLBACK (ml_selection_clear_event), message_list);
+       g_signal_connect (
+               p->invisible, "selection_received",
+               G_CALLBACK (ml_selection_received), message_list);
+
+       /* FIXME This is currently unused. */
+       target_list = gtk_target_list_new (NULL, 0);
+       message_list->priv->copy_target_list = target_list;
+
+       /* FIXME This is currently unused. */
+       target_list = gtk_target_list_new (NULL, 0);
+       message_list->priv->paste_target_list = target_list;
+}
+
+static void
 message_list_construct (MessageList *message_list)
 {
        AtkObject *a11y;
@@ -3075,7 +3223,8 @@ message_list_construct (MessageList *message_list)
 
        etspecfile = g_build_filename (EVOLUTION_ETSPECDIR, "message-list.etspec", NULL);
        constructed = e_tree_construct_from_spec_file (
-               E_TREE (message_list), message_list->model,
+               E_TREE (message_list),
+               E_TREE_MODEL (message_list),
                message_list->extras, etspecfile, NULL);
        g_free (etspecfile);
 
@@ -3165,23 +3314,21 @@ message_list_get_session (MessageList *message_list)
 
 static void
 clear_info (gchar *key,
-            ETreePath *node,
+            GNode *node,
             MessageList *message_list)
 {
        CamelMessageInfo *info;
 
-       info = e_tree_memory_node_get_data (
-               (ETreeMemory *) message_list->model, node);
+       info = node->data;
        camel_folder_free_message_info (message_list->priv->folder, info);
-       e_tree_memory_node_set_data (
-               (ETreeMemory *) message_list->model, node, NULL);
+       node->data = NULL;
 }
 
 static void
 clear_tree (MessageList *message_list,
             gboolean tfree)
 {
-       ETreeModel *etm = message_list->model;
+       ETreeModel *tree_model;
        CamelFolder *folder;
 
 #ifdef TIMEIT
@@ -3192,6 +3339,8 @@ clear_tree (MessageList *message_list,
        gettimeofday (&start, NULL);
 #endif
 
+       tree_model = E_TREE_MODEL (message_list);
+
        /* we also reset the uid_rowmap since it is no longer useful/valid anyway */
        folder = message_list_ref_folder (message_list);
        if (folder != NULL)
@@ -3207,23 +3356,24 @@ clear_tree (MessageList *message_list,
        message_list->priv->oldest_unread_date = 0;
        message_list->priv->oldest_unread_uid = NULL;
 
-       if (message_list->tree_root) {
+       if (message_list->priv->tree_model_root != NULL) {
                /* we should be frozen already */
-               e_tree_memory_node_remove (
-                       E_TREE_MEMORY (etm), message_list->tree_root);
+               message_list_tree_model_remove (
+                       message_list, message_list->priv->tree_model_root);
        }
 
-       message_list->tree_root = e_tree_memory_node_insert (
-               E_TREE_MEMORY (etm), NULL, 0, NULL);
+       /* Create a new placeholder root node. */
+       message_list_tree_model_insert (message_list, NULL, 0, NULL);
+       g_warn_if_fail (message_list->priv->tree_model_root != NULL);
+
        if (tfree)
-               e_tree_model_rebuilt (E_TREE_MODEL (etm));
+               e_tree_model_rebuilt (tree_model);
 #ifdef TIMEIT
        gettimeofday (&end, NULL);
        diff = end.tv_sec * 1000 + end.tv_usec / 1000;
        diff -= start.tv_sec * 1000 + start.tv_usec / 1000;
        printf ("Clearing tree took %ld.%03ld seconds\n", diff / 1000, diff % 1000);
 #endif
-
 }
 
 static gboolean
@@ -3360,7 +3510,7 @@ is_node_selectable (MessageList *message_list,
 static gchar *
 find_next_selectable (MessageList *message_list)
 {
-       ETreePath node;
+       GNode *node;
        gint last;
        gint vrow_orig;
        gint vrow;
@@ -3407,15 +3557,14 @@ find_next_selectable (MessageList *message_list)
        return NULL;
 }
 
-static ETreePath *
+static GNode *
 ml_uid_nodemap_insert (MessageList *message_list,
                        CamelMessageInfo *info,
-                       ETreePath *parent_node,
+                       GNode *parent,
                        gint row)
 {
        CamelFolder *folder;
-       ETreeMemory *tree;
-       ETreePath *node;
+       GNode *node;
        const gchar *uid;
        time_t date;
        guint flags;
@@ -3423,11 +3572,11 @@ ml_uid_nodemap_insert (MessageList *message_list,
        folder = message_list_ref_folder (message_list);
        g_return_val_if_fail (folder != NULL, NULL);
 
-       if (parent_node == NULL)
-               parent_node = message_list->tree_root;
+       if (parent == NULL)
+               parent = message_list->priv->tree_model_root;
 
-       tree = E_TREE_MEMORY (message_list->model);
-       node = e_tree_memory_node_insert (tree, parent_node, row, info);
+       node = message_list_tree_model_insert (
+               message_list, parent, row, info);
 
        uid = camel_message_info_uid (info);
        flags = camel_message_info_flags (info);
@@ -3490,13 +3639,13 @@ ml_uid_nodemap_remove (MessageList *message_list,
 /* builds the tree structure */
 
 static void    build_subtree                   (MessageList *message_list,
-                                                ETreePath parent,
+                                                GNode *parent,
                                                 CamelFolderThreadNode *c,
                                                 gint *row);
 
 static void    build_subtree_diff              (MessageList *message_list,
-                                                ETreePath parent,
-                                                ETreePath path,
+                                                GNode *parent,
+                                                GNode *node,
                                                 CamelFolderThreadNode *c,
                                                 gint *row);
 
@@ -3506,7 +3655,6 @@ build_tree (MessageList *message_list,
             gboolean folder_changed)
 {
        gint row = 0;
-       ETreeModel *etm = message_list->model;
        ETableItem *table_item = e_tree_get_item (E_TREE (message_list));
        gchar *saveuid = NULL;
        GPtrArray *selected;
@@ -3525,22 +3673,23 @@ build_tree (MessageList *message_list,
        printf ("Loading tree state took %ld.%03ld seconds\n", diff / 1000, diff % 1000);
 #endif
 
-       if (message_list->tree_root == NULL)
-               message_list->tree_root = e_tree_memory_node_insert (
-                       E_TREE_MEMORY (etm), NULL, 0, NULL);
+       if (message_list->priv->tree_model_root == NULL) {
+               message_list_tree_model_insert (message_list, NULL, 0, NULL);
+               g_warn_if_fail (message_list->priv->tree_model_root != NULL);
+       }
 
        if (message_list->cursor_uid != NULL)
                saveuid = find_next_selectable (message_list);
 
                selected = message_list_get_selected (message_list);
 
-               e_tree_memory_freeze (E_TREE_MEMORY (etm));
+               message_list_tree_model_freeze (message_list);
 
                clear_tree (message_list, FALSE);
 
                build_subtree (
                        message_list,
-                       message_list->tree_root,
+                       message_list->priv->tree_model_root,
                        thread->tree, &row);
 
                /* Show the cursor unless we're responding to a
@@ -3548,10 +3697,10 @@ build_tree (MessageList *message_list,
                if (folder_changed && table_item != NULL)
                        table_item->queue_show_cursor = FALSE;
 
-               e_tree_memory_thaw (E_TREE_MEMORY (etm));
+               message_list_tree_model_thaw (message_list);
 
                /* it's required to thaw & freeze, to propagate changes */
-               e_tree_memory_freeze (E_TREE_MEMORY (etm));
+               message_list_tree_model_freeze (message_list);
 
                message_list_set_selected (message_list, selected);
 
@@ -3562,7 +3711,7 @@ build_tree (MessageList *message_list,
                if (folder_changed && table_item != NULL)
                        table_item->queue_show_cursor = FALSE;
 
-               e_tree_memory_thaw (E_TREE_MEMORY (etm));
+               message_list_tree_model_thaw (message_list);
        if (!saveuid && message_list->cursor_uid && g_hash_table_lookup (message_list->uid_nodemap, 
message_list->cursor_uid)) {
                /* this makes sure a visible node is selected, like when
                 * collapsing all nodes and a children had been selected
@@ -3571,7 +3720,7 @@ build_tree (MessageList *message_list,
        }
 
        if (saveuid) {
-               ETreePath node;
+               GNode *node;
 
                node = g_hash_table_lookup (
                        message_list->uid_nodemap, saveuid);
@@ -3583,14 +3732,14 @@ build_tree (MessageList *message_list,
                                signals[MESSAGE_SELECTED], 0, NULL);
                } else {
                        ETree *tree = E_TREE (message_list);
-                       ETreePath parent = node;
+                       GNode *parent = node;
 
-                       while (parent = e_tree_model_node_get_parent (etm, parent), parent) {
+                       while ((parent = parent->parent) != NULL) {
                                if (!e_tree_node_is_expanded (tree, parent))
                                        node = parent;
                        }
 
-                       e_tree_memory_freeze (E_TREE_MEMORY (etm));
+                       message_list_tree_model_freeze (message_list);
 
                        e_tree_set_cursor (E_TREE (message_list), node);
 
@@ -3599,7 +3748,7 @@ build_tree (MessageList *message_list,
                        if (folder_changed && table_item != NULL)
                                table_item->queue_show_cursor = FALSE;
 
-                       e_tree_memory_thaw (E_TREE_MEMORY (etm));
+                       message_list_tree_model_thaw (message_list);
                }
                g_free (saveuid);
        } else if (message_list->cursor_uid && !g_hash_table_lookup (message_list->uid_nodemap, 
message_list->cursor_uid)) {
@@ -3624,11 +3773,11 @@ build_tree (MessageList *message_list,
 /* Otherwise, this code would probably go as it does the same thing essentially */
 static void
 build_subtree (MessageList *message_list,
-               ETreePath parent,
+               GNode *parent,
                CamelFolderThreadNode *c,
                gint *row)
 {
-       ETreePath node;
+       GNode *node;
 
        while (c) {
                /* phantom nodes no longer allowed */
@@ -3653,14 +3802,10 @@ build_subtree (MessageList *message_list,
  * the same object */
 static gint
 node_equal (ETreeModel *etm,
-            ETreePath ap,
+            GNode *ap,
             CamelFolderThreadNode *bp)
 {
-       CamelMessageInfo *info;
-
-       info = e_tree_memory_node_get_data (E_TREE_MEMORY (etm), ap);
-
-       if (bp->message && strcmp (camel_message_info_uid (info), camel_message_info_uid (bp->message)) == 0)
+       if (bp->message && strcmp (camel_message_info_uid (ap->data), camel_message_info_uid (bp->message)) 
== 0)
                return 1;
 
        return 0;
@@ -3669,14 +3814,14 @@ node_equal (ETreeModel *etm,
 /* adds a single node, retains save state, and handles adding children if required */
 static void
 add_node_diff (MessageList *message_list,
-               ETreePath parent,
-               ETreePath path,
+               GNode *parent,
+               GNode *node,
                CamelFolderThreadNode *c,
                gint *row,
                gint myrow)
 {
        CamelMessageInfo *info;
-       ETreePath node;
+       GNode *new_node;
 
        g_return_if_fail (c->message != NULL);
 
@@ -3685,40 +3830,40 @@ add_node_diff (MessageList *message_list,
 
        /* we just update the hashtable key */
        ml_uid_nodemap_remove (message_list, info);
-       node = ml_uid_nodemap_insert (message_list, info, parent, myrow);
+       new_node = ml_uid_nodemap_insert (message_list, info, parent, myrow);
        (*row)++;
 
        if (c->child) {
-               build_subtree_diff (message_list, node, NULL, c->child, row);
+               build_subtree_diff (
+                       message_list, new_node, NULL, c->child, row);
        }
 }
 
 /* removes node, children recursively and all associated data */
 static void
 remove_node_diff (MessageList *message_list,
-                  ETreePath node,
+                  GNode *node,
                   gint depth)
 {
-       ETreeModel *etm = message_list->model;
        ETreePath cp, cn;
        CamelMessageInfo *info;
 
-       t (printf ("Removing node: %s\n", (gchar *) e_tree_memory_node_get_data (etm, node)));
+       t (printf ("Removing node: %s\n", (gchar *) node->data));
 
        /* we depth-first remove all node data's ... */
-       cp = e_tree_model_node_get_first_child (etm, node);
+       cp = g_node_first_child (node);
        while (cp) {
-               cn = e_tree_model_node_get_next (etm, cp);
+               cn = g_node_next_sibling (cp);
                remove_node_diff (message_list, cp, depth + 1);
                cp = cn;
        }
 
        /* and the rowid entry - if and only if it is referencing this node */
-       info = e_tree_memory_node_get_data (E_TREE_MEMORY (etm), node);
+       info = node->data;
 
        /* and only at the toplevel, remove the node (etree should optimise this remove somewhat) */
        if (depth == 0)
-               e_tree_memory_node_remove (E_TREE_MEMORY (etm), node);
+               message_list_tree_model_remove (message_list, node);
 
        g_return_if_fail (info);
        ml_uid_nodemap_remove (message_list, info);
@@ -3728,17 +3873,19 @@ remove_node_diff (MessageList *message_list,
  * that have changed */
 static void
 build_subtree_diff (MessageList *message_list,
-                    ETreePath parent,
-                    ETreePath path,
+                    GNode *parent,
+                    GNode *node,
                     CamelFolderThreadNode *c,
                     gint *row)
 {
-       ETreeModel *etm = message_list->model;
-       ETreePath ap, *ai, *at, *tmp;
+       ETreeModel *tree_model;
+       GNode *ap, *ai, *at, *tmp;
        CamelFolderThreadNode *bp, *bi, *bt;
        gint i, j, myrow = 0;
 
-       ap = path;
+       tree_model = E_TREE_MODEL (message_list);
+
+       ap = node;
        bp = c;
 
        while (ap || bp) {
@@ -3753,31 +3900,31 @@ build_subtree_diff (MessageList *message_list,
                } else if (bp == NULL) {
                        t (printf ("out of new nodes\n"));
                        /* ran out of new nodes - remaining nodes are removed */
-                       tmp = e_tree_model_node_get_next (etm, ap);
+                       tmp = g_node_next_sibling (ap);
                        remove_node_diff (message_list, ap, 0);
                        ap = tmp;
-               } else if (node_equal (etm, ap, bp)) {
+               } else if (node_equal (tree_model, ap, bp)) {
                        *row = (*row)+1;
                        myrow++;
-                       tmp = e_tree_model_node_get_first_child (etm, ap);
+                       tmp = g_node_first_child (ap);
                        /* make child lists match (if either has one) */
                        if (bp->child || tmp) {
                                build_subtree_diff (
                                        message_list, ap, tmp, bp->child, row);
                        }
-                       ap = e_tree_model_node_get_next (etm, ap);
+                       ap = g_node_next_sibling (ap);
                        bp = bp->next;
                } else {
                        t (printf ("searching for matches\n"));
                        /* we have to scan each side for a match */
                        bi = bp->next;
-                       ai = e_tree_model_node_get_next (etm, ap);
+                       ai = g_node_next_sibling (ap);
                        for (i = 1; bi != NULL; i++,bi = bi->next) {
-                               if (node_equal (etm, ap, bi))
+                               if (node_equal (tree_model, ap, bi))
                                        break;
                        }
-                       for (j = 1; ai != NULL; j++,ai = e_tree_model_node_get_next (etm, ai)) {
-                               if (node_equal (etm, ai, bp))
+                       for (j = 1; ai != NULL; j++,ai = g_node_next_sibling (ai)) {
+                               if (node_equal (tree_model, ai, bp))
                                        break;
                        }
                        if (i < j) {
@@ -3806,7 +3953,7 @@ build_subtree_diff (MessageList *message_list,
                                        at = ap;
                                        while (at != NULL && at != ai) {
                                                t (printf ("removing old node 0\n"));
-                                               tmp = e_tree_model_node_get_next (etm, at);
+                                               tmp = g_node_next_sibling (at);
                                                remove_node_diff (message_list, at, 0);
                                                at = tmp;
                                        }
@@ -3828,7 +3975,6 @@ static void
 build_flat (MessageList *message_list,
             GPtrArray *summary)
 {
-       ETreeModel *etm = message_list->model;
        gchar *saveuid = NULL;
        gint i;
        GPtrArray *selected;
@@ -3845,7 +3991,7 @@ build_flat (MessageList *message_list,
 
        selected = message_list_get_selected (message_list);
 
-       e_tree_memory_freeze (E_TREE_MEMORY (etm));
+       message_list_tree_model_freeze (message_list);
 
        clear_tree (message_list, FALSE);
 
@@ -3855,14 +4001,14 @@ build_flat (MessageList *message_list,
                ml_uid_nodemap_insert (message_list, info, NULL, -1);
        }
 
-       e_tree_memory_thaw (E_TREE_MEMORY (etm));
+       message_list_tree_model_thaw (message_list);
 
        message_list_set_selected (message_list, selected);
 
        g_ptr_array_unref (selected);
 
        if (saveuid) {
-               ETreePath node;
+               GNode *node;
 
                node = g_hash_table_lookup (
                        message_list->uid_nodemap, saveuid);
@@ -3889,19 +4035,21 @@ build_flat (MessageList *message_list,
 
 static void
 message_list_change_first_visible_parent (MessageList *message_list,
-                                          ETreePath node)
+                                          GNode *node)
 {
-       ETreePath first_visible = NULL;
+       ETreeModel *tree_model;
+       GNode *first_visible = NULL;
+
+       tree_model = E_TREE_MODEL (message_list);
 
-       while (node && (node = e_tree_model_node_get_parent (message_list->model, node))) {
+       while (node != NULL && (node = node->parent) != NULL) {
                if (!e_tree_node_is_expanded (E_TREE (message_list), node))
                        first_visible = node;
        }
 
        if (first_visible != NULL) {
-               e_tree_model_pre_change (message_list->model);
-               e_tree_model_node_data_changed (
-                       message_list->model, first_visible);
+               e_tree_model_pre_change (tree_model);
+               e_tree_model_node_data_changed (tree_model, first_visible);
        }
 }
 
@@ -3918,7 +4066,7 @@ mail_folder_hide_by_flag (CamelFolder *folder,
        newchanges = camel_folder_change_info_new ();
 
        for (i = 0; i < changes->uid_changed->len; i++) {
-               ETreePath node;
+               GNode *node;
                guint32 flags;
 
                node = g_hash_table_lookup (
@@ -3963,6 +4111,7 @@ message_list_folder_changed (CamelFolder *folder,
                              MessageList *message_list)
 {
        CamelFolderChangeInfo *altered_changes = NULL;
+       ETreeModel *tree_model;
        gboolean need_list_regen = TRUE;
        gboolean hide_junk;
        gboolean hide_deleted;
@@ -3971,6 +4120,8 @@ message_list_folder_changed (CamelFolder *folder,
        if (message_list->priv->destroyed)
                return;
 
+       tree_model = E_TREE_MODEL (message_list);
+
        hide_junk = message_list_get_hide_junk (message_list, folder);
        hide_deleted = message_list_get_hide_deleted (message_list, folder);
 
@@ -3995,14 +4146,14 @@ message_list_folder_changed (CamelFolder *folder,
 
                if (altered_changes->uid_added->len == 0 && altered_changes->uid_removed->len == 0 && 
altered_changes->uid_changed->len < 100) {
                        for (i = 0; i < altered_changes->uid_changed->len; i++) {
-                               ETreePath node;
+                               GNode *node;
 
                                node = g_hash_table_lookup (
                                        message_list->uid_nodemap,
                                        altered_changes->uid_changed->pdata[i]);
                                if (node) {
-                                       e_tree_model_pre_change (message_list->model);
-                                       e_tree_model_node_data_changed (message_list->model, node);
+                                       e_tree_model_pre_change (tree_model);
+                                       e_tree_model_node_data_changed (tree_model, node);
 
                                        message_list_change_first_visible_parent (message_list, node);
                                }
@@ -4049,8 +4200,6 @@ void
 message_list_set_folder (MessageList *message_list,
                          CamelFolder *folder)
 {
-       ETreeModel *etm = message_list->model;
-
        /* XXX Do we need a property lock to guard this? */
 
        g_return_if_fail (IS_MESSAGE_LIST (message_list));
@@ -4082,9 +4231,9 @@ message_list_set_folder (MessageList *message_list,
        if (message_list->priv->folder != NULL)
                save_tree_state (message_list, message_list->priv->folder);
 
-       e_tree_memory_freeze (E_TREE_MEMORY (etm));
+       message_list_tree_model_freeze (message_list);
        clear_tree (message_list, TRUE);
-       e_tree_memory_thaw (E_TREE_MEMORY (etm));
+       message_list_tree_model_thaw (message_list);
 
        /* remove the cursor activate idle handler */
        if (message_list->idle_id != 0) {
@@ -4183,6 +4332,15 @@ message_list_get_paste_target_list (MessageList *message_list)
        return message_list->priv->paste_target_list;
 }
 
+void
+message_list_set_expanded_default (MessageList *message_list,
+                                   gboolean expanded_default)
+{
+       g_return_if_fail (IS_MESSAGE_LIST (message_list));
+
+       message_list->priv->expanded_default = expanded_default;
+}
+
 gboolean
 message_list_get_group_by_threads (MessageList *message_list)
 {
@@ -4309,16 +4467,16 @@ on_cursor_activated_idle (gpointer data)
 static void
 on_cursor_activated_cmd (ETree *tree,
                          gint row,
-                         ETreePath path,
+                         GNode *node,
                          gpointer user_data)
 {
        MessageList *message_list = MESSAGE_LIST (user_data);
        const gchar *new_uid;
 
-       if (path == NULL)
+       if (node == NULL)
                new_uid = NULL;
        else
-               new_uid = get_message_uid (message_list, path);
+               new_uid = get_message_uid (message_list, node);
 
        /* Do not check the cursor_uid and the new_uid values, because the
        * selected item (set in on_selection_changed_cmd) can be different
@@ -4347,7 +4505,7 @@ on_selection_changed_cmd (ETree *tree,
 {
        GPtrArray *uids;
        const gchar *newuid;
-       ETreePath cursor;
+       GNode *cursor;
 
        /* not sure if we could just ignore this for the cursor, i think sometimes you
         * only get a selection changed when you should also get a cursor activated? */
@@ -4356,7 +4514,7 @@ on_selection_changed_cmd (ETree *tree,
        if (uids->len == 1)
                newuid = g_ptr_array_index (uids, 0);
        else if ((cursor = e_tree_get_cursor (tree)))
-               newuid = (gchar *) camel_message_info_uid (e_tree_memory_node_get_data ((ETreeMemory *) tree, 
cursor));
+               newuid = (gchar *) camel_message_info_uid (cursor->data);
        else
                newuid = NULL;
 
@@ -4384,7 +4542,7 @@ on_selection_changed_cmd (ETree *tree,
 static gint
 on_click (ETree *tree,
           gint row,
-          ETreePath path,
+          GNode *node,
           gint col,
           GdkEvent *event,
           MessageList *list)
@@ -4403,7 +4561,7 @@ on_click (ETree *tree,
        else if (col != COL_FOLLOWUP_FLAG_STATUS)
                return FALSE;
 
-       if (!(info = get_message_info (list, path)))
+       if (!(info = get_message_info (list, node)))
                return FALSE;
 
        folder = message_list_ref_folder (list);
@@ -4482,16 +4640,16 @@ struct _ml_selected_data {
 };
 
 static void
-ml_getselected_cb (ETreePath path,
+ml_getselected_cb (GNode *node,
                    gpointer user_data)
 {
        struct _ml_selected_data *data = user_data;
        const gchar *uid;
 
-       if (e_tree_model_node_is_root (data->message_list->model, path))
+       if (G_NODE_IS_ROOT (node))
                return;
 
-       uid = get_message_uid (data->message_list, path);
+       uid = get_message_uid (data->message_list, node);
        g_return_if_fail (uid != NULL);
        g_ptr_array_add (data->uids, g_strdup (uid));
 }
@@ -4509,7 +4667,8 @@ message_list_get_selected (MessageList *message_list)
        g_ptr_array_set_free_func (data.uids, (GDestroyNotify) g_free);
 
        e_tree_selected_path_foreach (
-               E_TREE (message_list), ml_getselected_cb, &data);
+               E_TREE (message_list),
+               (ETreeForeachFunc) ml_getselected_cb, &data);
 
        folder = message_list_ref_folder (message_list);
 
@@ -4527,7 +4686,7 @@ message_list_set_selected (MessageList *message_list,
 {
        gint i;
        ETreeSelectionModel *etsm;
-       ETreePath node;
+       GNode *node;
        GPtrArray *paths = g_ptr_array_new ();
 
        etsm = (ETreeSelectionModel *)
@@ -4535,7 +4694,7 @@ message_list_set_selected (MessageList *message_list,
        for (i = 0; i < uids->len; i++) {
                node = g_hash_table_lookup (
                        message_list->uid_nodemap, uids->pdata[i]);
-               if (node)
+               if (node != NULL)
                        g_ptr_array_add (paths, node);
        }
 
@@ -4564,7 +4723,7 @@ message_list_sort_uids (MessageList *message_list,
 {
        struct ml_sort_uids_data *data;
        GPtrArray *array;
-       ETreePath path;
+       GNode *node;
        ETreeTableAdapter *adapter;
        gint ii;
 
@@ -4583,9 +4742,9 @@ message_list_sort_uids (MessageList *message_list,
                data = g_new0 (struct ml_sort_uids_data, 1);
                data->uid = g_ptr_array_index (uids, ii);
 
-               path = g_hash_table_lookup (message_list->uid_nodemap, data->uid);
-               if (path)
-                       data->row = e_tree_table_adapter_row_of_node (adapter, path);
+               node = g_hash_table_lookup (message_list->uid_nodemap, data->uid);
+               if (node != NULL)
+                       data->row = e_tree_table_adapter_row_of_node (adapter, node);
                else
                        data->row = ii;
 
@@ -4609,12 +4768,12 @@ struct ml_count_data {
 };
 
 static void
-ml_getcount_cb (ETreePath path,
+ml_getcount_cb (GNode *node,
                 gpointer user_data)
 {
        struct ml_count_data *data = user_data;
 
-       if (!e_tree_model_node_is_root (data->message_list->model, path))
+       if (!G_NODE_IS_ROOT (node))
                data->count++;
 }
 
@@ -4625,7 +4784,9 @@ message_list_count (MessageList *message_list)
 
        g_return_val_if_fail (IS_MESSAGE_LIST (message_list), 0);
 
-       e_tree_path_foreach (E_TREE (message_list), ml_getcount_cb, &data);
+       e_tree_path_foreach (
+               E_TREE (message_list),
+               (ETreeForeachFunc) ml_getcount_cb, &data);
 
        return data.count;
 }
@@ -5008,7 +5169,7 @@ message_list_regen_thread (GSimpleAsyncResult *simple,
        RegenData *regen_data;
        GPtrArray *uids, *searchuids = NULL;
        CamelMessageInfo *info;
-       ETreePath cursor;
+       GNode *cursor;
        ETree *tree;
        GString *expr;
        gboolean hide_deleted;
@@ -5279,12 +5440,12 @@ message_list_regen_done_cb (GObject *source_object,
                        regen_data->last_row = row_count;
 
                if (regen_data->last_row >= 0) {
-                       ETreePath path;
+                       GNode *node;
 
-                       path = e_tree_table_adapter_node_at_row (
+                       node = e_tree_table_adapter_node_at_row (
                                adapter, regen_data->last_row);
-                       if (path != NULL)
-                               select_path (message_list, path);
+                       if (node != NULL)
+                               select_node (message_list, node);
                }
        }
 
diff --git a/mail/message-list.h b/mail/message-list.h
index 06950fe..9a792e4 100644
--- a/mail/message-list.h
+++ b/mail/message-list.h
@@ -100,8 +100,6 @@ struct _MessageList {
        MessageListPrivate *priv;
 
        /* The table */
-       ETreeModel   *model;
-       ETreePath     tree_root;
        ETableExtras *extras;
 
        GHashTable *uid_nodemap; /* uid (from info) -> tree node mapping */
@@ -162,6 +160,9 @@ GtkTargetList *     message_list_get_copy_target_list
                                                (MessageList *message_list);
 GtkTargetList *        message_list_get_paste_target_list
                                                (MessageList *message_list);
+void           message_list_set_expanded_default
+                                               (MessageList *message_list,
+                                                gboolean expanded_default);
 gboolean       message_list_get_group_by_threads
                                                (MessageList *message_list);
 void           message_list_set_group_by_threads
diff --git a/modules/settings/e-settings-message-list.c b/modules/settings/e-settings-message-list.c
index 513069d..5ac549d 100644
--- a/modules/settings/e-settings-message-list.c
+++ b/modules/settings/e-settings-message-list.c
@@ -64,8 +64,8 @@ settings_message_list_constructed (GObject *object)
 
        /* This setting only controls the initial message list
         * state when in threaded mode, so just apply it here. */
-       e_tree_memory_set_expanded_default (
-               E_TREE_MEMORY (message_list->model),
+       message_list_set_expanded_default (
+               message_list,
                g_settings_get_boolean (settings, "thread-expand"));
 
        g_object_unref (settings);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]