[evolution] Introduce EMailSidebar into libevolution-mail.



commit 5ba8caffba174a468359cdb9a7da83bf1fad6033
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Dec 14 12:47:38 2009 -0500

    Introduce EMailSidebar into libevolution-mail.
    
    EMailSidebar is a subclass of EMFolderTree that implements the state
    saving and restoration feature from EMailShellSidebar.  Placing this
    in the shared mail library allows Anjal to reuse it.

 doc/reference/shell/tmpl/e-alert.sgml       |   45 +--
 doc/reference/shell/tmpl/e-shell-utils.sgml |    1 +
 doc/reference/shell/tmpl/e-shell-view.sgml  |    5 +
 doc/reference/shell/tmpl/e-shell.sgml       |   14 +
 doc/reference/shell/tmpl/eshell-unused.sgml |   37 ++
 mail/Makefile.am                            |    2 +
 mail/e-mail-sidebar.c                       |  616 +++++++++++++++++++++++++++
 mail/e-mail-sidebar.h                       |   87 ++++
 mail/em-folder-tree.c                       |  385 +++++++++--------
 modules/mail/e-mail-shell-sidebar.c         |  420 +------------------
 modules/mail/e-mail-shell-sidebar.h         |    9 -
 modules/mail/e-mail-shell-view-private.h    |    1 +
 modules/mail/e-mail-shell-view.c            |   12 +-
 shell/e-shell-view.c                        |   21 +
 14 files changed, 1003 insertions(+), 652 deletions(-)
---
diff --git a/doc/reference/shell/tmpl/e-alert.sgml b/doc/reference/shell/tmpl/e-alert.sgml
index d61c8a5..6306548 100644
--- a/doc/reference/shell/tmpl/e-alert.sgml
+++ b/doc/reference/shell/tmpl/e-alert.sgml
@@ -9,13 +9,11 @@ User Alert Handling
 
 </para>
 
-
 <!-- ##### SECTION See_Also ##### -->
 <para>
 
 </para>
 
-
 <!-- ##### SECTION Stability_Level ##### -->
 
 
@@ -87,53 +85,14 @@ User Alert Handling
 
 </para>
 
-
-<!-- ##### FUNCTION e_alert_new ##### -->
-<para>
-
-</para>
-
- tag: 
- arg0: 
- Varargs: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_alert_newv ##### -->
-<para>
-
-</para>
-
- tag: 
- arg0: 
- ap: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_alert_free ##### -->
-<para>
-
-</para>
-
- alert: 
-
-
-<!-- ##### FUNCTION e_alert_new_dialog ##### -->
-<para>
-
-</para>
-
 @parent: 
- alert: 
- Returns: 
-
+ priv: 
 
-<!-- ##### FUNCTION e_alert_new_dialog_for_args ##### -->
+<!-- ##### FUNCTION e_alert_new ##### -->
 <para>
 
 </para>
 
- parent: 
 @tag: 
 @arg0: 
 @Varargs: 
diff --git a/doc/reference/shell/tmpl/e-shell-utils.sgml b/doc/reference/shell/tmpl/e-shell-utils.sgml
index fa74606..5fb4913 100644
--- a/doc/reference/shell/tmpl/e-shell-utils.sgml
+++ b/doc/reference/shell/tmpl/e-shell-utils.sgml
@@ -46,6 +46,7 @@ Shell Utilities
 @shell: 
 @title: 
 @suggestion: 
+ filters: 
 @customize_func: 
 @customize_data: 
 @Returns: 
diff --git a/doc/reference/shell/tmpl/e-shell-view.sgml b/doc/reference/shell/tmpl/e-shell-view.sgml
index 79e8b86..0508608 100644
--- a/doc/reference/shell/tmpl/e-shell-view.sgml
+++ b/doc/reference/shell/tmpl/e-shell-view.sgml
@@ -79,6 +79,11 @@ EShellView
 
 </para>
 
+<!-- ##### ARG EShellView:state-key-file ##### -->
+<para>
+
+</para>
+
 <!-- ##### ARG EShellView:title ##### -->
 <para>
 
diff --git a/doc/reference/shell/tmpl/e-shell.sgml b/doc/reference/shell/tmpl/e-shell.sgml
index ce167e2..3946454 100644
--- a/doc/reference/shell/tmpl/e-shell.sgml
+++ b/doc/reference/shell/tmpl/e-shell.sgml
@@ -99,6 +99,11 @@ EShell
 
 </para>
 
+<!-- ##### ARG EShell:module-directory ##### -->
+<para>
+
+</para>
+
 <!-- ##### ARG EShell:network-available ##### -->
 <para>
 
@@ -236,6 +241,15 @@ EShell
 @parent: 
 
 
+<!-- ##### FUNCTION e_shell_get_module_directory ##### -->
+<para>
+
+</para>
+
+ shell: 
+ Returns: 
+
+
 <!-- ##### FUNCTION e_shell_get_network_available ##### -->
 <para>
 
diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml
index 96fc342..359f603 100644
--- a/doc/reference/shell/tmpl/eshell-unused.sgml
+++ b/doc/reference/shell/tmpl/eshell-unused.sgml
@@ -1933,6 +1933,43 @@ intelligent
 </para>
 
 
+<!-- ##### FUNCTION e_alert_free ##### -->
+<para>
+
+</para>
+
+ alert: 
+
+<!-- ##### FUNCTION e_alert_new_dialog ##### -->
+<para>
+
+</para>
+
+ parent: 
+ alert: 
+ Returns: 
+
+<!-- ##### FUNCTION e_alert_new_dialog_for_args ##### -->
+<para>
+
+</para>
+
+ parent: 
+ tag: 
+ arg0: 
+ Varargs: 
+ Returns: 
+
+<!-- ##### FUNCTION e_alert_newv ##### -->
+<para>
+
+</para>
+
+ tag: 
+ arg0: 
+ ap: 
+ Returns: 
+
 <!-- ##### FUNCTION e_config_upgrade ##### -->
 <para>
 
diff --git a/mail/Makefile.am b/mail/Makefile.am
index e06b175..2f0f5c9 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -48,6 +48,7 @@ mailinclude_HEADERS =					\
 	e-mail-reader.h					\
 	e-mail-reader-utils.h				\
 	e-mail-search-bar.h				\
+	e-mail-sidebar.h				\
 	e-mail-store.h					\
 	e-mail-tag-editor.h				\
 	e-searching-tokenizer.h				\
@@ -104,6 +105,7 @@ libevolution_mail_la_SOURCES =				\
 	e-mail-reader.c					\
 	e-mail-reader-utils.c				\
 	e-mail-search-bar.c				\
+	e-mail-sidebar.c				\
 	e-mail-store.c					\
 	e-mail-tag-editor.c				\
 	e-searching-tokenizer.c				\
