aboutsummaryrefslogtreecommitdiffstats
path: root/mail/em-folder-tree-model.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2009-08-30 13:37:36 +0800
committerMatthew Barnes <mbarnes@redhat.com>2009-08-30 13:40:49 +0800
commitcfb9c32b6657165e4d5e11aa7b47804f679a61f8 (patch)
tree1f9c8954df7a357b5dc20a13ac82bf31c1112083 /mail/em-folder-tree-model.c
parentfefeb30f58447f2fa7bcbee16dbe68a9333ce89d (diff)
parent0f7f4cfe38b3c4cd83efbe9922ae15c5aee00317 (diff)
downloadgsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar
gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.gz
gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.bz2
gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.lz
gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.xz
gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.zst
gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.zip
Merge commit 'origin/kill-bonobo'
Diffstat (limited to 'mail/em-folder-tree-model.c')
-rw-r--r--mail/em-folder-tree-model.c1371
1 files changed, 591 insertions, 780 deletions
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index 0a2ce6204e..9154e13c48 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -20,9 +20,7 @@
*
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "em-folder-tree-model.h"
#include <stdio.h>
#include <string.h>
@@ -32,13 +30,8 @@
#include <errno.h>
#include <sys/stat.h>
-#include <libxml/parser.h>
-
-#include <libedataserver/e-xml-utils.h>
-#include <libedataserver/e-data-server-util.h>
-
-#include <e-util/e-util.h>
-#include <e-util/e-mktemp.h>
+#include "e-util/e-util.h"
+#include "e-util/e-account-utils.h"
#include <glib/gi18n.h>
@@ -50,7 +43,6 @@
#include "mail-mt.h"
/* sigh, these 2 only needed for outbox total count checking - a mess */
-#include "mail-component.h"
#include "mail-folder-cache.h"
#include "em-utils.h"
@@ -60,22 +52,39 @@
#include <camel/camel-folder.h>
#include <camel/camel-vee-store.h>
-#include "em-folder-tree-model.h"
+#include "e-mail-local.h"
-#define u(x) /* unread count debug */
#define d(x)
-/* GObject virtual method overrides */
-static void em_folder_tree_model_class_init (EMFolderTreeModelClass *klass);
-static void em_folder_tree_model_init (EMFolderTreeModel *model);
-static void em_folder_tree_model_finalize (GObject *obj);
+#define EM_FOLDER_TREE_MODEL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), EM_TYPE_FOLDER_TREE_MODEL, EMFolderTreeModelPrivate))
+
+struct _EMFolderTreeModelPrivate {
+ /* This is set by EMailShellSidebar. It allows new EMFolderTree
+ * instances to initialize their selection and expanded states to
+ * mimic the sidebar. */
+ GtkTreeSelection *selection; /* weak reference */
+
+ EAccountList *accounts;
-/* interface init methods */
-static void tree_model_iface_init (GtkTreeModelIface *iface);
-static void tree_sortable_iface_init (GtkTreeSortableIface *iface);
+ /* EAccount -> EMFolderTreeStoreInfo */
+ GHashTable *account_index;
-static void account_changed (EAccountList *accounts, EAccount *account, gpointer user_data);
-static void account_removed (EAccountList *accounts, EAccount *account, gpointer user_data);
+ /* CamelStore -> EMFolderTreeStoreInfo */
+ GHashTable *store_index;
+
+ /* URI -> GtkTreeRowReference */
+ GHashTable *uri_index;
+
+ gulong account_changed_id;
+ gulong account_removed_id;
+};
+
+enum {
+ PROP_0,
+ PROP_SELECTION
+};
enum {
LOADING_ROW,
@@ -86,94 +95,30 @@ enum {
extern CamelStore *vfolder_store;
-static guint signals[LAST_SIGNAL] = { 0, };
-static GtkTreeStoreClass *parent_class = NULL;
-
-GType
-em_folder_tree_model_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof (EMFolderTreeModelClass),
- NULL, /* base_class_init */
- NULL, /* base_class_finalize */
- (GClassInitFunc) em_folder_tree_model_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (EMFolderTreeModel),
- 0, /* n_preallocs */
- (GInstanceInitFunc) em_folder_tree_model_init,
- };
- static const GInterfaceInfo tree_model_info = {
- (GInterfaceInitFunc) tree_model_iface_init,
- NULL,
- NULL
- };
- static const GInterfaceInfo sortable_info = {
- (GInterfaceInitFunc) tree_sortable_iface_init,
- NULL,
- NULL
- };
-
- type = g_type_register_static (GTK_TYPE_TREE_STORE, "EMFolderTreeModel", &info, 0);
-
- g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL,
- &tree_model_info);
- g_type_add_interface_static (type, GTK_TYPE_TREE_SORTABLE,
- &sortable_info);
- }
-
- return type;
-}
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
static void
-em_folder_tree_model_class_init (EMFolderTreeModelClass *klass)
+store_info_free (EMFolderTreeModelStoreInfo *si)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (GTK_TYPE_TREE_STORE);
-
- object_class->finalize = em_folder_tree_model_finalize;
-
- /* signals */
- signals[LOADING_ROW] =
- g_signal_new ("loading-row",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EMFolderTreeModelClass, loading_row),
- NULL, NULL,
- e_marshal_VOID__POINTER_POINTER,
- G_TYPE_NONE, 2,
- G_TYPE_POINTER,
- G_TYPE_POINTER);
-
- signals[LOADED_ROW] =
- g_signal_new ("loaded-row",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EMFolderTreeModelClass, loaded_row),
- NULL, NULL,
- e_marshal_VOID__POINTER_POINTER,
- G_TYPE_NONE, 2,
- G_TYPE_POINTER,
- G_TYPE_POINTER);
-
- signals[FOLDER_ADDED] =
- g_signal_new ("folder-added",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EMFolderTreeModelClass, folder_added),
- NULL, NULL,
- e_marshal_VOID__STRING_STRING,
- G_TYPE_NONE, 2,
- G_TYPE_STRING,
- G_TYPE_STRING);
+ camel_object_remove_event (si->store, si->created_id);
+ camel_object_remove_event (si->store, si->deleted_id);
+ camel_object_remove_event (si->store, si->renamed_id);
+ camel_object_remove_event (si->store, si->subscribed_id);
+ camel_object_remove_event (si->store, si->unsubscribed_id);
+
+ g_free (si->display_name);
+ camel_object_unref (si->store);
+ gtk_tree_row_reference_free (si->row);
+ g_hash_table_destroy (si->full_hash);
+ g_free (si);
}
static gint
-sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
+folder_tree_model_sort (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
{
gchar *aname, *bname;
CamelStore *store;
@@ -181,13 +126,21 @@ sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data
guint32 aflags, bflags;
gint rv = -2;
- gtk_tree_model_get (model, a, COL_BOOL_IS_STORE, &is_store,
- COL_POINTER_CAMEL_STORE, &store,
- COL_STRING_DISPLAY_NAME, &aname, COL_UINT_FLAGS, &aflags, -1);
- gtk_tree_model_get (model, b, COL_STRING_DISPLAY_NAME, &bname, COL_UINT_FLAGS, &bflags, -1);
+ gtk_tree_model_get (
+ model, a,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_POINTER_CAMEL_STORE, &store,
+ COL_STRING_DISPLAY_NAME, &aname,
+ COL_UINT_FLAGS, &aflags, -1);
+
+ gtk_tree_model_get (
+ model, b,
+ COL_STRING_DISPLAY_NAME, &bname,
+ COL_UINT_FLAGS, &bflags, -1);
if (is_store) {
- /* On This Computer is always first and Search Folders is always last */
+ /* On This Computer is always first, and Search Folders
+ * is always last. */
if (!strcmp (aname, _("On This Computer")))
rv = -1;
else if (!strcmp (bname, _("On This Computer")))
@@ -197,13 +150,13 @@ sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data
else if (!strcmp (bname, _("Search Folders")))
rv = -1;
} else if (store == vfolder_store) {
- /* UNMATCHED is always last */
+ /* UNMATCHED is always last. */
if (aname && !strcmp (aname, _("UNMATCHED")))
rv = 1;
else if (bname && !strcmp (bname, _("UNMATCHED")))
rv = -1;
} else {
- /* Inbox is always first */
+ /* Inbox is always first. */
if ((aflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
rv = -1;
else if ((bflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
@@ -226,136 +179,203 @@ sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data
}
static void
-store_info_free (struct _EMFolderTreeModelStoreInfo *si)
+account_changed_cb (EAccountList *accounts,
+ EAccount *account,
+ EMFolderTreeModel *model)
{
- camel_object_remove_event (si->store, si->created_id);
- camel_object_remove_event (si->store, si->deleted_id);
- camel_object_remove_event (si->store, si->renamed_id);
- camel_object_remove_event (si->store, si->subscribed_id);
- camel_object_remove_event (si->store, si->unsubscribed_id);
+ EMFolderTreeModelStoreInfo *si;
+ CamelProvider *provider;
+ CamelStore *store;
+ CamelException ex;
+ gchar *uri;
- g_free (si->display_name);
- camel_object_unref (si->store);
- gtk_tree_row_reference_free (si->row);
- g_hash_table_destroy (si->full_hash);
- g_free (si);
-}
+ si = g_hash_table_lookup (model->priv->account_index, account);
+ if (si == NULL)
+ return;
-static void
-emft_model_unread_count_changed (GtkTreeModel *model, GtkTreeIter *iter)
-{
- GtkTreeIter parent_iter;
- GtkTreeIter child_iter = *iter;
+ em_folder_tree_model_remove_store (model, si->store);
- g_signal_handlers_block_by_func (
- model, emft_model_unread_count_changed, NULL);
+ /* check if store needs to be added at all*/
+ if (!account->enabled ||!(uri = account->source->url))
+ return;
- /* Folders are displayed with a bold weight to indicate that
- they contain unread messages. We signal that parent rows
- have changed here to update them. */
+ camel_exception_init (&ex);
+ if (!(provider = camel_provider_get(uri, &ex))) {
+ camel_exception_clear (&ex);
+ return;
+ }
- while (gtk_tree_model_iter_parent (model, &parent_iter, &child_iter)) {
- GtkTreePath *parent_path;
+ /* make sure the new store belongs in the tree */
+ if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+ return;
- parent_path = gtk_tree_model_get_path (model, &parent_iter);
- gtk_tree_model_row_changed (model, parent_path, &parent_iter);
- gtk_tree_path_free (parent_path);
- child_iter = parent_iter;
+ if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
+ camel_exception_clear (&ex);
+ return;
}
- g_signal_handlers_unblock_by_func (
- model, emft_model_unread_count_changed, NULL);
+ em_folder_tree_model_add_store (model, store, account->name);
+ camel_object_unref (store);
}
static void
-em_folder_tree_model_init (EMFolderTreeModel *model)
+account_removed_cb (EAccountList *accounts,
+ EAccount *account,
+ EMFolderTreeModel *model)
{
- model->store_hash = g_hash_table_new_full (
- g_direct_hash, g_direct_equal,
- (GDestroyNotify) NULL,
- (GDestroyNotify) store_info_free);
+ EMFolderTreeModelStoreInfo *si;
- model->uri_hash = g_hash_table_new_full (
- g_str_hash, g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) gtk_tree_row_reference_free);
-
- gtk_tree_sortable_set_default_sort_func ((GtkTreeSortable *) model, sort_cb, NULL, NULL);
+ si = g_hash_table_lookup (model->priv->account_index, account);
+ if (si == NULL)
+ return;
- model->accounts = mail_config_get_accounts ();
- model->account_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
- model->account_changed_id = g_signal_connect (model->accounts, "account-changed", G_CALLBACK (account_changed), model);
- model->account_removed_id = g_signal_connect (model->accounts, "account-removed", G_CALLBACK (account_removed), model);
- /* g_signal_connect (model, "row-changed", G_CALLBACK (emft_model_unread_count_changed), NULL); */
+ em_folder_tree_model_remove_store (model, si->store);
}
static void
-em_folder_tree_model_finalize (GObject *obj)
+folder_tree_model_selection_finalized_cb (EMFolderTreeModel *model)
{
- EMFolderTreeModel *model = (EMFolderTreeModel *) obj;
+ model->priv->selection = NULL;
- g_free (model->filename);
- if (model->state)
- xmlFreeDoc (model->state);
-
- g_hash_table_destroy (model->store_hash);
- g_hash_table_destroy (model->uri_hash);
+ g_object_notify (G_OBJECT (model), "selection");
+}
- g_hash_table_destroy (model->account_hash);
- g_signal_handler_disconnect (model->accounts, model->account_changed_id);
- g_signal_handler_disconnect (model->accounts, model->account_removed_id);
+static void
+folder_tree_model_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTION:
+ em_folder_tree_model_set_selection (
+ EM_FOLDER_TREE_MODEL (object),
+ g_value_get_object (value));
+ return;
+ }
- G_OBJECT_CLASS (parent_class)->finalize (obj);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
-tree_model_iface_init (GtkTreeModelIface *iface)
+folder_tree_model_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- ;
+ switch (property_id) {
+ case PROP_SELECTION:
+ g_value_set_object (
+ value,
+ em_folder_tree_model_get_selection (
+ EM_FOLDER_TREE_MODEL (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
-tree_sortable_iface_init (GtkTreeSortableIface *iface)
+folder_tree_model_dispose (GObject *object)
{
- ;
+ EMFolderTreeModelPrivate *priv;
+
+ priv = EM_FOLDER_TREE_MODEL_GET_PRIVATE (object);
+
+ if (priv->selection != NULL) {
+ g_object_weak_unref (
+ G_OBJECT (priv->selection), (GWeakNotify)
+ folder_tree_model_selection_finalized_cb, object);
+ priv->selection = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
-em_folder_tree_model_load_state (EMFolderTreeModel *model, const gchar *filename)
+folder_tree_model_finalize (GObject *object)
{
- xmlNodePtr root, node;
+ EMFolderTreeModelPrivate *priv;
- if (model->state)
- xmlFreeDoc (model->state);
+ priv = EM_FOLDER_TREE_MODEL_GET_PRIVATE (object);
- if ((model->state = e_xml_parse_file (filename)) != NULL) {
- node = xmlDocGetRootElement (model->state);
- if (!node || strcmp ((gchar *)node->name, "tree-state") != 0) {
- /* it is not expected XML file, thus free it and use the default */
- xmlFreeDoc (model->state);
- } else
- return;
- }
+ g_hash_table_destroy (priv->account_index);
+ g_hash_table_destroy (priv->store_index);
+ g_hash_table_destroy (priv->uri_index);
- /* setup some defaults - expand "Local Folders" and "Search Folders" */
- model->state = xmlNewDoc ((const guchar *)"1.0");
- root = xmlNewDocNode (model->state, NULL, (const guchar *)"tree-state", NULL);
- xmlDocSetRootElement (model->state, root);
+ g_signal_handler_disconnect (
+ priv->accounts, priv->account_changed_id);
+ g_signal_handler_disconnect (
+ priv->accounts, priv->account_removed_id);
- node = xmlNewChild (root, NULL, (const guchar *)"node", NULL);
- xmlSetProp (node, (const guchar *)"name", (const guchar *)"local");
- xmlSetProp (node, (const guchar *)"expand", (const guchar *)"true");
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
- node = xmlNewChild (root, NULL, (const guchar *)"node", NULL);
- xmlSetProp (node, (const guchar *)"name", (const guchar *)"vfolder");
- xmlSetProp (node, (const guchar *)"expand", (const guchar *)"true");
+static void
+folder_tree_model_class_init (EMFolderTreeModelClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMFolderTreeModelPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = folder_tree_model_set_property;
+ object_class->get_property = folder_tree_model_get_property;
+ object_class->dispose = folder_tree_model_dispose;
+ object_class->finalize = folder_tree_model_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTION,
+ g_param_spec_object (
+ "selection",
+ "Selection",
+ NULL,
+ GTK_TYPE_TREE_SELECTION,
+ G_PARAM_READWRITE));
+
+ signals[LOADING_ROW] = g_signal_new (
+ "loading-row",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMFolderTreeModelClass, loading_row),
+ NULL, NULL,
+ e_marshal_VOID__POINTER_POINTER,
+ G_TYPE_NONE, 2,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+
+ signals[LOADED_ROW] = g_signal_new (
+ "loaded-row",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMFolderTreeModelClass, loaded_row),
+ NULL, NULL,
+ e_marshal_VOID__POINTER_POINTER,
+ G_TYPE_NONE, 2,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+
+ signals[FOLDER_ADDED] = g_signal_new (
+ "folder-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMFolderTreeModelClass, folder_added),
+ NULL, NULL,
+ e_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
}
-EMFolderTreeModel *
-em_folder_tree_model_new (const gchar *evolution_dir)
+static void
+folder_tree_model_init (EMFolderTreeModel *model)
{
- EMFolderTreeModel *model;
- gchar *filename;
+ GHashTable *store_index;
+ GHashTable *uri_index;
GType col_types[] = {
G_TYPE_STRING, /* display name */
@@ -371,80 +391,134 @@ em_folder_tree_model_new (const gchar *evolution_dir)
G_TYPE_UINT /* last known unread count */
};
- model = g_object_new (EM_TYPE_FOLDER_TREE_MODEL, NULL);
- gtk_tree_store_set_column_types ((GtkTreeStore *) model, NUM_COLUMNS, col_types);
- gtk_tree_sortable_set_sort_column_id ((GtkTreeSortable *) model,
- GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
- GTK_SORT_ASCENDING);
+ store_index = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) store_info_free);
- filename = g_build_filename (evolution_dir, "mail", "config", "folder-tree-expand-state.xml", NULL);
- em_folder_tree_model_load_state (model, filename);
- model->filename = filename;
+ uri_index = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gtk_tree_row_reference_free);
- return model;
+ model->priv = EM_FOLDER_TREE_MODEL_GET_PRIVATE (model);
+ model->priv->store_index = store_index;
+ model->priv->uri_index = uri_index;
+
+ gtk_tree_store_set_column_types (
+ GTK_TREE_STORE (model), NUM_COLUMNS, col_types);
+ gtk_tree_sortable_set_default_sort_func (
+ GTK_TREE_SORTABLE (model),
+ folder_tree_model_sort, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ model->priv->accounts = e_get_account_list ();
+ model->priv->account_index =
+ g_hash_table_new (g_direct_hash, g_direct_equal);
+ model->priv->account_changed_id = g_signal_connect (
+ model->priv->accounts, "account-changed",
+ G_CALLBACK (account_changed_cb), model);
+ model->priv->account_removed_id = g_signal_connect (
+ model->priv->accounts, "account-removed",
+ G_CALLBACK (account_removed_cb), model);
}
-static void
-account_changed (EAccountList *accounts, EAccount *account, gpointer user_data)
+GType
+em_folder_tree_model_get_type (void)
{
- EMFolderTreeModel *model = user_data;
- struct _EMFolderTreeModelStoreInfo *si;
- CamelProvider *provider;
- CamelStore *store;
- CamelException ex;
- gchar *uri;
+ static GType type = 0;
- if (!(si = g_hash_table_lookup (model->account_hash, account)))
- return;
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMFolderTreeModelClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) folder_tree_model_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMFolderTreeModel),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) folder_tree_model_init,
+ NULL /* value_table */
+ };
- em_folder_tree_model_remove_store (model, si->store);
+ type = g_type_register_static (
+ GTK_TYPE_TREE_STORE, "EMFolderTreeModel",
+ &type_info, 0);
+ }
- /* check if store needs to be added at all*/
- if (!account->enabled ||!(uri = account->source->url))
- return;
+ return type;
+}
- camel_exception_init (&ex);
- if (!(provider = camel_provider_get(uri, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
+EMFolderTreeModel *
+em_folder_tree_model_new (void)
+{
+ return g_object_new (EM_TYPE_FOLDER_TREE_MODEL, NULL);
+}
- /* make sure the new store belongs in the tree */
- if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
- return;
+EMFolderTreeModel *
+em_folder_tree_model_get_default (void)
+{
+ static EMFolderTreeModel *default_folder_tree_model;
- if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
+ if (G_UNLIKELY (default_folder_tree_model == NULL))
+ default_folder_tree_model = em_folder_tree_model_new ();
- em_folder_tree_model_add_store (model, store, account->name);
- camel_object_unref (store);
+ return default_folder_tree_model;
}
-static void
-account_removed (EAccountList *accounts, EAccount *account, gpointer user_data)
+GtkTreeSelection *
+em_folder_tree_model_get_selection (EMFolderTreeModel *model)
+{
+ g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL);
+
+ return GTK_TREE_SELECTION (model->priv->selection);
+}
+
+void
+em_folder_tree_model_set_selection (EMFolderTreeModel *model,
+ GtkTreeSelection *selection)
{
- EMFolderTreeModel *model = user_data;
- struct _EMFolderTreeModelStoreInfo *si;
+ g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
- if (!(si = g_hash_table_lookup (model->account_hash, account)))
- return;
+ if (selection != NULL)
+ g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
- em_folder_tree_model_remove_store (model, si->store);
+ if (model->priv->selection != NULL) {
+ g_object_weak_unref (
+ G_OBJECT (model->priv->selection), (GWeakNotify)
+ folder_tree_model_selection_finalized_cb, model);
+ model->priv->selection = NULL;
+ }
+
+ model->priv->selection = selection;
+
+ if (model->priv->selection != NULL)
+ g_object_weak_ref (
+ G_OBJECT (model->priv->selection), (GWeakNotify)
+ folder_tree_model_selection_finalized_cb, model);
+
+ g_object_notify (G_OBJECT (model), "selection");
}
void
-em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *iter,
- struct _EMFolderTreeModelStoreInfo *si,
- CamelFolderInfo *fi, gint fully_loaded)
+em_folder_tree_model_set_folder_info (EMFolderTreeModel *model,
+ GtkTreeIter *iter,
+ EMFolderTreeModelStoreInfo *si,
+ CamelFolderInfo *fi,
+ gint fully_loaded)
{
GtkTreeRowReference *uri_row, *path_row;
GtkTreeStore *tree_store;
guint unread;
GtkTreePath *path;
GtkTreeIter sub;
- gboolean load = FALSE, is_drafts = FALSE, is_templates = FALSE;
+ gboolean load = FALSE;
+ gboolean is_drafts = FALSE;
+ gboolean is_templates = FALSE;
CamelFolder *folder;
gboolean emitted = FALSE;
const gchar *name;
@@ -461,20 +535,28 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
if (!fully_loaded)
load = fi->child == NULL && !(fi->flags & (CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_NOINFERIORS));
- path = gtk_tree_model_get_path ((GtkTreeModel *) model, iter);
- uri_row = gtk_tree_row_reference_new ((GtkTreeModel *) model, path);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
+ uri_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
path_row = gtk_tree_row_reference_copy (uri_row);
gtk_tree_path_free (path);
- g_hash_table_insert (model->uri_hash, g_strdup (fi->uri), uri_row);
- g_hash_table_insert (si->full_hash, g_strdup (fi->full_name), path_row);
+ g_hash_table_insert (
+ model->priv->uri_index, g_strdup (fi->uri), uri_row);
+ g_hash_table_insert (
+ si->full_hash, g_strdup (fi->full_name), path_row);
/* HACK: if we have the folder, and its the outbox folder, we need the total count, not unread */
/* HACK2: We do the same to the draft folder */
/* This is duplicated in mail-folder-cache too, should perhaps be functionised */
unread = fi->unread;
if (mail_note_get_folder_from_uri(fi->uri, &folder) && folder) {
- if (folder == mail_component_get_folder(NULL, MAIL_COMPONENT_FOLDER_OUTBOX)) {
+ CamelFolder *local_drafts;
+ CamelFolder *local_outbox;
+
+ local_drafts = e_mail_local_get_folder (E_MAIL_FOLDER_DRAFTS);
+ local_outbox = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
+
+ if (folder == local_outbox) {
gint total;
if ((total = camel_folder_get_message_count (folder)) > 0) {
@@ -486,7 +568,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
unread = total > 0 ? total : 0;
}
- if (folder == mail_component_get_folder(NULL, MAIL_COMPONENT_FOLDER_DRAFTS)) {
+ if (folder == local_drafts) {
gint total;
if ((total = camel_folder_get_message_count (folder)) > 0) {
@@ -505,7 +587,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
/* TODO: maybe this should be handled by mail_get_folderinfo (except em-folder-tree doesn't use it, duh) */
flags = fi->flags;
name = fi->name;
- if (si->store == mail_component_peek_local_store(NULL)) {
+ if (si->store == e_mail_local_get_store ()) {
if (!strcmp(fi->full_name, "Drafts")) {
name = _("Drafts");
is_drafts = TRUE;
@@ -589,7 +671,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
COL_UINT_UNREAD_LAST_SEL, 0,
-1);
- path = gtk_tree_model_get_path ((GtkTreeModel *) model, iter);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
g_signal_emit (model, signals[LOADING_ROW], 0, path, iter);
gtk_tree_path_free (path);
return;
@@ -602,7 +684,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
gtk_tree_store_append (tree_store, &sub, iter);
if (!emitted) {
- path = gtk_tree_model_get_path ((GtkTreeModel *) model, iter);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
g_signal_emit (model, signals[LOADED_ROW], 0, path, iter);
gtk_tree_path_free (path);
emitted = TRUE;
@@ -614,23 +696,26 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite
}
if (!emitted) {
- path = gtk_tree_model_get_path ((GtkTreeModel *) model, iter);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
g_signal_emit (model, signals[LOADED_ROW], 0, path, iter);
gtk_tree_path_free (path);
}
}
static void
-folder_subscribed (CamelStore *store, CamelFolderInfo *fi, EMFolderTreeModel *model)
+folder_subscribed (CamelStore *store,
+ CamelFolderInfo *fi,
+ EMFolderTreeModel *model)
{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
GtkTreeIter parent, iter;
GtkTreePath *path;
gboolean load;
gchar *dirname, *p;
- if (!(si = g_hash_table_lookup (model->store_hash, store)))
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
goto done;
/* make sure we don't already know about it? */
@@ -643,140 +728,159 @@ folder_subscribed (CamelStore *store, CamelFolderInfo *fi, EMFolderTreeModel *mo
p = strrchr(dirname, '/');
if (p == NULL) {
/* user subscribed to a toplevel folder */
- row = si->row;
+ reference = si->row;
} else {
*p = 0;
- row = g_hash_table_lookup (si->full_hash, dirname);
-
- /* if row is NULL, don't bother adding to the tree,
- * when the user expands enough nodes - it will be
- * added auto-magically */
- if (row == NULL)
- goto done;
+ reference = g_hash_table_lookup (si->full_hash, dirname);
}
- path = gtk_tree_row_reference_get_path (row);
- if (!(gtk_tree_model_get_iter ((GtkTreeModel *) model, &parent, path))) {
- gtk_tree_path_free (path);
+ if (!gtk_tree_row_reference_valid (reference))
goto done;
- }
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &parent, path);
gtk_tree_path_free (path);
/* make sure parent's subfolders have already been loaded */
- gtk_tree_model_get ((GtkTreeModel *) model, &parent, COL_BOOL_LOAD_SUBDIRS, &load, -1);
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (model), &parent,
+ COL_BOOL_LOAD_SUBDIRS, &load, -1);
if (load)
goto done;
/* append a new node */
- gtk_tree_store_append ((GtkTreeStore *) model, &iter, &parent);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent);
em_folder_tree_model_set_folder_info (model, &iter, si, fi, TRUE);
g_signal_emit (model, signals[FOLDER_ADDED], 0, fi->full_name, fi->uri);
- done:
-
+done:
camel_object_unref (store);
camel_folder_info_free (fi);
}
static void
-folder_subscribed_cb (CamelStore *store, gpointer event_data, EMFolderTreeModel *model)
+folder_subscribed_cb (CamelStore *store,
+ gpointer event_data,
+ EMFolderTreeModel *model)
{
CamelFolderInfo *fi;
camel_object_ref (store);
fi = camel_folder_info_clone (event_data);
- mail_async_event_emit (mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc) folder_subscribed, store, fi, model);
+
+ mail_async_event_emit (
+ mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)
+ folder_subscribed, store, fi, model);
}
static void
-folder_unsubscribed (CamelStore *store, CamelFolderInfo *fi, EMFolderTreeModel *model)
+folder_unsubscribed (CamelStore *store,
+ CamelFolderInfo *fi,
+ EMFolderTreeModel *model)
{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
GtkTreePath *path;
GtkTreeIter iter;
- if (!(si = g_hash_table_lookup (model->store_hash, store)))
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
goto done;
- if (!(row = g_hash_table_lookup (si->full_hash, fi->full_name)))
+ reference = g_hash_table_lookup (si->full_hash, fi->full_name);
+ if (!gtk_tree_row_reference_valid (reference))
goto done;
- path = gtk_tree_row_reference_get_path (row);
- if (!(gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path))) {
- gtk_tree_path_free (path);
- goto done;
- }
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ gtk_tree_path_free (path);
em_folder_tree_model_remove_folders (model, si, &iter);
- done:
-
+done:
camel_object_unref (store);
camel_folder_info_free (fi);
}
static void
-folder_unsubscribed_cb (CamelStore *store, gpointer event_data, EMFolderTreeModel *model)
+folder_unsubscribed_cb (CamelStore *store,
+ gpointer event_data,
+ EMFolderTreeModel *model)
{
CamelFolderInfo *fi;
camel_object_ref (store);
fi = camel_folder_info_clone (event_data);
- mail_async_event_emit (mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc) folder_unsubscribed, store, fi, model);
+
+ mail_async_event_emit (
+ mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)
+ folder_unsubscribed, store, fi, model);
}
static void
-folder_created_cb (CamelStore *store, gpointer event_data, EMFolderTreeModel *model)
+folder_created_cb (CamelStore *store,
+ gpointer event_data,
+ EMFolderTreeModel *model)
{
CamelFolderInfo *fi;
- /* we only want created events to do more work if we don't support subscriptions */
+ /* We only want created events to do more
+ * work if we don't support subscriptions. */
if (camel_store_supports_subscriptions (store))
return;
camel_object_ref (store);
fi = camel_folder_info_clone (event_data);
- mail_async_event_emit (mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc) folder_subscribed, store, fi, model);
+
+ mail_async_event_emit (
+ mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)
+ folder_subscribed, store, fi, model);
}
static void
-folder_deleted_cb (CamelStore *store, gpointer event_data, EMFolderTreeModel *model)
+folder_deleted_cb (CamelStore *store,
+ gpointer event_data,
+ EMFolderTreeModel *model)
{
CamelFolderInfo *fi;
- /* we only want deleted events to do more work if we don't support subscriptions */
+ /* We only want deleted events to do more
+ * work if we don't support subscriptions. */
if (camel_store_supports_subscriptions (store))
return;
camel_object_ref (store);
fi = camel_folder_info_clone (event_data);
- mail_async_event_emit (mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc) folder_unsubscribed_cb, store, fi, model);
+
+ mail_async_event_emit (
+ mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)
+ folder_unsubscribed_cb, store, fi, model);
}
static void
-folder_renamed (CamelStore *store, CamelRenameInfo *info, EMFolderTreeModel *model)
+folder_renamed (CamelStore *store,
+ CamelRenameInfo *info,
+ EMFolderTreeModel *model)
{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
GtkTreeIter root, iter;
GtkTreePath *path;
gchar *parent, *p;
- if (!(si = g_hash_table_lookup (model->store_hash, store)))
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
goto done;
- if (!(row = g_hash_table_lookup (si->full_hash, info->old_base)))
+ reference = g_hash_table_lookup (si->full_hash, info->old_base);
+ if (!gtk_tree_row_reference_valid (reference))
goto done;
- path = gtk_tree_row_reference_get_path (row);
- if (!(gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path))) {
- gtk_tree_path_free (path);
- goto done;
- }
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ gtk_tree_path_free (path);
em_folder_tree_model_remove_folders (model, si, &iter);
@@ -784,36 +888,25 @@ folder_renamed (CamelStore *store, CamelRenameInfo *info, EMFolderTreeModel *mod
p = strrchr(parent, '/');
if (p)
*p = 0;
- if (p == NULL || parent == p) {
+ if (p == NULL || parent == p)
/* renamed to a toplevel folder on the store */
- path = gtk_tree_row_reference_get_path (si->row);
- } else {
- if (!(row = g_hash_table_lookup (si->full_hash, parent))) {
- /* NOTE: this should never happen, but I
- * suppose if it does in reality, we can add
- * code here to add the missing nodes to the
- * tree */
- g_warning ("This shouldn't be reached\n");
- g_free (parent);
- goto done;
- }
-
- path = gtk_tree_row_reference_get_path (row);
- }
+ reference = si->row;
+ else
+ reference = g_hash_table_lookup (si->full_hash, parent);
g_free (parent);
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &root, path)) {
- gtk_tree_path_free (path);
- g_warning ("This shouldn't be reached\n");
+ if (!gtk_tree_row_reference_valid (reference))
goto done;
- }
- gtk_tree_store_append ((GtkTreeStore *) model, &iter, &root);
- em_folder_tree_model_set_folder_info (model, &iter, si, info->new, TRUE);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &root, path);
+ gtk_tree_path_free (path);
- done:
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &root);
+ em_folder_tree_model_set_folder_info (model, &iter, si, info->new, TRUE);
+done:
camel_object_unref (store);
g_free (info->old_base);
@@ -822,7 +915,9 @@ folder_renamed (CamelStore *store, CamelRenameInfo *info, EMFolderTreeModel *mod
}
static void
-folder_renamed_cb (CamelStore *store, gpointer event_data, EMFolderTreeModel *model)
+folder_renamed_cb (CamelStore *store,
+ gpointer event_data,
+ EMFolderTreeModel *model)
{
CamelRenameInfo *rinfo, *info = event_data;
@@ -832,14 +927,19 @@ folder_renamed_cb (CamelStore *store, gpointer event_data, EMFolderTreeModel *mo
rinfo->old_base = g_strdup (info->old_base);
rinfo->new = camel_folder_info_clone (info->new);
- mail_async_event_emit (mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc) folder_renamed, store, rinfo, model);
+ mail_async_event_emit (
+ mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)
+ folder_renamed, store, rinfo, model);
}
void
-em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store, const gchar *display_name)
+em_folder_tree_model_add_store (EMFolderTreeModel *model,
+ CamelStore *store,
+ const gchar *display_name)
{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
+ GtkTreeStore *tree_store;
GtkTreeIter root, iter;
GtkTreePath *path;
EAccount *account;
@@ -849,62 +949,77 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store, con
g_return_if_fail (CAMEL_IS_STORE (store));
g_return_if_fail (display_name != NULL);
- if ((si = g_hash_table_lookup (model->store_hash, store)))
+ tree_store = GTK_TREE_STORE (model);
+
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si != NULL)
em_folder_tree_model_remove_store (model, store);
- uri = camel_url_to_string (((CamelService *) store)->url, CAMEL_URL_HIDE_ALL);
+ uri = camel_url_to_string (
+ ((CamelService *) store)->url, CAMEL_URL_HIDE_ALL);
account = mail_config_get_account_by_source_url (uri);
/* add the store to the tree */
- gtk_tree_store_append ((GtkTreeStore *) model, &iter, NULL);
- gtk_tree_store_set ((GtkTreeStore *) model, &iter,
- COL_STRING_DISPLAY_NAME, display_name,
- COL_POINTER_CAMEL_STORE, store,
- COL_STRING_FULL_NAME, NULL,
- COL_BOOL_LOAD_SUBDIRS, TRUE,
- COL_BOOL_IS_STORE, TRUE,
- COL_STRING_URI, uri, -1);
-
- path = gtk_tree_model_get_path ((GtkTreeModel *) model, &iter);
- row = gtk_tree_row_reference_new ((GtkTreeModel *) model, path);
-
- si = g_new (struct _EMFolderTreeModelStoreInfo, 1);
+ gtk_tree_store_append (tree_store, &iter, NULL);
+ gtk_tree_store_set (
+ tree_store, &iter,
+ COL_STRING_DISPLAY_NAME, display_name,
+ COL_POINTER_CAMEL_STORE, store,
+ COL_STRING_FULL_NAME, NULL,
+ COL_BOOL_LOAD_SUBDIRS, TRUE,
+ COL_BOOL_IS_STORE, TRUE,
+ COL_STRING_URI, uri, -1);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+ reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
+
+ si = g_new (EMFolderTreeModelStoreInfo, 1);
si->display_name = g_strdup (display_name);
camel_object_ref (store);
si->store = store;
si->account = account;
- si->row = row;
+ si->row = gtk_tree_row_reference_copy (reference);
si->full_hash = g_hash_table_new_full (
g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) gtk_tree_row_reference_free);
- g_hash_table_insert (model->store_hash, store, si);
- g_hash_table_insert (model->account_hash, account, si);
+ g_hash_table_insert (model->priv->store_index, store, si);
+ g_hash_table_insert (model->priv->account_index, account, si);
+
+ /* Transfer ownership of the URI and GtkTreeRowReference. */
+ g_hash_table_insert (model->priv->uri_index, uri, reference);
/* each store has folders... but we don't load them until the user demands them */
root = iter;
- gtk_tree_store_append ((GtkTreeStore *) model, &iter, &root);
- gtk_tree_store_set ((GtkTreeStore *) model, &iter,
- COL_STRING_DISPLAY_NAME, _("Loading..."),
- COL_POINTER_CAMEL_STORE, NULL,
- COL_STRING_FULL_NAME, NULL,
- COL_BOOL_LOAD_SUBDIRS, FALSE,
- COL_BOOL_IS_STORE, FALSE,
- COL_STRING_URI, NULL,
- COL_UINT_UNREAD, 0,
- COL_UINT_UNREAD_LAST_SEL, 0,
- -1);
-
- g_free (uri);
+ gtk_tree_store_append (tree_store, &iter, &root);
+ gtk_tree_store_set (
+ tree_store, &iter,
+ COL_STRING_DISPLAY_NAME, _("Loading..."),
+ COL_POINTER_CAMEL_STORE, NULL,
+ COL_STRING_FULL_NAME, NULL,
+ COL_BOOL_LOAD_SUBDIRS, FALSE,
+ COL_BOOL_IS_STORE, FALSE,
+ COL_STRING_URI, NULL,
+ COL_UINT_UNREAD, 0,
+ COL_UINT_UNREAD_LAST_SEL, 0, -1);
/* listen to store events */
-#define CAMEL_CALLBACK(func) ((CamelObjectEventHookFunc) func)
- si->created_id = camel_object_hook_event (store, "folder_created", CAMEL_CALLBACK (folder_created_cb), model);
- si->deleted_id = camel_object_hook_event (store, "folder_deleted", CAMEL_CALLBACK (folder_deleted_cb), model);
- si->renamed_id = camel_object_hook_event (store, "folder_renamed", CAMEL_CALLBACK (folder_renamed_cb), model);
- si->subscribed_id = camel_object_hook_event (store, "folder_subscribed", CAMEL_CALLBACK (folder_subscribed_cb), model);
- si->unsubscribed_id = camel_object_hook_event (store, "folder_unsubscribed", CAMEL_CALLBACK (folder_unsubscribed_cb), model);
+ si->created_id = camel_object_hook_event (
+ store, "folder_created",
+ (CamelObjectEventHookFunc) folder_created_cb, model);
+ si->deleted_id = camel_object_hook_event (
+ store, "folder_deleted",
+ (CamelObjectEventHookFunc) folder_deleted_cb, model);
+ si->renamed_id = camel_object_hook_event (
+ store, "folder_renamed",
+ (CamelObjectEventHookFunc) folder_renamed_cb, model);
+ si->subscribed_id = camel_object_hook_event (
+ store, "folder_subscribed",
+ (CamelObjectEventHookFunc) folder_subscribed_cb, model);
+ si->unsubscribed_id = camel_object_hook_event (
+ store, "folder_unsubscribed",
+ (CamelObjectEventHookFunc) folder_unsubscribed_cb, model);
g_signal_emit (model, signals[LOADED_ROW], 0, path, &root);
gtk_tree_path_free (path);
@@ -916,50 +1031,55 @@ em_folder_tree_model_remove_uri (EMFolderTreeModel *model, const gchar *uri)
g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
g_return_if_fail (uri != NULL);
- g_hash_table_remove (model->uri_hash, uri);
+ g_hash_table_remove (model->priv->uri_index, uri);
}
static void
-em_folder_tree_model_remove_store_info (EMFolderTreeModel *model, CamelStore *store)
+em_folder_tree_model_remove_store_info (EMFolderTreeModel *model,
+ CamelStore *store)
{
- struct _EMFolderTreeModelStoreInfo *si;
+ EMFolderTreeModelStoreInfo *si;
g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
g_return_if_fail (CAMEL_IS_STORE (store));
- if (!(si = g_hash_table_lookup (model->store_hash, store)))
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
return;
- g_hash_table_remove (model->account_hash, si->account);
- /* store_hash owns and frees the si structure, thus free it after done with it */
- g_hash_table_remove (model->store_hash, si->store);
+ g_hash_table_remove (model->priv->account_index, si->account);
+ g_hash_table_remove (model->priv->store_index, si->store);
}
void
-em_folder_tree_model_remove_folders (EMFolderTreeModel *model, struct _EMFolderTreeModelStoreInfo *si, GtkTreeIter *toplevel)
+em_folder_tree_model_remove_folders (EMFolderTreeModel *model,
+ EMFolderTreeModelStoreInfo *si,
+ GtkTreeIter *toplevel)
{
gchar *uri, *full_name;
gboolean is_store, go;
GtkTreeIter iter;
- if (gtk_tree_model_iter_children ((GtkTreeModel *) model, &iter, toplevel)) {
+ if (gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, toplevel)) {
do {
GtkTreeIter next = iter;
- go = gtk_tree_model_iter_next ((GtkTreeModel *) model, &next);
+ go = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &next);
em_folder_tree_model_remove_folders (model, si, &iter);
iter = next;
} while (go);
}
- gtk_tree_model_get ((GtkTreeModel *) model, toplevel, COL_STRING_URI, &uri,
- COL_STRING_FULL_NAME, &full_name,
- COL_BOOL_IS_STORE, &is_store, -1);
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (model), toplevel,
+ COL_STRING_URI, &uri,
+ COL_STRING_FULL_NAME, &full_name,
+ COL_BOOL_IS_STORE, &is_store, -1);
- if (full_name)
+ if (full_name != NULL)
g_hash_table_remove (si->full_hash, full_name);
- if (uri)
+ if (uri != NULL)
em_folder_tree_model_remove_uri (model, uri);
gtk_tree_store_remove ((GtkTreeStore *) model, toplevel);
@@ -972,298 +1092,36 @@ em_folder_tree_model_remove_folders (EMFolderTreeModel *model, struct _EMFolderT
}
void
-em_folder_tree_model_remove_store (EMFolderTreeModel *model, CamelStore *store)
+em_folder_tree_model_remove_store (EMFolderTreeModel *model,
+ CamelStore *store)
{
- struct _EMFolderTreeModelStoreInfo *si;
+ EMFolderTreeModelStoreInfo *si;
GtkTreePath *path;
GtkTreeIter iter;
g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
g_return_if_fail (CAMEL_IS_STORE (store));
- if (!(si = g_hash_table_lookup (model->store_hash, store)))
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
return;
path = gtk_tree_row_reference_get_path (si->row);
- gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
gtk_tree_path_free (path);
/* recursively remove subfolders and finally the toplevel store */
em_folder_tree_model_remove_folders (model, si, &iter);
}
-static xmlNodePtr
-find_xml_node (xmlNodePtr root, const gchar *name)
-{
- xmlNodePtr node;
- gchar *nname;
-
- node = root->children;
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "node")) {
- nname = (gchar *)xmlGetProp (node, (const guchar *)"name");
- if (nname && !strcmp (nname, name)) {
- xmlFree (nname);
- return node;
- }
-
- xmlFree (nname);
- }
-
- node = node->next;
- }
-
- return node;
-}
-
-gboolean
-em_folder_tree_model_get_expanded (EMFolderTreeModel *model, const gchar *key)
-{
- xmlNodePtr node;
- const gchar *name;
- gchar *buf, *p;
-
- /* This code needs to be rewritten.
- First it doesn't belong on the model
- Second, it shouldn't use an xml tree to store a bit table in memory! */
-
- node = model->state ? model->state->children : NULL;
- if (!node || strcmp ((gchar *)node->name, "tree-state") != 0)
- return FALSE;
-
- name = buf = g_alloca (strlen (key) + 1);
- p = g_stpcpy (buf, key);
- if (p[-1] == '/')
- p[-1] = '\0';
- p = NULL;
-
- do {
- if ((p = strchr (name, '/')))
- *p = '\0';
-
- if ((node = find_xml_node (node, name))) {
- gboolean expanded;
-
- buf = (gchar *)xmlGetProp (node, (const guchar *)"expand");
- expanded = buf && !strcmp ((gchar *)buf, "true");
- xmlFree (buf);
-
- if (!expanded || p == NULL)
- return expanded;
- }
-
- name = p ? p + 1 : NULL;
- } while (name && node);
-
- return FALSE;
-}
-
-void
-em_folder_tree_model_set_expanded (EMFolderTreeModel *model, const gchar *key, gboolean expanded)
-{
- xmlNodePtr node, parent;
- const gchar *name;
- gchar *buf, *p;
-
- if (model->state == NULL)
- model->state = xmlNewDoc ((const guchar *)"1.0");
-
- if (!model->state->children) {
- node = xmlNewDocNode (model->state, NULL, (const guchar *)"tree-state", NULL);
- xmlDocSetRootElement (model->state, node);
- } else {
- node = model->state->children;
- }
-
- name = buf = g_alloca (strlen (key) + 1);
- p = g_stpcpy (buf, key);
- if (p[-1] == '/')
- p[-1] = '\0';
- p = NULL;
-
- do {
- parent = node;
- if ((p = strchr (name, '/')))
- *p = '\0';
-
- if (!(node = find_xml_node (node, name))) {
- if (!expanded) {
- /* node doesn't exist, so we don't need to set expanded to FALSE */
- return;
- }
-
- /* node (or parent node) doesn't exist, need to add it */
- node = xmlNewChild (parent, NULL, (const guchar *)"node", NULL);
- xmlSetProp (node, (const guchar *)"name", (guchar *)name);
- }
-
- xmlSetProp (node, (const guchar *)"expand", (const guchar *)(expanded || p ? "true" : "false"));
-
- name = p ? p + 1 : NULL;
- } while (name);
-}
-
-/**
- * emftm_uri_to_key
- * Converts uri to key used in functions like em_folder_tree_model_[s/g]et_expanded.
- * @param uri Uri to be converted.
- * @return Key of the uri or NULL, if failed. Returned value should be clear by g_free.
- **/
-static gchar *
-emftm_uri_to_key (const gchar *uri)
-{
- CamelException ex = { 0 };
- CamelStore *store;
- CamelURL *url;
- gchar *key;
-
- if (!uri)
- return NULL;
-
- store = (CamelStore *)camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex);
- camel_exception_clear(&ex);
-
- url = camel_url_new (uri, NULL);
-
- if (store == NULL || url == NULL) {
- key = NULL;
- } else {
- const gchar *path;
- EAccount *account;
-
- if (((CamelService *)store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
- path = url->fragment;
- else
- path = url->path && url->path[0]=='/' ? url->path+1:url->path;
-
- if (path == NULL)
- path = "";
-
- if ( (account = mail_config_get_account_by_source_url (uri)) )
- key = g_strdup_printf ("%s/%s", account->uid, path);
- else if (CAMEL_IS_VEE_STORE (store))
- key = g_strdup_printf ("vfolder/%s", path);
- else
- key = g_strdup_printf ("local/%s", path);
- }
-
- if (url)
- camel_url_free (url);
-
- if (store)
- camel_object_unref (store);
-
- return key;
-}
-
-/**
- * em_folder_tree_model_get_expanded_uri
- * Same as @ref em_folder_tree_model_get_expanded, but here we use uri, not key for node.
- **/
gboolean
-em_folder_tree_model_get_expanded_uri (EMFolderTreeModel *model, const gchar *uri)
+em_folder_tree_model_is_type_inbox (EMFolderTreeModel *model,
+ CamelStore *store,
+ const gchar *full)
{
- gchar *key;
- gboolean expanded;
-
- g_return_val_if_fail (model != NULL, FALSE);
- g_return_val_if_fail (uri != NULL, FALSE);
-
- key = emftm_uri_to_key (uri);
- expanded = key && em_folder_tree_model_get_expanded (model, key);
-
- g_free (key);
-
- return expanded;
-}
-
-/**
- * em_folder_tree_model_set_expanded_uri
- * Same as @ref em_folder_tree_model_set_expanded, but here we use uri, not key for node.
- **/
-void
-em_folder_tree_model_set_expanded_uri (EMFolderTreeModel *model, const gchar *uri, gboolean expanded)
-{
- gchar *key;
-
- g_return_if_fail (model != NULL);
- g_return_if_fail (uri != NULL);
-
- key = emftm_uri_to_key (uri);
- if (key)
- em_folder_tree_model_set_expanded (model, key, expanded);
-
- g_free (key);
-}
-
-void
-em_folder_tree_model_save_state (EMFolderTreeModel *model)
-{
- gchar *dirname;
-
- if (model->state == NULL)
- return;
-
- dirname = g_path_get_dirname (model->filename);
- if (g_mkdir_with_parents (dirname, 0777) == -1 && errno != EEXIST) {
- g_free (dirname);
- return;
- }
-
- g_free (dirname);
-
- e_xml_save_file (model->filename, model->state);
-}
-
-static void
-expand_foreach_r (EMFolderTreeModel *model, xmlNodePtr parent, const gchar *dirname, EMFTModelExpandFunc func, gpointer user_data)
-{
- xmlNodePtr node = parent->children;
- gchar *path, *name, *expand;
-
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "node")) {
- name = (gchar *)xmlGetProp (node, (const guchar *)"name");
- expand = (gchar *)xmlGetProp (node, (const guchar *)"expand");
-
- if (expand && name && !strcmp ((gchar *)expand, "true")) {
- if (dirname)
- path = g_strdup_printf ("%s/%s", dirname, name);
- else
- path = g_strdup (name);
-
- func (model, path, user_data);
- if (node->children)
- expand_foreach_r (model, node, path, func, user_data);
- g_free (path);
- }
-
- xmlFree (expand);
- xmlFree (name);
- }
-
- node = node->next;
- }
-}
-
-void
-em_folder_tree_model_expand_foreach (EMFolderTreeModel *model, EMFTModelExpandFunc func, gpointer user_data)
-{
- xmlNodePtr root;
-
- root = model->state ? model->state->children : NULL;
- if (!root || !root->children || strcmp ((gchar *)root->name, "tree-state") != 0)
- return;
-
- expand_foreach_r (model, root, NULL, func, user_data);
-}
-
-gboolean
-em_folder_tree_model_is_type_inbox (EMFolderTreeModel *model, CamelStore *store, const gchar *full)
-{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
- GtkTreePath *tree_path;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
GtkTreeIter iter;
guint32 flags;
@@ -1271,40 +1129,33 @@ em_folder_tree_model_is_type_inbox (EMFolderTreeModel *model, CamelStore *store,
g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
g_return_val_if_fail (full != NULL, FALSE);
- u(printf("Checking if the folder is an INBOX type %p '%s' %d\n", store, full, unread));
-
- if (!(si = g_hash_table_lookup (model->store_hash, store))) {
- u(printf(" can't find store\n"));
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
return FALSE;
- }
- if (!(row = g_hash_table_lookup (si->full_hash, full))) {
- u(printf(" can't find row\n"));
+ reference = g_hash_table_lookup (si->full_hash, full);
+ if (!gtk_tree_row_reference_valid (reference))
return FALSE;
- }
- tree_path = gtk_tree_row_reference_get_path (row);
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, tree_path)) {
- gtk_tree_path_free (tree_path);
- return FALSE;
- }
-
- gtk_tree_path_free (tree_path);
-
- gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, COL_UINT_FLAGS, &flags, -1);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ gtk_tree_path_free (path);
- if ((flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX)
- return TRUE;
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (model), &iter,
+ COL_UINT_FLAGS, &flags, -1);
- return FALSE;
+ return ((flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX);
}
gchar *
-em_folder_tree_model_get_folder_name (EMFolderTreeModel *model, CamelStore *store, const gchar *full)
+em_folder_tree_model_get_folder_name (EMFolderTreeModel *model,
+ CamelStore *store,
+ const gchar *full)
{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
- GtkTreePath *tree_path;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
GtkTreeIter iter;
gchar *name = NULL;
@@ -1312,140 +1163,100 @@ em_folder_tree_model_get_folder_name (EMFolderTreeModel *model, CamelStore *stor
g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
g_return_val_if_fail (full != NULL, NULL);
- if (!(si = g_hash_table_lookup (model->store_hash, store))) {
- u(printf(" can't find store\n"));
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
return NULL;
- }
- if (!(row = g_hash_table_lookup (si->full_hash, full))) {
- u(printf(" can't find row\n"));
+ reference = g_hash_table_lookup (si->full_hash, full);
+ if (!gtk_tree_row_reference_valid (reference))
return NULL;
- }
- tree_path = gtk_tree_row_reference_get_path (row);
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, tree_path)) {
- gtk_tree_path_free (tree_path);
- return NULL;
- }
-
- gtk_tree_path_free (tree_path);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ gtk_tree_path_free (path);
- gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, COL_STRING_DISPLAY_NAME, &name, -1);
+ gtk_tree_model_get (
+ GTK_TREE_MODEL (model), &iter,
+ COL_STRING_DISPLAY_NAME, &name, -1);
return name;
}
void
-em_folder_tree_model_set_unread_count (EMFolderTreeModel *model, CamelStore *store, const gchar *full, gint unread)
+em_folder_tree_model_set_unread_count (EMFolderTreeModel *model,
+ CamelStore *store,
+ const gchar *full,
+ gint unread)
{
- struct _EMFolderTreeModelStoreInfo *si;
- GtkTreeRowReference *row;
- GtkTreePath *tree_path;
+ EMFolderTreeModelStoreInfo *si;
+ GtkTreeRowReference *reference;
+ GtkTreeModel *tree_model;
+ GtkTreePath *path;
+ GtkTreeIter parent;
GtkTreeIter iter;
guint old_unread = 0;
- gchar *uri, *sel_uri;
g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
g_return_if_fail (CAMEL_IS_STORE (store));
g_return_if_fail (full != NULL);
- u(printf("set unread count %p '%s' %d\n", store, full, unread));
-
if (unread < 0)
return;
- if (!(si = g_hash_table_lookup (model->store_hash, store))) {
- u(printf(" can't find store\n"));
+ si = em_folder_tree_model_lookup_store_info (model, store);
+ if (si == NULL)
return;
- }
- if (!(row = g_hash_table_lookup (si->full_hash, full))) {
- u(printf(" can't find row\n"));
+ reference = g_hash_table_lookup (si->full_hash, full);
+ if (!gtk_tree_row_reference_valid (reference))
return;
- }
- tree_path = gtk_tree_row_reference_get_path (row);
- if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, tree_path)) {
- gtk_tree_path_free (tree_path);
- return;
- }
+ tree_model = GTK_TREE_MODEL (model);
- gtk_tree_path_free (tree_path);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (tree_model, &iter, path);
+ gtk_tree_path_free (path);
- sel_uri = em_folder_tree_model_get_selected (model);
gtk_tree_model_get (
- GTK_TREE_MODEL (model), &iter,
- COL_UINT_UNREAD_LAST_SEL, &old_unread,
- COL_STRING_URI, &uri, -1);
- if (!(g_strcmp0 (sel_uri, uri) != 0 && unread > old_unread))
- old_unread = unread;
+ tree_model, &iter,
+ COL_UINT_UNREAD_LAST_SEL, &old_unread, -1);
+
gtk_tree_store_set (
GTK_TREE_STORE (model), &iter,
COL_UINT_UNREAD, unread,
- COL_UINT_UNREAD_LAST_SEL, old_unread, -1);
-
- g_free (uri);
- g_free (sel_uri);
+ COL_UINT_UNREAD_LAST_SEL, MIN (old_unread, unread), -1);
- /* May be this is from where we should propagate unread count to parents etc. */
- emft_model_unread_count_changed (GTK_TREE_MODEL (model), &iter);
+ /* Folders are displayed with a bold weight to indicate that
+ * they contain unread messages. We signal that parent rows
+ * have changed here to update them. */
+ while (gtk_tree_model_iter_parent (tree_model, &parent, &iter)) {
+ path = gtk_tree_model_get_path (tree_model, &parent);
+ gtk_tree_model_row_changed (tree_model, path, &parent);
+ gtk_tree_path_free (path);
+ iter = parent;
+ }
}
-gchar *
-em_folder_tree_model_get_selected (EMFolderTreeModel *model)
+EMFolderTreeModelStoreInfo *
+em_folder_tree_model_lookup_store_info (EMFolderTreeModel *model,
+ CamelStore *store)
{
- xmlNodePtr node;
- gchar *buf, *uri;
-
- node = model->state ? model->state->children : NULL;
- if (!node || strcmp ((gchar *)node->name, "tree-state") != 0)
- return NULL;
-
- node = node->children;
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "selected"))
- break;
- node = node->next;
- }
-
- if (node == NULL)
- return NULL;
-
- buf = (gchar *)xmlGetProp (node, (guchar *)"uri");
- uri = g_strdup (buf);
- xmlFree (buf);
+ g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL);
+ g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
- if (uri && !*uri) {
- g_free (uri);
- return NULL;
- }
- return uri;
+ return g_hash_table_lookup (model->priv->store_index, store);
}
-void
-em_folder_tree_model_set_selected (EMFolderTreeModel *model, const gchar *uri)
+GtkTreeRowReference *
+em_folder_tree_model_lookup_uri (EMFolderTreeModel *model,
+ const gchar *uri)
{
- xmlNodePtr root, node;
-
- if (model->state == NULL)
- model->state = xmlNewDoc ((guchar *)"1.0");
+ GtkTreeRowReference *reference;
- if (!model->state->children) {
- root = xmlNewDocNode (model->state, NULL, (const guchar *)"tree-state", NULL);
- xmlDocSetRootElement (model->state, root);
- } else {
- root = model->state->children;
- }
-
- node = root->children;
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "selected"))
- break;
- node = node->next;
- }
+ g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
- if (node == NULL)
- node = xmlNewChild (root, NULL, (const guchar *)"selected", NULL);
+ reference = g_hash_table_lookup (model->priv->uri_index, uri);
- xmlSetProp (node, (const guchar *)"uri", (guchar *)uri);
+ return gtk_tree_row_reference_valid (reference) ? reference : NULL;
}