From 781c3b10aae6a0d7630bca665787b5ff31e4b567 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 16 Feb 2010 16:55:51 -0500 Subject: Bug 609982 - Avoid unnecessary prompts when marking folders as read --- plugins/mark-all-read/mark-all-read.c | 213 +++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 93 deletions(-) (limited to 'plugins/mark-all-read') diff --git a/plugins/mark-all-read/mark-all-read.c b/plugins/mark-all-read/mark-all-read.c index 3923f86c2b..24bc48521a 100644 --- a/plugins/mark-all-read/mark-all-read.c +++ b/plugins/mark-all-read/mark-all-read.c @@ -196,6 +196,104 @@ prompt_user (void) return response; } +static gboolean +scan_folder_tree_for_unread_helper (GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreePath *path, + gint initial_depth, + gint *relative_depth) +{ + /* This is based on gtk_tree_model_foreach(). Unfortunately + * that function insists on traversing the entire tree model. */ + + do { + GtkTreeIter child; + gboolean folder_has_unread; + gboolean is_draft = FALSE; + gboolean is_store = FALSE; + guint unread = 0; + + gtk_tree_model_get ( + model, iter, + COL_UINT_UNREAD, &unread, + COL_BOOL_IS_STORE, &is_store, + COL_BOOL_IS_DRAFT, &is_draft, -1); + + folder_has_unread = + !is_store && !is_draft && + unread > 0 && unread != ~((guint) 0); + + if (folder_has_unread) { + gint current_depth; + + current_depth = gtk_tree_path_get_depth (path); + *relative_depth = current_depth - initial_depth + 1; + + /* If we find unread messages in a child of the + * selected folder, short-circuit the recursion. */ + if (*relative_depth > 1) + return TRUE; + } + + if (gtk_tree_model_iter_children (model, &child, iter)) { + gtk_tree_path_down (path); + + if (scan_folder_tree_for_unread_helper ( + model, &child, path, + initial_depth, relative_depth)) + return TRUE; + + gtk_tree_path_up (path); + } + + gtk_tree_path_next (path); + + } while (gtk_tree_model_iter_next (model, iter)); + + return FALSE; +} + +static gint +scan_folder_tree_for_unread (const gchar *folder_uri) +{ + GtkTreeRowReference *reference; + EMFolderTreeModel *model; + gint relative_depth = 0; + + /* Traverses the selected folder and its children and returns + * the relative depth of the furthest child folder containing + * unread mail. Except, we abort the traversal as soon as we + * find a child folder with unread messages. So the possible + * return values are: + * + * Depth = 0: No unread mail found. + * Depth = 1: Unread mail only in selected folder. + * Depth = 2: Unread mail in one of the child folders. + */ + + if (folder_uri == NULL) + return 0; + + model = em_folder_tree_model_get_default (); + reference = em_folder_tree_model_lookup_uri (model, folder_uri); + + if (gtk_tree_row_reference_valid (reference)) { + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_row_reference_get_path (reference); + gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path); + + scan_folder_tree_for_unread_helper ( + GTK_TREE_MODEL (model), &iter, path, + gtk_tree_path_get_depth (path), &relative_depth); + + gtk_tree_path_free (path); + } + + return relative_depth; +} + static void mark_all_as_read (CamelFolder *folder) { @@ -238,15 +336,14 @@ mar_all_sub_folders (CamelStore *store, } static void -mar_got_folder (gchar *uri, +mar_got_folder (gchar *folder_uri, CamelFolder *folder, gpointer data) { - CamelFolderInfo *info; + CamelFolderInfo *folder_info; CamelStore *store; CamelException ex; gint response; - guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_FAST; /* FIXME we have to disable the menu item */ if (!folder) @@ -255,12 +352,15 @@ mar_got_folder (gchar *uri, camel_exception_init (&ex); store = folder->parent_store; - info = camel_store_get_folder_info (store, folder->full_name, flags, &ex); + folder_info = camel_store_get_folder_info ( + store, folder->full_name, + CAMEL_STORE_FOLDER_INFO_RECURSIVE | + CAMEL_STORE_FOLDER_INFO_FAST, &ex); if (camel_exception_is_set (&ex)) - goto out; + goto exit; - if (info && (info->child || info->next)) + if (scan_folder_tree_for_unread (folder_uri) > 1) response = prompt_user (); else response = GTK_RESPONSE_NO; @@ -268,58 +368,10 @@ mar_got_folder (gchar *uri, if (response == GTK_RESPONSE_NO) mark_all_as_read (folder); else if (response == GTK_RESPONSE_YES) - mar_all_sub_folders (store, info, &ex); -out: - camel_store_free_folder_info(store, info); -} - -static void -has_unread_mail (GtkTreeModel *model, - GtkTreeIter *parent, - gboolean is_root, - gboolean *has_unread, - gboolean *applicable) -{ - guint unread = 0; - GtkTreeIter iter, child; - - g_return_if_fail (model != NULL); - g_return_if_fail (parent != NULL); - g_return_if_fail (has_unread != NULL); - g_return_if_fail (applicable != NULL); + mar_all_sub_folders (store, folder_info, &ex); - if (is_root) { - gboolean is_draft = FALSE, is_store = FALSE; - - gtk_tree_model_get (model, parent, - COL_UINT_UNREAD, &unread, - COL_BOOL_IS_STORE, &is_store, - COL_BOOL_IS_DRAFT, &is_draft, - -1); - - *has_unread = *has_unread || (unread > 0 && unread != ~((guint)0)); - *applicable = !is_store && !is_draft; - - if (*has_unread) - return; - - if (!gtk_tree_model_iter_children (model, &iter, parent)) - return; - } else { - iter = *parent; - } - - do { - gtk_tree_model_get (model, &iter, COL_UINT_UNREAD, &unread, -1); - - *has_unread = *has_unread || (unread > 0 && unread != ~((guint)0)); - if (*has_unread) - break; - - if (gtk_tree_model_iter_children (model, &child, &iter)) - has_unread_mail (model, &child, FALSE, has_unread, applicable); - - } while (gtk_tree_model_iter_next (model, &iter) && !*has_unread); +exit: + camel_store_free_folder_info (store, folder_info); } static void @@ -336,10 +388,11 @@ action_mail_mark_read_recursive_cb (GtkAction *action, g_return_if_fail (folder_uri != NULL); mail_get_folder ( - folder_uri, 0, mar_got_folder, NULL, mail_msg_unordered_push); + folder_uri, 0, mar_got_folder, + NULL, mail_msg_unordered_push); - g_free (folder_uri); g_object_unref (folder_tree); + g_free (folder_uri); } static GtkActionEntry entries[] = { @@ -357,56 +410,30 @@ update_actions_cb (EShellView *shell_view, gpointer user_data) { GtkActionGroup *action_group; - EShellWindow *shell_window; - GtkAction *action; EShellSidebar *shell_sidebar; + EShellWindow *shell_window; EMFolderTree *folder_tree; + GtkAction *action; gchar *folder_uri; - gboolean has_unread = FALSE; - gboolean applicable = FALSE; gboolean visible; g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); - shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL); - folder_uri = em_folder_tree_get_selected_uri (folder_tree); - - if (folder_uri != NULL) { - EMFolderTreeModel *model; - - model = em_folder_tree_model_get_default (); - if (model) { - GtkTreeRowReference *reference; - - reference = em_folder_tree_model_lookup_uri ( - model, folder_uri); - if (reference != NULL) { - GtkTreePath *path; - GtkTreeIter iter; - - path = gtk_tree_row_reference_get_path (reference); - gtk_tree_model_get_iter ( - GTK_TREE_MODEL (model), &iter, path); - has_unread_mail ( - GTK_TREE_MODEL (model), &iter, - TRUE, &has_unread, &applicable); - gtk_tree_path_free (path); - } - } - } - shell_window = e_shell_view_get_shell_window (shell_view); action_group = e_shell_window_get_action_group (shell_window, "mail"); action = gtk_action_group_get_action (action_group, entries[0].name); g_return_if_fail (action != NULL); - visible = has_unread && applicable; + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); + g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL); + folder_uri = em_folder_tree_get_selected_uri (folder_tree); + + visible = (scan_folder_tree_for_unread (folder_uri) > 0); gtk_action_set_visible (action, visible); - g_free (folder_uri); g_object_unref (folder_tree); + g_free (folder_uri); } gboolean -- cgit v1.2.3