[evolution/wip/webkit2] Bug 752644 - Unread mail indicator next to collapsed account names



commit c3893218cd04a10599f8f09a0a9b8102487c04b1
Author: Milan Crha <mcrha redhat com>
Date:   Tue Jul 21 16:24:37 2015 +0200

    Bug 752644 - Unread mail indicator next to collapsed account names

 mail/em-folder-tree-model.c |  138 +++++++++++++++++++++++++++++++++++++++++--
 mail/em-folder-tree-model.h |    3 +
 mail/em-folder-tree.c       |   39 ++++++++++++-
 3 files changed, 173 insertions(+), 7 deletions(-)
---
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index ebe61b8..6bce0e9 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -65,6 +65,13 @@ struct _EMFolderTreeModelPrivate {
        GMutex store_index_lock;
 };
 
+typedef struct _FolderUnreadInfo {
+       guint unread;
+       guint unread_last_sel;
+       gboolean is_drafts;
+       guint32 fi_flags;
+} FolderUnreadInfo;
+
 struct _StoreInfo {
        volatile gint ref_count;
 
@@ -74,6 +81,10 @@ struct _StoreInfo {
        /* CamelFolderInfo::full_name -> GtkTreeRowReference */
        GHashTable *full_hash;
 
+       /* CamelFolderInfo::full_name ~> FolderUnreadInfo * - last known unread count
+          for folders which are not loaded in the tree yet */
+       GHashTable *full_hash_unread;
+
        /* CamelStore signal handler IDs */
        gulong folder_created_handler_id;
        gulong folder_deleted_handler_id;
@@ -171,6 +182,7 @@ store_info_unref (StoreInfo *si)
                g_object_unref (si->store);
                gtk_tree_row_reference_free (si->row);
                g_hash_table_destroy (si->full_hash);
+               g_hash_table_destroy (si->full_hash_unread);
 
                g_slice_free (StoreInfo, si);
        }
@@ -194,6 +206,8 @@ store_info_new (EMFolderTreeModel *model,
                (GDestroyNotify) g_free,
                (GDestroyNotify) gtk_tree_row_reference_free);
 
+       si->full_hash_unread = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
        handler_id = g_signal_connect_data (
                store, "folder-created",
                G_CALLBACK (folder_tree_model_folder_created_cb),
@@ -490,8 +504,10 @@ folder_tree_model_remove_folders (EMFolderTreeModel *folder_tree_model,
                COL_STRING_FULL_NAME, &full_name,
                COL_BOOL_IS_STORE, &is_store, -1);
 
-       if (full_name != NULL)
+       if (full_name != NULL) {
                g_hash_table_remove (si->full_hash, full_name);
+               g_hash_table_remove (si->full_hash_unread, full_name);
+       }
 
        gtk_tree_store_remove (GTK_TREE_STORE (model), toplevel);
 
@@ -773,7 +789,8 @@ static void
 folder_tree_model_set_unread_count (EMFolderTreeModel *model,
                                     CamelStore *store,
                                     const gchar *full,
-                                    gint unread)
+                                    gint unread,
+                                   MailFolderCache *folder_cache)
 {
        GtkTreeRowReference *reference;
        GtkTreeModel *tree_model;
@@ -794,11 +811,47 @@ folder_tree_model_set_unread_count (EMFolderTreeModel *model,
        if (si == NULL)
                return;
 
+       tree_model = GTK_TREE_MODEL (model);
+
        reference = g_hash_table_lookup (si->full_hash, full);
-       if (!gtk_tree_row_reference_valid (reference))
-               goto exit;
+       if (!gtk_tree_row_reference_valid (reference)) {
+               FolderUnreadInfo *fu_info;
 
-       tree_model = GTK_TREE_MODEL (model);
+               fu_info = g_new0 (FolderUnreadInfo, 1);
+               fu_info->unread = unread;
+               fu_info->unread_last_sel = unread;
+               fu_info->is_drafts = FALSE;
+
+               if (g_hash_table_contains (si->full_hash_unread, full)) {
+                       FolderUnreadInfo *saved_fu_info;
+
+                       saved_fu_info = g_hash_table_lookup (si->full_hash_unread, full);
+
+                       fu_info->unread_last_sel = MIN (saved_fu_info->unread_last_sel, unread);
+                       fu_info->is_drafts = saved_fu_info->is_drafts;
+                       fu_info->fi_flags = saved_fu_info->fi_flags;
+               } else {
+                       CamelFolder *folder;
+                       CamelFolderInfoFlags flags;
+
+                       fu_info->unread_last_sel = unread;
+
+                       folder = mail_folder_cache_ref_folder (folder_cache, store, full);
+                       if (folder) {
+                               fu_info->is_drafts = em_utils_folder_is_drafts (e_mail_session_get_registry 
(model->priv->session), folder);
+                               g_object_unref (folder);
+                       }
+
+                       if (!mail_folder_cache_get_folder_info_flags (folder_cache, store, full, &flags))
+                               flags = 0;
+
+                       fu_info->fi_flags = flags;
+               }
+
+               g_hash_table_insert (si->full_hash_unread, g_strdup (full), fu_info);
+
+               goto exit;
+       }
 
        path = gtk_tree_row_reference_get_path (reference);
        gtk_tree_model_get_iter (tree_model, &iter, path);
@@ -1127,6 +1180,8 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model,
        g_hash_table_insert (
                si->full_hash, g_strdup (fi->full_name), path_row);
 
+       g_hash_table_remove (si->full_hash_unread, fi->full_name);
+
        store_info_unref (si);
        si = NULL;
 
@@ -1879,3 +1934,76 @@ em_folder_tree_model_user_marked_unread (EMFolderTreeModel *model,
                COL_UINT_UNREAD_LAST_SEL, unread,
                COL_UINT_UNREAD, unread, -1);
 }
+
+static gboolean
+folder_tree_model_eval_children_has_unread_mismatch (GtkTreeModel *model,
+                                                    GtkTreeIter *root)
+{
+       guint unread, unread_last_sel;
+       GtkTreeIter iter;
+
+       if (!gtk_tree_model_iter_children (model, &iter, root))
+               return FALSE;
+
+       do {
+               gtk_tree_model_get (model, &iter,
+                       COL_UINT_UNREAD, &unread,
+                       COL_UINT_UNREAD_LAST_SEL, &unread_last_sel,
+                       -1);
+
+               if (unread != ~0 && unread > unread_last_sel)
+                       return TRUE;
+
+               if (gtk_tree_model_iter_has_child (model, &iter))
+                       if (folder_tree_model_eval_children_has_unread_mismatch (model, &iter))
+                               return TRUE;
+       } while (gtk_tree_model_iter_next (model, &iter));
+
+       return FALSE;
+}
+
+gboolean
+em_folder_tree_model_has_unread_mismatch (GtkTreeModel *model,
+                                         GtkTreeIter *store_iter)
+{
+       StoreInfo *si;
+       CamelStore *store = NULL;
+       gboolean is_store = FALSE;
+       gboolean has_unread_mismatch = FALSE;
+
+       g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), FALSE);
+       g_return_val_if_fail (store_iter != NULL, FALSE);
+
+       gtk_tree_model_get (model, store_iter,
+               COL_BOOL_IS_STORE, &is_store,
+               COL_OBJECT_CAMEL_STORE, &store,
+               -1);
+
+       if (is_store) {
+               si = folder_tree_model_store_index_lookup (EM_FOLDER_TREE_MODEL (model), store);
+               if (si) {
+                       GHashTableIter hash_iter;
+                       gpointer value;
+
+                       g_hash_table_iter_init (&hash_iter, si->full_hash_unread);
+                       while (g_hash_table_iter_next (&hash_iter, NULL, &value)) {
+                               FolderUnreadInfo *fu_info = value;
+
+                               if (fu_info && !fu_info->is_drafts && (fu_info->fi_flags & 
CAMEL_FOLDER_VIRTUAL) == 0 &&
+                                   fu_info->unread > fu_info->unread_last_sel) {
+                                       has_unread_mismatch = TRUE;
+                                       break;
+                               }
+                       }
+
+                       store_info_unref (si);
+               }
+
+               has_unread_mismatch = has_unread_mismatch ||
+                       folder_tree_model_eval_children_has_unread_mismatch (model, store_iter);
+       }
+
+       g_clear_object (&store);
+
+       return has_unread_mismatch;
+}
diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h
index 325e3a5..e04f5b5 100644
--- a/mail/em-folder-tree-model.h
+++ b/mail/em-folder-tree-model.h
@@ -146,6 +146,9 @@ void                em_folder_tree_model_user_marked_unread
                                        (EMFolderTreeModel *model,
                                         CamelFolder *folder,
                                         guint n_marked);