diff --git a/mail/e-mail-sidebar.c b/mail/e-mail-sidebar.c
new file mode 100644
index 0000000..95379e5
--- /dev/null
+++ b/mail/e-mail-sidebar.c
@@ -0,0 +1,616 @@
+/*
+ * e-mail-sidebar.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
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-sidebar.h"
+
+#include <string.h>
+#include <camel/camel.h>
+
+#include "mail/e-mail-local.h"
+#include "mail/em-utils.h"
+
+#define E_MAIL_SIDEBAR_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_SIDEBAR, EMailSidebarPrivate))
+
+#define STATE_KEY_EXPANDED	"Expanded"
+
+struct _EMailSidebarPrivate {
+	GKeyFile *key_file;  /* not owned */
+};
+
+enum {
+	PROP_0,
+	PROP_KEY_FILE
+};
+
+enum {
+	KEY_FILE_CHANGED,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+mail_sidebar_restore_state (EMailSidebar *sidebar)
+{
+	EMFolderTree *folder_tree;
+	GtkTreeModel *tree_model;
+	GtkTreeView *tree_view;
+	GtkTreeIter iter;
+	GKeyFile *key_file;
+	gboolean valid;
+	gchar *selected;
+	gchar **groups;
+	gint ii;
+
+	key_file = e_mail_sidebar_get_key_file (sidebar);
+
+	/* Make sure we have a key file to restore state from. */
+	if (key_file == NULL)
+		return;
+
+	folder_tree = EM_FOLDER_TREE (sidebar);
+
+	tree_view = GTK_TREE_VIEW (sidebar);
+	tree_model = gtk_tree_view_get_model (tree_view);
+
+	/* Restore selected folder. */
+
+	selected = g_key_file_get_string (
+		key_file, "Folder Tree", "Selected", NULL);
+	if (selected != NULL) {
+		em_folder_tree_set_selected (folder_tree, selected, FALSE);
+		g_free (selected);
+	}
+
+	/* Set the initial folder tree expanded state in two stages:
+	 *
+	 * 1) Iterate over the "Store" and "Folder" state file groups
+	 *    and apply the "Expanded" keys where possible.
+	 *
+	 * 2) Iterate over the top-level nodes in the folder tree
+	 *    (these are all stores) and expand those that have no
+	 *    corresponding "Expanded" key in the state file.  This
+	 *    ensures that new stores are expanded by default.
+	 */
+
+	/* Stage 1 */
+
+	/* Collapse all so we have a clean slate. */
+	gtk_tree_view_collapse_all (tree_view);
+
+	groups = g_key_file_get_groups (key_file, NULL);
+
+	for (ii = 0; groups[ii] != NULL; ii++) {
+		GtkTreeRowReference *reference;
+		GtkTreePath *path;
+		GtkTreeIter iter;
+		const gchar *group_name = groups[ii];
+		const gchar *key = STATE_KEY_EXPANDED;
+		const gchar *uri;
+		gboolean expanded;
+
+		if (g_str_has_prefix (group_name, "Store ")) {
+			uri = group_name + 6;
+			expanded = TRUE;
+		} else if (g_str_has_prefix (group_name, "Folder ")) {
+			uri = group_name + 7;
+			expanded = FALSE;
+		} else
+			continue;
+
+		if (g_key_file_has_key (key_file, group_name, key, NULL))
+			expanded = g_key_file_get_boolean (
+				key_file, group_name, key, NULL);
+
+		if (!expanded)
+			continue;
+
+		reference = em_folder_tree_model_lookup_uri (
+			EM_FOLDER_TREE_MODEL (tree_model), uri);
+		if (reference == NULL)
+			continue;
+
+		path = gtk_tree_row_reference_get_path (reference);
+		gtk_tree_model_get_iter (tree_model, &iter, path);
+		gtk_tree_view_expand_row (tree_view, path, FALSE);
+		gtk_tree_path_free (path);
+	}
+
+	g_strfreev (groups);
+
+	/* Stage 2 */
+
+	valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+	while (valid) {
+		const gchar *key = STATE_KEY_EXPANDED;
+		gchar *group_name;
+		gchar *uri;
+
+		gtk_tree_model_get (
+			tree_model, &iter, COL_STRING_URI, &uri, -1);
+
+		if (uri == NULL)
+			goto next;
+
+		group_name = g_strdup_printf ("Store %s", uri);
+
+		if (!g_key_file_has_key (key_file, group_name, key, NULL)) {
+			GtkTreePath *path;
+
+			path = gtk_tree_model_get_path (tree_model, &iter);
+			gtk_tree_view_expand_row (tree_view, path, FALSE);
+			gtk_tree_path_free (path);
+		}
+
+		g_free (group_name);
+		g_free (uri);
+
+	next:
+		valid = gtk_tree_model_iter_next (tree_model, &iter);
+	}
+}
+
+static void
+mail_sidebar_model_loaded_row_cb (GtkTreeModel *model,
+                                  GtkTreePath *path,
+                                  GtkTreeIter *iter,
+                                  EMailSidebar *sidebar)
+{
+	GtkTreeView *tree_view;
+	GKeyFile *key_file;
+	gboolean expanded;
+	gboolean is_folder;
+	gboolean is_store;
+	const gchar *key;
+	gchar *group_name;
+	gchar *uri;
+
+	tree_view = GTK_TREE_VIEW (sidebar);
+	key_file = e_mail_sidebar_get_key_file (sidebar);
+
+	/* Make sure we have a key file to record state changes. */
+	if (key_file == NULL)
+		return;
+
+	gtk_tree_model_get (
+		model, iter,
+		COL_STRING_URI, &uri,
+		COL_BOOL_IS_STORE, &is_store,
+		COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+	g_return_if_fail (is_store || is_folder);
+
+	key = STATE_KEY_EXPANDED;
+	if (is_store) {
+		group_name = g_strdup_printf ("Store %s", uri);
+		expanded = TRUE;
+	} else {
+		group_name = g_strdup_printf ("Folder %s", uri);
+		expanded = FALSE;
+	}
+
+	if (g_key_file_has_key (key_file, group_name, key, NULL))
+		expanded = g_key_file_get_boolean (
+			key_file, group_name, key, NULL);
+
+	if (expanded)
+		gtk_tree_view_expand_row (tree_view, path, FALSE);
+
+	g_free (group_name);
+	g_free (uri);
+}
+
+static void
+mail_sidebar_selection_changed_cb (GtkTreeSelection *selection,
+                                   EMailSidebar *sidebar)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GKeyFile *key_file;
+	gchar *uri = NULL;
+
+	key_file = e_mail_sidebar_get_key_file (sidebar);
+
+	/* Make sure we have a key file to record state changes. */
+	if (key_file == NULL)
+		return;
+
+	if (gtk_tree_selection_get_selected (selection, &model, &iter))
+		gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1);
+
+	if (uri != NULL)
+		g_key_file_set_string (
+			key_file, "Folder Tree", "Selected", uri);
+	else
+		g_key_file_remove_key (
+			key_file, "Folder Tree", "Selected", NULL);
+
+	e_mail_sidebar_key_file_changed (sidebar);
+}
+
+static void
+mail_sidebar_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_KEY_FILE:
+			e_mail_sidebar_set_key_file (
+				E_MAIL_SIDEBAR (object),
+				g_value_get_pointer (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_sidebar_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_KEY_FILE:
+			g_value_set_pointer (
+				value, e_mail_sidebar_get_key_file (
+				E_MAIL_SIDEBAR (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_sidebar_row_expanded (GtkTreeView *tree_view,
+                           GtkTreeIter *unused,
+                           GtkTreePath *path)
+{
+	GtkTreeViewClass *tree_view_class;
+	EMailSidebar *sidebar;
+	GtkTreeModel *model;
+	GKeyFile *key_file;
+	const gchar *key;
+	gboolean is_folder;
+	gboolean is_store;
+	gchar *group_name;
+	gchar *uri;
+
+	/* Chain up to parent's row_expanded() method.  Do this first
+	 * because we stomp on the path argument a few lines down. */
+	tree_view_class = GTK_TREE_VIEW_CLASS (parent_class);
+	tree_view_class->row_expanded (tree_view, unused, path);
+
+	sidebar = E_MAIL_SIDEBAR (tree_view);
+	key_file = e_mail_sidebar_get_key_file (sidebar);
+
+	/* Make sure we have a key file to record state changes. */
+	if (key_file == NULL)
+		return;
+
+	path = gtk_tree_path_copy (path);
+	model = gtk_tree_view_get_model (tree_view);
+
+	/* Expand the node and all ancestors. */
+	while (gtk_tree_path_get_depth (path) > 0) {
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter (model, &iter, path);
+
+		gtk_tree_model_get (
+			model, &iter,
+			COL_STRING_URI, &uri,
+			COL_BOOL_IS_STORE, &is_store,
+			COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+		g_return_if_fail (is_store || is_folder);
+
+		key = STATE_KEY_EXPANDED;
+		if (is_store)
+			group_name = g_strdup_printf ("Store %s", uri);
+		else
+			group_name = g_strdup_printf ("Folder %s", uri);
+
+		g_key_file_set_boolean (key_file, group_name, key, TRUE);
+		e_mail_sidebar_key_file_changed (sidebar);
+
+		g_free (group_name);
+		g_free (uri);
+
+		gtk_tree_path_up (path);
+	}
+
+	gtk_tree_path_free (path);
+}
+
+static void
+mail_sidebar_row_collapsed (GtkTreeView *tree_view,
+                            GtkTreeIter *iter,
+                            GtkTreePath *path)
+{
+	EMailSidebar *sidebar;
+	GtkTreeModel *model;
+	GKeyFile *key_file;
+	const gchar *key;
+	gboolean is_folder;
+	gboolean is_store;
+	gchar *group_name;
+	gchar *uri;
+
+	sidebar = E_MAIL_SIDEBAR (tree_view);
+	key_file = e_mail_sidebar_get_key_file (sidebar);
+
+	/* Make sure we have a key file to record state changes. */
+	if (key_file == NULL)
+		return;
+
+	model = gtk_tree_view_get_model (tree_view);
+
+	gtk_tree_model_get (
+		model, iter,
+		COL_STRING_URI, &uri,
+		COL_BOOL_IS_STORE, &is_store,
+		COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+	g_return_if_fail (is_store || is_folder);
+
+	key = STATE_KEY_EXPANDED;
+	if (is_store)
+		group_name = g_strdup_printf ("Store %s", uri);
+	else
+		group_name = g_strdup_printf ("Folder %s", uri);
+
+	g_key_file_set_boolean (key_file, group_name, key, FALSE);
+	e_mail_sidebar_key_file_changed (sidebar);
+
+	g_free (group_name);
+	g_free (uri);
+}
+
+static guint32
+mail_sidebar_check_state (EMailSidebar *sidebar)
+{
+	GtkTreeSelection *selection;
+	GtkTreeView *tree_view;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	CamelStore *local_store;
+	CamelStore *store;
+	gchar *full_name;
+	gchar *uri;
+	gboolean allows_children = TRUE;
+	gboolean can_delete = TRUE;
+	gboolean is_junk = FALSE;
+	gboolean is_outbox = FALSE;
+	gboolean is_store;
+	gboolean is_trash = FALSE;
+	guint32 folder_flags = 0;
+	guint32 state = 0;
+
+	local_store = e_mail_local_get_store ();
+
+	tree_view = GTK_TREE_VIEW (sidebar);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+		return 0;
+
+	gtk_tree_model_get (
+		model, &iter,
+		COL_POINTER_CAMEL_STORE, &store,
+		COL_STRING_FULL_NAME, &full_name,
+		COL_BOOL_IS_STORE, &is_store,
+		COL_UINT_FLAGS, &folder_flags,
+		COL_STRING_URI, &uri, -1);
+
+	if (!is_store && full_name != NULL) {
+		guint32 folder_type;
+
+		/* Is this a virtual junk or trash folder? */
+		is_junk = (strcmp (full_name, CAMEL_VJUNK_NAME) == 0);
+		is_trash = (strcmp (full_name, CAMEL_VTRASH_NAME) == 0);
+
+		/* Is this a real trash folder?
+		 * Used by Exchange and GroupWise accounts. */
+		folder_type = (folder_flags & CAMEL_FOLDER_TYPE_MASK);
+		is_trash |= (folder_type == CAMEL_FOLDER_TYPE_TRASH);
+
+		allows_children = !(is_junk || is_trash);
+
+		/* Don't allow deletion of special local folders. */
+		if (store == local_store)
+			can_delete =
+				(strcmp (full_name, "Drafts") != 0) &&
+				(strcmp (full_name, "Inbox") != 0) &&
+				(strcmp (full_name, "Outbox") != 0) &&
+				(strcmp (full_name, "Sent") != 0) &&
+				(strcmp (full_name, "Templates") != 0);
+
+		is_outbox = em_utils_folder_is_outbox (NULL, uri);
+		can_delete &= !(folder_flags & CAMEL_FOLDER_SYSTEM);
+	}
+
+	if (allows_children)
+		state |= E_MAIL_SIDEBAR_FOLDER_ALLOWS_CHILDREN;
+	if (can_delete)
+		state |= E_MAIL_SIDEBAR_FOLDER_CAN_DELETE;
+	if (is_junk)
+		state |= E_MAIL_SIDEBAR_FOLDER_IS_JUNK;
+	if (is_outbox)
+		state |= E_MAIL_SIDEBAR_FOLDER_IS_OUTBOX;
+	if (is_store)
+		state |= E_MAIL_SIDEBAR_FOLDER_IS_STORE;
+	if (is_trash)
+		state |= E_MAIL_SIDEBAR_FOLDER_IS_TRASH;
+
+	return state;
+}
+
+static void
+mail_sidebar_class_init (EMailSidebarClass *class)
+{
+	GObjectClass *object_class;
+	GtkTreeViewClass *tree_view_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMailSidebarPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = mail_sidebar_set_property;
+	object_class->get_property = mail_sidebar_get_property;
+
+	tree_view_class = GTK_TREE_VIEW_CLASS (class);
+	tree_view_class->row_expanded = mail_sidebar_row_expanded;
+	tree_view_class->row_collapsed = mail_sidebar_row_collapsed;
+
+	class->check_state = mail_sidebar_check_state;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_KEY_FILE,
+		g_param_spec_pointer (
+			"key-file",
+			"Key File",
+			NULL,
+			G_PARAM_READWRITE));
+
+	signals[KEY_FILE_CHANGED] = g_signal_new (
+		"key-file-changed",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		G_STRUCT_OFFSET (EMailSidebarClass, key_file_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+mail_sidebar_init (EMailSidebar *sidebar)
+{
+	GtkTreeModel *model;
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+	EMFolderTree *folder_tree;
+
+	sidebar->priv = E_MAIL_SIDEBAR_GET_PRIVATE (sidebar);
+
+	folder_tree = EM_FOLDER_TREE (sidebar);
+	em_folder_tree_set_excluded (folder_tree, 0);
+	em_folder_tree_enable_drag_and_drop (folder_tree);
+
+	tree_view = GTK_TREE_VIEW (sidebar);
+	model = gtk_tree_view_get_model (tree_view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	em_folder_tree_model_set_selection (
+		EM_FOLDER_TREE_MODEL (model), selection);
+
+	g_signal_connect (
+		model, "loaded-row",
+		G_CALLBACK (mail_sidebar_model_loaded_row_cb), sidebar);
+
+	g_signal_connect (
+		selection, "changed",
+		G_CALLBACK (mail_sidebar_selection_changed_cb), sidebar);
+}
+
+GType
+e_mail_sidebar_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMailSidebarClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) mail_sidebar_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMailSidebar),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) mail_sidebar_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			EM_TYPE_FOLDER_TREE, "EMailSidebar", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_mail_sidebar_new (void)
+{
+	return g_object_new (E_TYPE_MAIL_SIDEBAR, NULL);
+}
+
+GKeyFile *
+e_mail_sidebar_get_key_file (EMailSidebar *sidebar)
+{
+	g_return_val_if_fail (E_IS_MAIL_SIDEBAR (sidebar), NULL);
+
+	return sidebar->priv->key_file;
+}
+
+void
+e_mail_sidebar_set_key_file (EMailSidebar *sidebar,
+                             GKeyFile *key_file)
+{
+	g_return_if_fail (E_IS_MAIL_SIDEBAR (sidebar));
+
+	/* XXX GKeyFile has no reference count, so all we can do is
+	 *     replace the old pointer and hope the key file is not
+	 *     freed on us.  Most other GLib data structures have
+	 *     grown reference counts so maybe this should too. */
+	sidebar->priv->key_file = key_file;
+
+	mail_sidebar_restore_state (sidebar);
+
+	g_object_notify (G_OBJECT (sidebar), "key-file");
+}
+
+guint32
+e_mail_sidebar_check_state (EMailSidebar *sidebar)
+{
+	EMailSidebarClass *class;
+
+	g_return_val_if_fail (E_IS_MAIL_SIDEBAR (sidebar), 0);
+
+	class = E_MAIL_SIDEBAR_GET_CLASS (sidebar);
+	g_return_val_if_fail (class->check_state != NULL, 0);
+
+	return class->check_state (sidebar);
+}
+
+void
+e_mail_sidebar_key_file_changed (EMailSidebar *sidebar)
+{
+	g_return_if_fail (E_IS_MAIL_SIDEBAR (sidebar));
+
+	g_signal_emit (sidebar, signals[KEY_FILE_CHANGED], 0);
+}
diff --git a/mail/e-mail-sidebar.h b/mail/e-mail-sidebar.h
new file mode 100644
index 0000000..f08c05d
--- /dev/null
+++ b/mail/e-mail-sidebar.h
@@ -0,0 +1,87 @@
+/*
+ * e-mail-sidebar.h
+ *
+ * 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
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SIDEBAR_H
+#define E_MAIL_SIDEBAR_H
+
+#include <mail/em-folder-tree.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SIDEBAR \
+	(e_mail_sidebar_get_type ())
+#define E_MAIL_SIDEBAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_SIDEBAR, EMailSidebar))
+#define E_MAIL_SIDEBAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_SIDEBAR, EMailSidebarClass))
+#define E_IS_MAIL_SIDEBAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_SIDEBAR))
+#define E_IS_MAIL_SIDEBAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_SIDEBAR))
+#define E_MAIL_SIDEBAR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_SIDEBAR, EMailSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailSidebar EMailSidebar;
+typedef struct _EMailSidebarClass EMailSidebarClass;
+typedef struct _EMailSidebarPrivate EMailSidebarPrivate;
+
+/* Flags describing the selected folder. */
+enum {
+	E_MAIL_SIDEBAR_FOLDER_ALLOWS_CHILDREN	= 1 << 0,
+	E_MAIL_SIDEBAR_FOLDER_CAN_DELETE	= 1 << 1,
+	E_MAIL_SIDEBAR_FOLDER_IS_JUNK		= 1 << 2,
+	E_MAIL_SIDEBAR_FOLDER_IS_OUTBOX		= 1 << 3,
+	E_MAIL_SIDEBAR_FOLDER_IS_STORE		= 1 << 4,
+	E_MAIL_SIDEBAR_FOLDER_IS_TRASH		= 1 << 5
+};
+
+struct _EMailSidebar {
+	EMFolderTree parent;
+	EMailSidebarPrivate *priv;
+};
+
+struct _EMailSidebarClass {
+	EMFolderTreeClass parent;
+
+	/* Methods */
+	guint32		(*check_state)		(EMailSidebar *sidebar);
+
+	/* Signals */
+	void		(*key_file_changed)	(EMailSidebar *sidebar);
+};
+
+GType		e_mail_sidebar_get_type		(void);
+GtkWidget *	e_mail_sidebar_new		(void);
+GKeyFile *	e_mail_sidebar_get_key_file	(EMailSidebar *sidebar);
+void		e_mail_sidebar_set_key_file	(EMailSidebar *sidebar,
+						 GKeyFile *key_file);
+guint32		e_mail_sidebar_check_state	(EMailSidebar *sidebar);
+void		e_mail_sidebar_key_file_changed	(EMailSidebar *sidebar);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SIDEBAR_H */
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 4a336d1..c439961 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -381,6 +381,154 @@ folder_tree_select_func (GtkTreeSelection *selection,
 	return (flags & priv->excluded) == 0;
 }
 
+/* NOTE: Removes and frees the selected uri structure */
+static void
+folder_tree_select_uri (EMFolderTree *folder_tree,
+                        GtkTreePath *path,
+                        struct _selected_uri *u)
+{
+	EMFolderTreePrivate *priv = folder_tree->priv;
+	GtkTreeView *tree_view;
+	GtkTreeSelection *selection;
+
+	tree_view = GTK_TREE_VIEW (folder_tree);
+	selection = gtk_tree_view_get_selection (tree_view);
+	gtk_tree_selection_select_path(selection, path);
+	if (!priv->cursor_set) {
+		gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
+		priv->cursor_set = TRUE;
+	}
+	gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.8f, 0.0f);
+	g_hash_table_remove(priv->select_uris_table, u->key);
+	priv->select_uris = g_slist_remove(priv->select_uris, u);
+	folder_tree_free_select_uri(u);
+}
+
+static void
+folder_tree_expand_node (const gchar *key,
+                         EMFolderTree *folder_tree)
+{
+	struct _EMFolderTreeModelStoreInfo *si;
+	GtkTreeRowReference *row;
+	GtkTreeView *tree_view;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	EAccount *account;
+	CamelStore *store;
+	const gchar *p;
+	gchar *uid;
+	gsize n;
+	struct _selected_uri *u;
+
+	if (!(p = strchr (key, '/')))
+		n = strlen (key);
+	else
+		n = (p - key);
+
+	uid = g_alloca (n + 1);
+	memcpy (uid, key, n);
+	uid[n] = '\0';
+
+	tree_view = GTK_TREE_VIEW (folder_tree);
+	model = gtk_tree_view_get_model (tree_view);
+
+	if ((account = e_get_account_by_uid (uid)) && account->enabled) {
+		CamelException ex;
+
+		camel_exception_init (&ex);
+		store = (CamelStore *) camel_session_get_service (session, account->source->url, CAMEL_PROVIDER_STORE, &ex);
+		camel_exception_clear (&ex);
+
+		if (store == NULL)
+			return;
+	} else if (!strcmp (uid, "vfolder")) {
+		if (!(store = vfolder_store))
+			return;
+
+		camel_object_ref (store);
+	} else if (!strcmp (uid, "local")) {
+		if (!(store = e_mail_local_get_store ()))
+			return;
+
+		camel_object_ref (store);
+	} else {
+		return;
+	}
+
+	si = em_folder_tree_model_lookup_store_info (
+		EM_FOLDER_TREE_MODEL (model), store);
+	if (si == NULL) {
+		camel_object_unref (store);
+		return;
+	}
+
+	camel_object_unref (store);
+
+	if (p != NULL) {
+		if (!(row = g_hash_table_lookup (si->full_hash, p + 1)))
+			return;
+	} else
+		row = si->row;
+
+	path = gtk_tree_row_reference_get_path (row);
+	gtk_tree_view_expand_to_path (tree_view, path);
+
+	u = g_hash_table_lookup(folder_tree->priv->select_uris_table, key);
+	if (u)
+		folder_tree_select_uri(folder_tree, path, u);
+
+	gtk_tree_path_free (path);
+}
+
+static void
+folder_tree_maybe_expand_row (EMFolderTreeModel *model,
+                              GtkTreePath *tree_path,
+                              GtkTreeIter *iter,
+                              EMFolderTree *folder_tree)
+{
+	EMFolderTreePrivate *priv = folder_tree->priv;
+	struct _EMFolderTreeModelStoreInfo *si;
+	GtkTreeView *tree_view;
+	gboolean is_store;
+	CamelStore *store;
+	EAccount *account;
+	gchar *full_name;
+	gchar *key;
+	struct _selected_uri *u;
+
+	tree_view = GTK_TREE_VIEW (folder_tree);
+
+	gtk_tree_model_get ((GtkTreeModel *) model, iter,
+			    COL_STRING_FULL_NAME, &full_name,
+			    COL_POINTER_CAMEL_STORE, &store,
+			    COL_BOOL_IS_STORE, &is_store,
+			    -1);
+
+	si = em_folder_tree_model_lookup_store_info (model, store);
+	if ((account = e_get_account_by_name (si->display_name))) {
+		key = g_strdup_printf ("%s/%s", account->uid, full_name ? full_name : "");
+	} else if (CAMEL_IS_VEE_STORE (store)) {
+		/* vfolder store */
+		key = g_strdup_printf ("vfolder/%s", full_name ? full_name : "");
+	} else {
+		/* local store */
+		key = g_strdup_printf ("local/%s", full_name ? full_name : "");
+	}
+
+	u = g_hash_table_lookup(priv->select_uris_table, key);
+	if (u) {
+		gchar *c = strrchr (key, '/');
+
+		*c = '\0';
+		folder_tree_expand_node (key, folder_tree);
+
+		folder_tree_select_uri(folder_tree, tree_path, u);
+	}
+
+	g_free (full_name);
+	g_free (key);
+}
+
 static void
 folder_tree_clear_selected_list(EMFolderTree *folder_tree)
 {
@@ -854,57 +1002,6 @@ folder_tree_class_init (EMFolderTreeClass *class)
 			      G_TYPE_NONE, 1, GDK_TYPE_EVENT);
 }
 
-static void
-folder_tree_init (EMFolderTree *folder_tree)
-{
-	GtkTreeSelection *selection;
-	GHashTable *select_uris_table;
-	EMFolderTreeModel *model;
-	gulong handler_id;
-
-	select_uris_table = g_hash_table_new (g_str_hash, g_str_equal);
-
-	folder_tree->priv = EM_FOLDER_TREE_GET_PRIVATE (folder_tree);
-	folder_tree->priv->select_uris_table = select_uris_table;
-
-	model = em_folder_tree_model_get_default ();
-	gtk_tree_view_set_model (GTK_TREE_VIEW (folder_tree), GTK_TREE_MODEL (model));
-
-	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_tree));
-
-	handler_id = g_signal_connect_swapped (
-		selection, "changed",
-		G_CALLBACK (folder_tree_selection_changed_cb), folder_tree);
-
-	folder_tree->priv->selection_changed_handler_id = handler_id;
-}
-
-GType
-em_folder_tree_get_type (void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY (type == 0)) {
-		static const GTypeInfo type_info = {
-			sizeof (EMFolderTreeClass),
-			(GBaseInitFunc) NULL,
-			(GBaseFinalizeFunc) NULL,
-			(GClassInitFunc) folder_tree_class_init,
-			(GClassFinalizeFunc) NULL,
-			NULL,  /* class_data */
-			sizeof (EMFolderTree),
-			0,     /* n_preallocs */
-			(GInstanceInitFunc) folder_tree_init,
-			NULL   /* value_table */
-		};
-
-		type = g_type_register_static (
-			GTK_TYPE_TREE_VIEW, "EMFolderTree", &type_info, 0);
-	}
-
-	return type;
-}
-
 static gboolean
 subdirs_contain_unread (GtkTreeModel *model, GtkTreeIter *root)
 {
@@ -1144,171 +1241,79 @@ em_folder_tree_construct (EMFolderTree *folder_tree)
 	gtk_widget_show (GTK_WIDGET (folder_tree));
 }
 
-/* NOTE: Removes and frees the selected uri structure */
 static void
-folder_tree_select_uri(EMFolderTree *folder_tree, GtkTreePath *path, struct _selected_uri *u)
+folder_tree_init (EMFolderTree *folder_tree)
 {
-	EMFolderTreePrivate *priv = folder_tree->priv;
 	GtkTreeView *tree_view;
 	GtkTreeSelection *selection;
+	GHashTable *select_uris_table;
+	EMFolderTreeModel *model;
+	gulong handler_id;
+	AtkObject *a11y;
 
-	tree_view = GTK_TREE_VIEW (folder_tree);
-	selection = gtk_tree_view_get_selection (tree_view);
-	gtk_tree_selection_select_path(selection, path);
-	if (!priv->cursor_set) {
-		gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE);
-		priv->cursor_set = TRUE;
-	}
-	gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.8f, 0.0f);
-	g_hash_table_remove(priv->select_uris_table, u->key);
-	priv->select_uris = g_slist_remove(priv->select_uris, u);
-	folder_tree_free_select_uri(u);
-}
-
-static void
-folder_tree_expand_node (const gchar *key, EMFolderTree *folder_tree)
-{
-	struct _EMFolderTreeModelStoreInfo *si;
-	GtkTreeRowReference *row;
-	GtkTreeView *tree_view;
-	GtkTreeModel *model;
-	GtkTreePath *path;
-	EAccount *account;
-	CamelStore *store;
-	const gchar *p;
-	gchar *uid;
-	gsize n;
-	struct _selected_uri *u;
-
-	if (!(p = strchr (key, '/')))
-		n = strlen (key);
-	else
-		n = (p - key);
+	select_uris_table = g_hash_table_new (g_str_hash, g_str_equal);
 
-	uid = g_alloca (n + 1);
-	memcpy (uid, key, n);
-	uid[n] = '\0';
+	folder_tree->priv = EM_FOLDER_TREE_GET_PRIVATE (folder_tree);
+	folder_tree->priv->select_uris_table = select_uris_table;
 
 	tree_view = GTK_TREE_VIEW (folder_tree);
-	model = gtk_tree_view_get_model (tree_view);
-
-	if ((account = e_get_account_by_uid (uid)) && account->enabled) {
-		CamelException ex;
-
-		camel_exception_init (&ex);
-		store = (CamelStore *) camel_session_get_service (session, account->source->url, CAMEL_PROVIDER_STORE, &ex);
-		camel_exception_clear (&ex);
-
-		if (store == NULL)
-			return;
-	} else if (!strcmp (uid, "vfolder")) {
-		if (!(store = vfolder_store))
-			return;
-
-		camel_object_ref (store);
-	} else if (!strcmp (uid, "local")) {
-		if (!(store = e_mail_local_get_store ()))
-			return;
-
-		camel_object_ref (store);
-	} else {
-		return;
-	}
+	model = em_folder_tree_model_get_default ();
+	selection = gtk_tree_view_get_selection (tree_view);
 
-	si = em_folder_tree_model_lookup_store_info (
-		EM_FOLDER_TREE_MODEL (model), store);
-	if (si == NULL) {
-		camel_object_unref (store);
-		return;
-	}
+	gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (model));
 
