diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2003-12-02 06:18:49 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2003-12-02 06:18:49 +0800 |
commit | 81660eb86333fcb3d3e643300c4e041396e92b98 (patch) | |
tree | 36330b5db2dc6d0a57246aff225fa73a865bb3da /mail/em-folder-tree-model.c | |
parent | 7af66de0238f45979c19eaa3cc9a2e2ba1d9dea0 (diff) | |
download | gsoc2013-evolution-81660eb86333fcb3d3e643300c4e041396e92b98.tar.gz gsoc2013-evolution-81660eb86333fcb3d3e643300c4e041396e92b98.tar.zst gsoc2013-evolution-81660eb86333fcb3d3e643300c4e041396e92b98.zip |
Updated to call em_folder_tree_model_set_folder_info().
2003-12-01 Jeffrey Stedfast <fejj@ximian.com>
* em-folder-tree.c (em_folder_tree_get_folder_info__got): Updated
to call em_folder_tree_model_set_folder_info().
(folder_subscribed_cb): Removed.
(folder_unsubscribed_cb): Removed.
(folder_created_cb): Removed.
(folder_deleted_cb): Removed.
(folder_renamed_cb): Removed.
* em-folder-tree-model.c (em_folder_tree_store_set_folder_info):
New function to replace tree_store_set_folder_info() which had
been in em-folder-tree.c
(em_folder_tree_model_remove_uri): Made private.
(em_folder_tree_model_remove_store_info): Made private.
(em_folder_tree_model_remove_folders): New function to replace
remove_folders() from em-folder-tree.c
(em_folder_tree_model_new): No longer takes any args.
* em-folder-tree.c (em_folder_tree_new): Updated.
* mail-component.c (add_store): Add the store to the model rather
than the treeview.
(impl_createControls): create a new treeview based on the
already-instantiated model.
(mail_component_init): Create a new tree model.
(mail_component_remove_store): Remove the store from the model
directly.
(mail_component_get_tree_model): Updated.
* em-folder-tree.c (folder_unsubscribed_cb): Call
em_folder_tree_model_remove_folders() rather than the deprecated
internal remove_folders() function.
(folder_renamed_cb): Same.
(em_folder_tree_remove_store): Removed.
(em_folder_tree_add_store): Removed.
(remove_folders): Removed.
svn path=/trunk/; revision=23545
Diffstat (limited to 'mail/em-folder-tree-model.c')
-rw-r--r-- | mail/em-folder-tree-model.c | 412 |
1 files changed, 409 insertions, 3 deletions
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c index f6f7d6cc27..677ab8d0fe 100644 --- a/mail/em-folder-tree-model.c +++ b/mail/em-folder-tree-model.c @@ -25,10 +25,25 @@ #include <config.h> #endif +#include <string.h> + +#include "mail-config.h" + #include "em-marshal.h" #include "em-folder-tree-model.h" +static GType col_types[] = { + G_TYPE_STRING, /* display name */ + G_TYPE_POINTER, /* store object */ + G_TYPE_STRING, /* path */ + G_TYPE_STRING, /* uri */ + G_TYPE_UINT, /* unread count */ + G_TYPE_BOOLEAN, /* is a store node */ + G_TYPE_BOOLEAN, /* has not-yet-loaded subfolders */ +}; + + /* GObject virtual method overrides */ static void em_folder_tree_model_class_init (EMFolderTreeModelClass *klass); static void em_folder_tree_model_init (EMFolderTreeModel *model); @@ -321,18 +336,348 @@ model_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *src_path) EMFolderTreeModel * -em_folder_tree_model_new (int n_columns, GType *types) +em_folder_tree_model_new (void) { EMFolderTreeModel *model; model = g_object_new (EM_TYPE_FOLDER_TREE_MODEL, NULL); - gtk_tree_store_set_column_types ((GtkTreeStore *) model, n_columns, types); + gtk_tree_store_set_column_types ((GtkTreeStore *) model, NUM_COLUMNS, col_types); return model; } void +em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *iter, + struct _EMFolderTreeModelStoreInfo *si, + CamelFolderInfo *fi) +{ + GtkTreeRowReference *uri_row, *path_row; + unsigned int unread; + EAccount *account; + GtkTreePath *path; + GtkTreeIter sub; + gboolean load; + char *node; + + load = !fi->child && (fi->flags & CAMEL_FOLDER_CHILDREN) && !(fi->flags & CAMEL_FOLDER_NOINFERIORS); + + path = gtk_tree_model_get_path ((GtkTreeModel *) model, iter); + uri_row = gtk_tree_row_reference_new ((GtkTreeModel *) 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->url), uri_row); + g_hash_table_insert (si->path_hash, g_strdup (fi->path), path_row); + + unread = fi->unread_message_count == -1 ? 0 : fi->unread_message_count; + + gtk_tree_store_set ((GtkTreeStore *) model, iter, + COL_STRING_DISPLAY_NAME, fi->name, + COL_POINTER_CAMEL_STORE, si->store, + COL_STRING_FOLDER_PATH, fi->path, + COL_STRING_URI, fi->url, + COL_UINT_UNREAD, unread, + COL_BOOL_IS_STORE, FALSE, + COL_BOOL_LOAD_SUBDIRS, load, + -1); + + node = fi->path; + + if (fi->child) { + fi = fi->child; + + do { + gtk_tree_store_append ((GtkTreeStore *) model, &sub, iter); + em_folder_tree_model_set_folder_info (model, &sub, si, fi); + fi = fi->sibling; + } while (fi); + } else if (load) { + /* create a placeholder node for our subfolders... */ + gtk_tree_store_append ((GtkTreeStore *) model, &sub, iter); + gtk_tree_store_set ((GtkTreeStore *) model, &sub, + COL_STRING_DISPLAY_NAME, _("Loading..."), + COL_POINTER_CAMEL_STORE, si->store, + COL_STRING_FOLDER_PATH, fi->path, + COL_BOOL_LOAD_SUBDIRS, TRUE, + COL_BOOL_IS_STORE, FALSE, + COL_STRING_URI, fi->url, + COL_UINT_UNREAD, 0, + -1); + } +#if 0 + /* FIXME: need to somehow get access to the appropriate treeview widget... */ + if ((account = mail_config_get_account_by_name (si->display_name))) + node = g_strdup_printf ("%s:%s", account->uid, node); + else + node = g_strdup_printf ("%s:%s", si->display_name, node); + + if (g_hash_table_lookup (priv->expanded, node)) { + printf ("expanding node '%s'\n", node); + gtk_tree_view_expand_to_path (priv->treeview, path); + } + + gtk_tree_path_free (path); + g_free (node); +#endif +} + + +static void +folder_subscribed_cb (CamelStore *store, void *event_data, EMFolderTreeModel *model) +{ + struct _EMFolderTreeModelStoreInfo *si; + CamelFolderInfo *fi = event_data; + GtkTreeRowReference *row; + GtkTreeIter parent, iter; + GtkTreePath *path; + gboolean load; + char *dirname; + + if (!(si = g_hash_table_lookup (model->store_hash, store))) + return; + + /* make sure we don't already know about it? */ + if (g_hash_table_lookup (si->path_hash, fi->path)) + return; + + /* get our parent folder's path */ + if (!(dirname = g_path_get_dirname (fi->path))) + return; + + if (!strcmp (dirname, "/")) { + /* user subscribed to a toplevel folder */ + row = si->row; + g_free (dirname); + } else { + row = g_hash_table_lookup (si->path_hash, dirname); + g_free (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) + return; + } + + path = gtk_tree_row_reference_get_path (row); + if (!(gtk_tree_model_get_iter ((GtkTreeModel *) model, &parent, path))) { + gtk_tree_path_free (path); + return; + } + + 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); + if (load) + return; + + /* append a new node */ + gtk_tree_store_append ((GtkTreeStore *) model, &iter, &parent); + + em_folder_tree_model_set_folder_info (model, &iter, si, fi); +} + +static void +folder_unsubscribed_cb (CamelStore *store, void *event_data, EMFolderTreeModel *model) +{ + struct _EMFolderTreeModelStoreInfo *si; + CamelFolderInfo *fi = event_data; + GtkTreeRowReference *row; + GtkTreePath *path; + GtkTreeIter iter; + + if (!(si = g_hash_table_lookup (model->store_hash, store))) + return; + + if (!(row = g_hash_table_lookup (si->path_hash, fi->path))) + return; + + path = gtk_tree_row_reference_get_path (row); + if (!(gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path))) { + gtk_tree_path_free (path); + return; + } + + em_folder_tree_model_remove_folders (model, si, &iter); +} + +static void +folder_created_cb (CamelStore *store, void *event_data, EMFolderTreeModel *model) +{ + /* we only want created events to do more work if we don't support subscriptions */ + if (!camel_store_supports_subscriptions (store)) + folder_subscribed_cb (store, event_data, model); +} + +static void +folder_deleted_cb (CamelStore *store, void *event_data, EMFolderTreeModel *model) +{ + /* we only want deleted events to do more work if we don't support subscriptions */ + if (!camel_store_supports_subscriptions (store)) + folder_unsubscribed_cb (store, event_data, model); +} + +static void +folder_renamed_cb (CamelStore *store, void *event_data, EMFolderTreeModel *model) +{ + struct _EMFolderTreeModelStoreInfo *si; + CamelRenameInfo *info = event_data; + GtkTreeRowReference *row; + GtkTreeIter root, iter; + GtkTreePath *path; + char *parent, *p; + + if (!(si = g_hash_table_lookup (model->store_hash, store))) + return; + + parent = g_strdup_printf ("/%s", info->old_base); + if (!(row = g_hash_table_lookup (si->path_hash, parent))) { + g_free (parent); + return; + } + g_free (parent); + + path = gtk_tree_row_reference_get_path (row); + if (!(gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path))) { + gtk_tree_path_free (path); + return; + } + + em_folder_tree_model_remove_folders (model, si, &iter); + + parent = g_strdup (info->new->path); + if ((p = strrchr (parent + 1, '/'))) + *p = '\0'; + + if (!strcmp (parent, "/")) { + /* 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->path_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_assert_not_reached (); + g_free (parent); + return; + } + + path = gtk_tree_row_reference_get_path (row); + } + + g_free (parent); + + if (!gtk_tree_model_get_iter ((GtkTreeModel *) model, &root, path)) { + gtk_tree_path_free (path); + g_assert_not_reached (); + return; + } + + gtk_tree_store_append ((GtkTreeStore *) model, &iter, &root); + em_folder_tree_model_set_folder_info (model, &iter, si, info->new); +} + + +void +em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store, const char *display_name) +{ + struct _EMFolderTreeModelStoreInfo *si; + GtkTreeRowReference *row; + GtkTreeIter root, iter; + GtkTreePath *path; + EAccount *account; + char *node, *uri; + + g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model)); + 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))) { + const char *name; + + path = gtk_tree_row_reference_get_path (si->row); + gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path); + gtk_tree_path_free (path); + + gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_STRING_DISPLAY_NAME, (char **) &name, -1); + + g_warning ("the store `%s' is already in the folder tree as `%s'", + display_name, name); + + return; + } + + uri = camel_url_to_string (((CamelService *) store)->url, CAMEL_URL_HIDE_ALL); + + /* 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_FOLDER_PATH, "/", + 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); + gtk_tree_path_free (path); + + si = g_new (struct _EMFolderTreeModelStoreInfo, 1); + si->display_name = g_strdup (display_name); + camel_object_ref (store); + si->store = store; + si->row = row; + si->path_hash = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (model->store_hash, store, si); + + /* 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, store, + COL_STRING_FOLDER_PATH, "/", + COL_BOOL_LOAD_SUBDIRS, TRUE, + COL_BOOL_IS_STORE, FALSE, + COL_STRING_URI, uri, + COL_UINT_UNREAD, 0, + -1); + + g_free (uri); + +#if 0 + /* FIXME: how to do this now that it is being done in the + * model instead of the tree widget code??? need to somehow + * get access to the appropriate treeview widget... */ + if ((account = mail_config_get_account_by_name (display_name))) + node = g_strdup_printf ("%s:/", account->uid); + else + node = g_strdup_printf ("%s:/", display_name); + + if (g_hash_table_lookup (priv->expanded, node)) { + path = gtk_tree_model_get_path ((GtkTreeModel *) model, &iter); + gtk_tree_view_expand_to_path (priv->treeview, path); + gtk_tree_path_free (path); + } + + g_free (node); +#endif + + /* 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); +} + + +static void em_folder_tree_model_remove_uri (EMFolderTreeModel *model, const char *uri) { GtkTreeRowReference *row; @@ -347,7 +692,7 @@ em_folder_tree_model_remove_uri (EMFolderTreeModel *model, const char *uri) } -void +static void em_folder_tree_model_remove_store_info (EMFolderTreeModel *model, CamelStore *store) { struct _EMFolderTreeModelStoreInfo *si; @@ -361,3 +706,64 @@ em_folder_tree_model_remove_store_info (EMFolderTreeModel *model, CamelStore *st g_hash_table_remove (model->store_hash, si->store); store_info_free (si); } + + +void +em_folder_tree_model_remove_folders (EMFolderTreeModel *model, struct _EMFolderTreeModelStoreInfo *si, GtkTreeIter *toplevel) +{ + GtkTreeRowReference *row; + char *uri, *folder_path; + gboolean is_store, go; + GtkTreeIter iter; + + if (gtk_tree_model_iter_children ((GtkTreeModel *) model, &iter, toplevel)) { + do { + GtkTreeIter next = iter; + + go = gtk_tree_model_iter_next ((GtkTreeModel *) 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_FOLDER_PATH, &folder_path, + COL_BOOL_IS_STORE, &is_store, -1); + + if ((row = g_hash_table_lookup (si->path_hash, folder_path))) { + g_hash_table_remove (si->path_hash, folder_path); + gtk_tree_row_reference_free (row); + } + + em_folder_tree_model_remove_uri (model, uri); + + gtk_tree_store_remove ((GtkTreeStore *) model, toplevel); + + if (is_store) + em_folder_tree_model_remove_store_info (model, si->store); +} + + +void +em_folder_tree_model_remove_store (EMFolderTreeModel *model, CamelStore *store) +{ + struct _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))) { + g_warning ("the store `%s' is not in the folder tree", si->display_name); + + return; + } + + path = gtk_tree_row_reference_get_path (si->row); + gtk_tree_model_get_iter ((GtkTreeModel *) 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); +} |