+gboolean       em_folder_tree_model_has_unread_mismatch
+                                       (GtkTreeModel *model,
+                                        GtkTreeIter *store_iter);
 
 G_END_DECLS
 
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 37d5792..2c8592a 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -728,6 +728,32 @@ exit:
        g_clear_object (&store);
 }
 
+static void
+folder_tree_render_store_icon (GtkTreeViewColumn *column,
+                              GtkCellRenderer *renderer,
+                              GtkTreeModel *model,
+                              GtkTreeIter *iter,
+                              gpointer text_renderer)
+{
+       GtkTreeIter parent;
+       gboolean expanded = TRUE, children_has_unread_mismatch = FALSE;
+
+       /* The first prerequisite: it's a root node and has children. */
+       if (gtk_tree_model_iter_parent (model, &parent, iter) ||
+           !gtk_tree_model_iter_has_child (model, iter)) {
+               g_object_set (renderer, "visible", FALSE, NULL);
+               return;
+       }
+
+       g_object_get (text_renderer, "is-expanded", &expanded, NULL);
+
+       /* The second prerequisite: it's not expanded and children has unread mismatch. */
+       if (!expanded)
+               children_has_unread_mismatch = em_folder_tree_model_has_unread_mismatch (model, iter);
+
+       g_object_set (renderer, "visible", !expanded && children_has_unread_mismatch, NULL);
+}
+
 static gboolean
 subdirs_contain_unread (GtkTreeModel *model,
                         GtkTreeIter *root)
@@ -1272,13 +1298,22 @@ folder_tree_constructed (GObject *object)
                column, renderer, (GtkTreeCellDataFunc)
                folder_tree_render_icon, NULL, NULL);
 
-       renderer = gtk_cell_renderer_text_new ();
+       renderer = gtk_cell_renderer_pixbuf_new ();
+       g_object_set (G_OBJECT (renderer), "icon-name", "mail-unread", NULL);
+       gtk_tree_view_column_pack_start (column, renderer, FALSE);
+
+       priv->text_renderer = g_object_ref (gtk_cell_renderer_text_new ());
+
+       gtk_tree_view_column_set_cell_data_func (
+               column, renderer, folder_tree_render_store_icon,
+               g_object_ref (priv->text_renderer), g_object_unref);
+
+       renderer = priv->text_renderer;
        g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
        gtk_tree_view_column_pack_start (column, renderer, TRUE);
        gtk_tree_view_column_set_cell_data_func (
                column, renderer, (GtkTreeCellDataFunc)
                folder_tree_render_display_name, NULL, NULL);
-       priv->text_renderer = g_object_ref (renderer);
 
        g_signal_connect_swapped (
                renderer, "edited",


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