-	camel_object_unref (store);
+	handler_id = g_signal_connect (
+		model, "loading-row",
+		G_CALLBACK (folder_tree_maybe_expand_row), folder_tree);
+	folder_tree->priv->loading_row_id = handler_id;
 
-	if (p != NULL) {
-		if (!(row = g_hash_table_lookup (si->full_hash, p + 1)))
-			return;
-	} else
-		row = si->row;
+	handler_id = g_signal_connect (
+		model, "loaded-row",
+		G_CALLBACK (folder_tree_maybe_expand_row), folder_tree);
+	folder_tree->priv->loaded_row_id = handler_id;
 
-	path = gtk_tree_row_reference_get_path (row);
-	gtk_tree_view_expand_to_path (tree_view, path);
+	handler_id = g_signal_connect_swapped (
+		selection, "changed",
+		G_CALLBACK (folder_tree_selection_changed_cb), folder_tree);
+	folder_tree->priv->selection_changed_handler_id = handler_id;
 
-	u = g_hash_table_lookup(folder_tree->priv->select_uris_table, key);
-	if (u)
-		folder_tree_select_uri(folder_tree, path, u);
+	a11y = gtk_widget_get_accessible (GTK_WIDGET (folder_tree));
+	atk_object_set_name (a11y, _("Mail Folder Tree"));
 
-	gtk_tree_path_free (path);
+	/* FIXME Kill this thing. */
+	em_folder_tree_construct (folder_tree);
 }
 
-static void
-folder_tree_maybe_expand_row (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTreeIter *iter, EMFolderTree *folder_tree)
+GType
+em_folder_tree_get_type (void)
 {
-	EMFolderTreePrivate *priv = folder_tree->priv;
-	struct _EMFolderTreeModelStoreInfo *si;
-	GtkTreeView *tree_view;
-	gboolean is_store;
-	CamelStore *store;
-	EAccount *account;
-	gchar *full_name;
-	gchar *key;
-	struct _selected_uri *u;
-
-	tree_view = GTK_TREE_VIEW (folder_tree);
-
-	gtk_tree_model_get ((GtkTreeModel *) model, iter,
-			    COL_STRING_FULL_NAME, &full_name,
-			    COL_POINTER_CAMEL_STORE, &store,
-			    COL_BOOL_IS_STORE, &is_store,
-			    -1);
-
-	si = em_folder_tree_model_lookup_store_info (model, store);
-	if ((account = e_get_account_by_name (si->display_name))) {
-		key = g_strdup_printf ("%s/%s", account->uid, full_name ? full_name : "");
-	} else if (CAMEL_IS_VEE_STORE (store)) {
-		/* vfolder store */
-		key = g_strdup_printf ("vfolder/%s", full_name ? full_name : "");
-	} else {
-		/* local store */
-		key = g_strdup_printf ("local/%s", full_name ? full_name : "");
-	}
-
-	u = g_hash_table_lookup(priv->select_uris_table, key);
-	if (u) {
-		gchar *c = strrchr (key, '/');
+	static GType type = 0;
 
-		*c = '\0';
-		folder_tree_expand_node (key, folder_tree);
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMFolderTreeClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) folder_tree_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMFolderTree),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) folder_tree_init,
+			NULL   /* value_table */
+		};
 
-		folder_tree_select_uri(folder_tree, tree_path, u);
+		type = g_type_register_static (
+			GTK_TYPE_TREE_VIEW, "EMFolderTree", &type_info, 0);
 	}
 
-	g_free (full_name);
-	g_free (key);
+	return type;
 }
 
 GtkWidget *
 em_folder_tree_new (void)
 {
-	EMFolderTree *folder_tree;
-	GtkTreeModel *model;
-	AtkObject *a11y;
-
-	folder_tree = g_object_new (EM_TYPE_FOLDER_TREE, NULL);
-	em_folder_tree_construct (folder_tree);
-
-	model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_tree));
-
-	folder_tree->priv->loading_row_id = g_signal_connect (
-		model, "loading-row",
-		G_CALLBACK (folder_tree_maybe_expand_row), folder_tree);
-	folder_tree->priv->loaded_row_id = g_signal_connect (
-		model, "loaded-row",
-		G_CALLBACK (folder_tree_maybe_expand_row), folder_tree);
-
-	a11y = gtk_widget_get_accessible (GTK_WIDGET (folder_tree));
-	atk_object_set_name (a11y, _("Mail Folder Tree"));
-
-	return (GtkWidget *) folder_tree;
+	return g_object_new (EM_TYPE_FOLDER_TREE, NULL);
 }
 
 static void
diff --git a/modules/mail/e-mail-shell-sidebar.c b/modules/mail/e-mail-shell-sidebar.c
index fa0acd1..70b59ad 100644
--- a/modules/mail/e-mail-shell-sidebar.c
+++ b/modules/mail/e-mail-shell-sidebar.c
@@ -21,23 +21,15 @@
 
 #include "e-mail-shell-sidebar.h"
 
-#include <string.h>
-#include <camel/camel.h>
-
 #include "e-util/e-binding.h"
 
-#include "em-utils.h"
-#include "em-folder-utils.h"
-
-#include "e-mail-local.h"
-#include "e-mail-store.h"
+#include "mail/e-mail-sidebar.h"
+#include "mail/em-folder-utils.h"
 
 #define E_MAIL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarPrivate))
 
-#define STATE_KEY_EXPANDED	"Expanded"
-
 struct _EMailShellSidebarPrivate {
 	GtkWidget *folder_tree;
 };
@@ -51,270 +43,6 @@ static gpointer parent_class;
 static GType mail_shell_sidebar_type;
 
 static void
-mail_shell_sidebar_restore_state (EMailShellSidebar *mail_shell_sidebar)
-{
-	EShellView *shell_view;
-	EShellSidebar *shell_sidebar;
-	EMFolderTree *folder_tree;
-	GtkTreeModel *tree_model;
-	GtkTreeView *tree_view;
-	GtkTreeIter iter;
-	GKeyFile *key_file;
-	gboolean valid;
-	gchar *selected;
-	gchar **groups;
-	gint ii;
-
-	shell_sidebar = E_SHELL_SIDEBAR (mail_shell_sidebar);
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	key_file = e_shell_view_get_state_key_file (shell_view);
-
-	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
-
-	tree_view = GTK_TREE_VIEW (folder_tree);
-	tree_model = gtk_tree_view_get_model (tree_view);
-
-	/* Restore selected folder. */
-
-	selected = g_key_file_get_string (
-		key_file, "Folder Tree", "Selected", NULL);
-	if (selected != NULL) {
-		em_folder_tree_set_selected (folder_tree, selected, FALSE);
-		g_free (selected);
-	}
-
-	/* Set the initial folder tree expanded state in two stages:
-	 *
-	 * 1) Iterate over the "Store" and "Folder" state file groups
-	 *    and apply the "Expanded" keys where possible.
-	 *
-	 * 2) Iterate over the top-level nodes in the folder tree
-	 *    (these are all stores) and expand those that have no
-	 *    corresponding "Expanded" key in the state file.  This
-	 *    ensures that new stores are expanded by default.
-	 */
-
-	/* Stage 1 */
-
-	groups = g_key_file_get_groups (key_file, NULL);
-
-	for (ii = 0; groups[ii] != NULL; ii++) {
-		GtkTreeRowReference *reference;
-		GtkTreePath *path;
-		GtkTreeIter iter;
-		const gchar *group_name = groups[ii];
-		const gchar *key = STATE_KEY_EXPANDED;
-		const gchar *uri;
-		gboolean expanded;
-
-		if (g_str_has_prefix (group_name, "Store ")) {
-			uri = group_name + 6;
-			expanded = TRUE;
-		} else if (g_str_has_prefix (group_name, "Folder ")) {
-			uri = group_name + 7;
-			expanded = FALSE;
-		} else
-			continue;
-
-		if (g_key_file_has_key (key_file, group_name, key, NULL))
-			expanded = g_key_file_get_boolean (
-				key_file, group_name, key, NULL);
-
-		if (!expanded)
-			continue;
-
-		reference = em_folder_tree_model_lookup_uri (
-			EM_FOLDER_TREE_MODEL (tree_model), uri);
-		if (reference == NULL)
-			continue;
-
-		path = gtk_tree_row_reference_get_path (reference);
-		gtk_tree_model_get_iter (tree_model, &iter, path);
-		gtk_tree_view_expand_row (tree_view, path, FALSE);
-		gtk_tree_path_free (path);
-	}
-
-	g_strfreev (groups);
-
-	/* Stage 2 */
-
-	valid = gtk_tree_model_get_iter_first (tree_model, &iter);
-
-	while (valid) {
-		const gchar *key = STATE_KEY_EXPANDED;
-		gchar *group_name;
-		gchar *uri;
-
-		gtk_tree_model_get (
-			tree_model, &iter, COL_STRING_URI, &uri, -1);
-
-		if (uri == NULL)
-			goto next;
-
-		group_name = g_strdup_printf ("Store %s", uri);
-
-		if (!g_key_file_has_key (key_file, group_name, key, NULL)) {
-			GtkTreePath *path;
-
-			path = gtk_tree_model_get_path (tree_model, &iter);
-			gtk_tree_view_expand_row (tree_view, path, FALSE);
-			gtk_tree_path_free (path);
-		}
-
-		g_free (group_name);
-		g_free (uri);
-
-	next:
-		valid = gtk_tree_model_iter_next (tree_model, &iter);
-	}
-}
-
-static void
-mail_shell_sidebar_row_collapsed_cb (EShellSidebar *shell_sidebar,
-                                     GtkTreeIter *iter,
-                                     GtkTreePath *path,
-                                     GtkTreeView *tree_view)
-{
-	EShellView *shell_view;
-	GtkTreeModel *model;
-	GKeyFile *key_file;
-	const gchar *key;
-	gboolean is_folder;
-	gboolean is_store;
-	gchar *group_name;
-	gchar *uri;
-
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	key_file = e_shell_view_get_state_key_file (shell_view);
-
-	model = gtk_tree_view_get_model (tree_view);
-
-	gtk_tree_model_get (
-		model, iter,
-		COL_STRING_URI, &uri,
-		COL_BOOL_IS_STORE, &is_store,
-		COL_BOOL_IS_FOLDER, &is_folder, -1);
-
-	g_return_if_fail (is_store || is_folder);
-
-	key = STATE_KEY_EXPANDED;
-	if (is_store)
-		group_name = g_strdup_printf ("Store %s", uri);
-	else
-		group_name = g_strdup_printf ("Folder %s", uri);
-
-	g_key_file_set_boolean (key_file, group_name, key, FALSE);
-	e_shell_view_set_state_dirty (shell_view);
-
-	g_free (group_name);
-	g_free (uri);
-}
-
-static void
-mail_shell_sidebar_row_expanded_cb (EShellSidebar *shell_sidebar,
-                                    GtkTreeIter *unused,
-                                    GtkTreePath *path,
-                                    GtkTreeView *tree_view)
-{
-	EShellView *shell_view;
-	GtkTreeModel *model;
-	GKeyFile *key_file;
-	const gchar *key;
-	gboolean is_folder;
-	gboolean is_store;
-	gchar *group_name;
-	gchar *uri;
-
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	key_file = e_shell_view_get_state_key_file (shell_view);
-
-	path = gtk_tree_path_copy (path);
-	model = gtk_tree_view_get_model (tree_view);
-
-	/* Expand the node and all ancestors. */
-	while (gtk_tree_path_get_depth (path) > 0) {
-		GtkTreeIter iter;
-
-		gtk_tree_model_get_iter (model, &iter, path);
-
-		gtk_tree_model_get (
-			model, &iter,
-			COL_STRING_URI, &uri,
-			COL_BOOL_IS_STORE, &is_store,
-			COL_BOOL_IS_FOLDER, &is_folder, -1);
-
-		g_return_if_fail (is_store || is_folder);
-
-		key = STATE_KEY_EXPANDED;
-		if (is_store)
-			group_name = g_strdup_printf ("Store %s", uri);
-		else
-			group_name = g_strdup_printf ("Folder %s", uri);
-
-		g_key_file_set_boolean (key_file, group_name, key, TRUE);
-		e_shell_view_set_state_dirty (shell_view);
-
-		g_free (group_name);
-		g_free (uri);
-
-		gtk_tree_path_up (path);
-	}
-
-	gtk_tree_path_free (path);
-}
-
-static void
-mail_shell_sidebar_model_loaded_row_cb (EMailShellSidebar *mail_shell_sidebar,
-                                        GtkTreePath *path,
-                                        GtkTreeIter *iter,
-                                        GtkTreeModel *model)
-{
-	EShellSidebar *shell_sidebar;
-	EShellView *shell_view;
-	GtkTreeView *tree_view;
-	GKeyFile *key_file;
-	gboolean is_folder;
-	gboolean is_store;
-	const gchar *key;
-	gchar *group_name;
-	gchar *uri;
-	gboolean expanded;
-
-	shell_sidebar = E_SHELL_SIDEBAR (mail_shell_sidebar);
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-	key_file = e_shell_view_get_state_key_file (shell_view);
-
-	tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
-
-	gtk_tree_model_get (
-		model, iter,
-		COL_STRING_URI, &uri,
-		COL_BOOL_IS_STORE, &is_store,
-		COL_BOOL_IS_FOLDER, &is_folder, -1);
-
-	g_return_if_fail (is_store || is_folder);
-
-	key = STATE_KEY_EXPANDED;
-	if (is_store) {
-		group_name = g_strdup_printf ("Store %s", uri);
-		expanded = TRUE;
-	} else {
-		group_name = g_strdup_printf ("Folder %s", uri);
-		expanded = FALSE;
-	}
-
-	if (g_key_file_has_key (key_file, group_name, key, NULL))
-		expanded = g_key_file_get_boolean (
-			key_file, group_name, key, NULL);
-
-	if (expanded)
-		gtk_tree_view_expand_row (tree_view, path, FALSE);
-
-	g_free (group_name);
-	g_free (uri);
-}
-
-static void
 mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
                                          GtkTreeSelection *selection)
 {
@@ -322,34 +50,21 @@ mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
 	EShellViewClass *shell_view_class;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
-	GKeyFile *key_file;
 	const gchar *icon_name;
 	gchar *display_name = NULL;
-	gchar *uri = NULL;
 	gboolean is_folder = FALSE;
 	guint flags = 0;
 
 	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
-	key_file = e_shell_view_get_state_key_file (shell_view);
 
 	if (gtk_tree_selection_get_selected (selection, &model, &iter))
 		gtk_tree_model_get (
 			model, &iter,
 			COL_STRING_DISPLAY_NAME, &display_name,
-			COL_STRING_URI, &uri,
 			COL_BOOL_IS_FOLDER, &is_folder,
 			COL_UINT_FLAGS, &flags, -1);
 
-	if (uri != NULL)
-		g_key_file_set_string (
-			key_file, "Folder Tree", "Selected", uri);
-	else
-		g_key_file_remove_key (
-			key_file, "Folder Tree", "Selected", NULL);
-
-	e_shell_view_set_state_dirty (shell_view);
-
 	if (is_folder)
 		icon_name = em_folder_utils_get_icon_name (flags);
 	else {
@@ -361,7 +76,6 @@ mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
 	e_shell_sidebar_set_primary_text (shell_sidebar, display_name);
 
 	g_free (display_name);
-	g_free (uri);
 }
 
 static void
@@ -398,17 +112,6 @@ mail_shell_sidebar_dispose (GObject *object)
 }
 
 static void
-mail_shell_sidebar_finalize (GObject *object)
-{
-	EMailShellSidebarPrivate *priv;
-
-	priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
-
-	/* Chain up to parent's finalize() method. */
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
 mail_shell_sidebar_constructed (GObject *object)
 {
 	EMailShellSidebar *mail_shell_sidebar;
@@ -419,7 +122,6 @@ mail_shell_sidebar_constructed (GObject *object)
 	EShell *shell;
 	GtkTreeSelection *selection;
 	GtkTreeView *tree_view;
-	GtkTreeModel *model;
 	GtkWidget *container;
 	GtkWidget *widget;
 
@@ -450,40 +152,25 @@ mail_shell_sidebar_constructed (GObject *object)
 
 	container = widget;
 
-	widget = em_folder_tree_new ();
-	em_folder_tree_set_excluded (EM_FOLDER_TREE (widget), 0);
-	em_folder_tree_enable_drag_and_drop (EM_FOLDER_TREE (widget));
+	widget = e_mail_sidebar_new ();
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	mail_shell_sidebar->priv->folder_tree = g_object_ref (widget);
 	gtk_widget_show (widget);
 
 	e_binding_new (
+		shell_view, "state-key-file",
+		widget, "key-file");
+
+	e_binding_new (
 		shell_settings, "mail-side-bar-search",
 		widget, "enable-search");
 
-	tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
-	selection = gtk_tree_view_get_selection (tree_view);
-	model = gtk_tree_view_get_model (tree_view);
-
-	mail_shell_sidebar_restore_state (mail_shell_sidebar);
-
-	em_folder_tree_model_set_selection (
-		EM_FOLDER_TREE_MODEL (model), selection);
-
 	g_signal_connect_swapped (
-		tree_view, "row-collapsed",
-		G_CALLBACK (mail_shell_sidebar_row_collapsed_cb),
-		shell_sidebar);
+		widget, "key-file-changed",
+		G_CALLBACK (e_shell_view_set_state_dirty), shell_view);
 
-	g_signal_connect_swapped (
-		tree_view, "row-expanded",
-		G_CALLBACK (mail_shell_sidebar_row_expanded_cb),
-		shell_sidebar);
-
-	g_signal_connect_swapped (
-		model, "loaded-row",
-		G_CALLBACK (mail_shell_sidebar_model_loaded_row_cb),
-		shell_sidebar);
+	tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
+	selection = gtk_tree_view_get_selection (tree_view);
 
 	g_signal_connect_swapped (
 		selection, "changed",
@@ -494,87 +181,13 @@ mail_shell_sidebar_constructed (GObject *object)
 static guint32
 mail_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
 {
-	EMailShellSidebar *mail_shell_sidebar;
-	EShellView *shell_view;
-	EMFolderTree *folder_tree;
-	GtkTreeSelection *selection;
-	GtkTreeView *tree_view;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	CamelStore *local_store;
-	CamelStore *store;
-	gchar *full_name;
-	gchar *uri;
-	gboolean allows_children = TRUE;
-	gboolean can_delete = TRUE;
-	gboolean is_junk = FALSE;
-	gboolean is_outbox = FALSE;
-	gboolean is_store;
-	gboolean is_trash = FALSE;
-	guint32 folder_flags = 0;
-	guint32 state = 0;
-
-	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
-
-	local_store = e_mail_local_get_store ();
-
-	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
-	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
-	tree_view = GTK_TREE_VIEW (folder_tree);
+	EMailShellSidebarPrivate *priv;
+	EMailSidebar *sidebar;
 
-	selection = gtk_tree_view_get_selection (tree_view);
-	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-		return 0;
-
-	gtk_tree_model_get (
-		model, &iter,
-		COL_POINTER_CAMEL_STORE, &store,
-		COL_STRING_FULL_NAME, &full_name,
-		COL_BOOL_IS_STORE, &is_store,
-		COL_UINT_FLAGS, &folder_flags,
-		COL_STRING_URI, &uri, -1);
-
-	if (!is_store && full_name != NULL) {
-		guint32 folder_type;
-
-		/* Is this a virtual junk or trash folder? */
-		is_junk = (strcmp (full_name, CAMEL_VJUNK_NAME) == 0);
-		is_trash = (strcmp (full_name, CAMEL_VTRASH_NAME) == 0);
-
-		/* Is this is a real trash folder? */
-		/* Used by Exchange and GroupWise accounts. */
-		folder_type = (folder_flags & CAMEL_FOLDER_TYPE_MASK);
-		is_trash |= (folder_type == CAMEL_FOLDER_TYPE_TRASH);
-
-		allows_children = !(is_junk || is_trash);
-
-		/* Don't allow deletion of special local folders. */
-		if (store == local_store)
-			can_delete =
-				(strcmp (full_name, "Drafts") != 0) &&
-				(strcmp (full_name, "Inbox") != 0) &&
-				(strcmp (full_name, "Outbox") != 0) &&
-				(strcmp (full_name, "Sent") != 0) &&
-				(strcmp (full_name, "Templates") != 0);
-
-		is_outbox = em_utils_folder_is_outbox (NULL, uri);
-		can_delete &= !(folder_flags & CAMEL_FOLDER_SYSTEM);
-	}
+	priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (shell_sidebar);
+	sidebar = E_MAIL_SIDEBAR (priv->folder_tree);
 
-	if (allows_children)
-		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN;
-	if (can_delete)
-		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE;
-	if (is_junk)
-		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK;
-	if (is_outbox)
-		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX;
-	if (is_store)
-		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE;
-	if (is_trash)
-		state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH;
-
-	return state;
+	return e_mail_sidebar_check_state (sidebar);
 }
 
 static void
@@ -589,7 +202,6 @@ mail_shell_sidebar_class_init (EMailShellSidebarClass *class)
 	object_class = G_OBJECT_CLASS (class);
 	object_class->get_property = mail_shell_sidebar_get_property;
 	object_class->dispose = mail_shell_sidebar_dispose;
-	object_class->finalize = mail_shell_sidebar_finalize;
 	object_class->constructed = mail_shell_sidebar_constructed;
 
 	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
diff --git a/modules/mail/e-mail-shell-sidebar.h b/modules/mail/e-mail-shell-sidebar.h
index 10a2ff6..b27bd80 100644
--- a/modules/mail/e-mail-shell-sidebar.h
+++ b/modules/mail/e-mail-shell-sidebar.h
@@ -51,15 +51,6 @@ typedef struct _EMailShellSidebar EMailShellSidebar;
 typedef struct _EMailShellSidebarClass EMailShellSidebarClass;
 typedef struct _EMailShellSidebarPrivate EMailShellSidebarPrivate;
 
-enum {
-	E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN	= 1 << 0,
-	E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE		= 1 << 1,
-	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK		= 1 << 2,
-	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX		= 1 << 3,
-	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE		= 1 << 4,
-	E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH		= 1 << 5
-};
-
 struct _EMailShellSidebar {
 	EShellSidebar parent;
 	EMailShellSidebarPrivate *priv;
diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h
index dac7d81..bd99da5 100644
--- a/modules/mail/e-mail-shell-view-private.h
+++ b/modules/mail/e-mail-shell-view-private.h
@@ -45,6 +45,7 @@
 #include "e-mail-label-list-store.h"
 #include "e-mail-local.h"
 #include "e-mail-reader.h"
+#include "e-mail-sidebar.h"
 #include "e-mail-store.h"
 #include "em-composer-utils.h"
 #include "em-folder-properties.h"
diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c
index 70ab01c..a3dbbed 100644
--- a/modules/mail/e-mail-shell-view.c
+++ b/modules/mail/e-mail-shell-view.c
@@ -448,17 +448,17 @@ mail_shell_view_update_actions (EShellView *shell_view)
 	state = e_shell_sidebar_check_state (shell_sidebar);
 
 	folder_allows_children =
-		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
+		(state & E_MAIL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
 	folder_can_be_deleted =
-		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE);
+		(state & E_MAIL_SIDEBAR_FOLDER_CAN_DELETE);
 	folder_is_junk =
-		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK);
+		(state & E_MAIL_SIDEBAR_FOLDER_IS_JUNK);
 	folder_is_outbox =
-		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX);
+		(state & E_MAIL_SIDEBAR_FOLDER_IS_OUTBOX);
 	folder_is_store =
-		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE);
+		(state & E_MAIL_SIDEBAR_FOLDER_IS_STORE);
 	folder_is_trash =
-		(state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH);
+		(state & E_MAIL_SIDEBAR_FOLDER_IS_TRASH);
 
 	uri = em_folder_tree_get_selected_uri (folder_tree);
 	if (uri != NULL) {
diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c
index 03dac3b..8ee65e0 100644
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@ -64,6 +64,7 @@ enum {
 	PROP_SHELL_SIDEBAR,
 	PROP_SHELL_TASKBAR,
 	PROP_SHELL_WINDOW,
+	PROP_STATE_KEY_FILE,
 	PROP_VIEW_ID
 };
 
@@ -322,6 +323,12 @@ shell_view_get_property (GObject *object,
 				E_SHELL_VIEW (object)));
 			return;
 
+		case PROP_STATE_KEY_FILE:
+			g_value_set_pointer (
+				value, e_shell_view_get_state_key_file (
+				E_SHELL_VIEW (object)));
+			return;
+
 		case PROP_VIEW_ID:
 			g_value_set_string (
 				value, e_shell_view_get_view_id (
@@ -604,6 +611,20 @@ shell_view_class_init (EShellViewClass *class)
 			G_PARAM_CONSTRUCT_ONLY));
 
 	/**
+	 * EShellView:state-key-file
+	 *
+	 * The #GKeyFile holding widget state data.
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_STATE_KEY_FILE,
+		g_param_spec_pointer (
+			"state-key-file",
+			"State Key File",
+			_("The key file holding widget state data"),
+			G_PARAM_READABLE));
+
+	/**
 	 * EShellView:view-id
 	 *
 	 * The current #GalView ID.



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