[evolution-data-server/gnome-3-0] Bug #562912 - Unread vfolder marks unread messages as read



commit 4de215d8a23a1e5486daa5f8d65671f5e7b0193b
Author: Milan Crha <mcrha redhat com>
Date:   Tue Aug 23 13:20:19 2011 +0200

    Bug #562912 - Unread vfolder marks unread messages as read

 camel/camel-vee-folder.c  |  118 +++++++++++++++++++++++++++++++++++++++++---
 camel/camel-vee-folder.h  |    1 +
 camel/camel-vee-summary.c |  103 +++++++--------------------------------
 3 files changed, 130 insertions(+), 92 deletions(-)
---
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
index d15f30f..cb90037 100644
--- a/camel/camel-vee-folder.c
+++ b/camel/camel-vee-folder.c
@@ -47,11 +47,12 @@ struct _CamelVeeFolderPrivate {
 	gboolean destroyed;
 	GList *folders;			/* lock using subfolder_lock before changing/accessing */
 	GList *folders_changed;		/* for list of folders that have changed between updates */
+	GHashTable *ignore_changed;	/* hash of subfolder pointers to ignore the next folder's 'changed' signal */
+	GHashTable *skipped_changes;	/* CamelFolder -> CamelFolderChangeInfo accumulating ignored changes */
 
 	GMutex *summary_lock;		/* for locking vfolder summary */
 	GMutex *subfolder_lock;		/* for locking the subfolder list */
 	GMutex *changed_lock;		/* for locking the folders-changed list */
-	gint unread_vfolder;
 };
 
 struct _update_data {
@@ -847,6 +848,24 @@ folder_changed (CamelFolder *sub,
 {
 	CamelVeeFolderClass *class;
 
+	g_return_if_fail (vee_folder != NULL);
+	g_return_if_fail (CAMEL_IS_VEE_FOLDER (vee_folder));
+
+	camel_vee_folder_lock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+	if (g_hash_table_lookup (vee_folder->priv->ignore_changed, sub)) {
+		CamelFolderChangeInfo *old_changes;
+		g_hash_table_remove (vee_folder->priv->ignore_changed, sub);
+
+		old_changes = g_hash_table_lookup (vee_folder->priv->skipped_changes, sub);
+		if (!old_changes)
+			old_changes = camel_folder_change_info_new ();
+		camel_folder_change_info_cat (old_changes, changes);
+		g_hash_table_insert (vee_folder->priv->skipped_changes, sub, old_changes);
+		camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+		return;
+	}
+	camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
 	class = CAMEL_VEE_FOLDER_GET_CLASS (vee_folder);
 	class->folder_changed (vee_folder, sub, changes);
 }
@@ -997,6 +1016,12 @@ vee_folder_dispose (GObject *object)
 }
 
 static void
+free_change_info_cb (gpointer folder, gpointer change_info, gpointer user_data)
+{
+	camel_folder_change_info_free (change_info);
+}
+
+static void
 vee_folder_finalize (GObject *object)
 {
 	CamelVeeFolder *vf;
@@ -1011,15 +1036,49 @@ vee_folder_finalize (GObject *object)
 	camel_folder_change_info_free (vf->changes);
 	g_object_unref (vf->search);
 
+	g_hash_table_foreach (vf->priv->skipped_changes, free_change_info_cb, NULL);
+
 	g_mutex_free (vf->priv->summary_lock);
 	g_mutex_free (vf->priv->subfolder_lock);
 	g_mutex_free (vf->priv->changed_lock);
 	g_hash_table_destroy (vf->hashes);
+	g_hash_table_destroy (vf->priv->ignore_changed);
+	g_hash_table_destroy (vf->priv->skipped_changes);
 
 	/* Chain up to parent's finalize () method. */
 	G_OBJECT_CLASS (camel_vee_folder_parent_class)->finalize (object);
 }
 
+static void
+vee_folder_propagate_skipped_changes (CamelVeeFolder *vf)
+{
+	CamelVeeFolderClass *klass;
+	GHashTableIter iter;
+	gpointer psub, pchanges;
+
+	g_return_if_fail (vf != NULL);
+
+	klass = CAMEL_VEE_FOLDER_GET_CLASS (vf);
+
+	camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
+	g_hash_table_iter_init (&iter, vf->priv->skipped_changes);
+	while (g_hash_table_iter_next (&iter, &psub, &pchanges)) {
+		g_warn_if_fail (pchanges != NULL);
+		if (!pchanges)
+			continue;
+
+		if (g_list_find (vf->priv->folders, psub) != NULL)
+			klass->folder_changed (vf, psub, pchanges);
+
+		camel_folder_change_info_free (pchanges);
+	}
+
+	g_hash_table_remove_all (vf->priv->skipped_changes);
+
+	camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+}
+
 static GPtrArray *
 vee_folder_search_by_expression (CamelFolder *folder,
                                  const gchar *expression,
@@ -1035,6 +1094,8 @@ vee_folder_search_by_expression (CamelFolder *folder,
 	gboolean is_folder_unmatched = vf == folder_unmatched && folder_unmatched;
 	GHashTable *folder_unmatched_hash = NULL;
 
+	vee_folder_propagate_skipped_changes (vf);
+
 	if (is_folder_unmatched) {
 		expr = g_strdup (expression);
 		folder_unmatched_hash = camel_folder_summary_get_hashtable (((CamelFolder *) folder_unmatched)->summary);
@@ -1094,6 +1155,8 @@ vee_folder_search_by_uids (CamelFolder *folder,
 	CamelVeeFolderPrivate *p = vf->priv;
 	GHashTable *searched = g_hash_table_new (NULL, NULL);
 
+	vee_folder_propagate_skipped_changes (vf);
+
 	camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
 
 	expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
@@ -1157,6 +1220,8 @@ vee_folder_count_by_expression (CamelFolder *folder,
 	GHashTable *searched = g_hash_table_new (NULL, NULL);
 	CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
 
+	vee_folder_propagate_skipped_changes (vf);
+
 	if (vf != folder_unmatched)
 		expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
 	else
@@ -1313,6 +1378,8 @@ vee_folder_refresh_info_sync (CamelFolder *folder,
 	GList *node, *list;
 	gboolean success = TRUE;
 
+	vee_folder_propagate_skipped_changes (vf);
+
 	camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
 	list = p->folders_changed;
 	p->folders_changed = NULL;
@@ -1345,6 +1412,8 @@ vee_folder_synchronize_sync (CamelFolder *folder,
 	CamelVeeFolderPrivate *p = vf->priv;
 	GList *node;
 
+	vee_folder_propagate_skipped_changes (vf);
+
 	if (((CamelVeeSummary *)folder->summary)->fake_visible_count)
 		folder->summary->visible_count = ((CamelVeeSummary *)folder->summary)->fake_visible_count;
 	((CamelVeeSummary *)folder->summary)->fake_visible_count = 0;
@@ -1377,7 +1446,7 @@ vee_folder_synchronize_sync (CamelFolder *folder,
 		node = node->next;
 	}
 
-	if (vf->priv->unread_vfolder == 1) {
+	if (!CAMEL_IS_VTRASH_FOLDER (vf)) {
 		/* Cleanup Junk/Trash uids */
 		CamelStore *parent_store;
 		const gchar *full_name;
@@ -2032,7 +2101,8 @@ camel_vee_folder_init (CamelVeeFolder *vee_folder)
 	vee_folder->priv->summary_lock = g_mutex_new ();
 	vee_folder->priv->subfolder_lock = g_mutex_new ();
 	vee_folder->priv->changed_lock = g_mutex_new ();
-	vee_folder->priv->unread_vfolder = -1;
+	vee_folder->priv->ignore_changed = g_hash_table_new (g_direct_hash, g_direct_equal);
+	vee_folder->priv->skipped_changes = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 void
@@ -2262,6 +2332,8 @@ camel_vee_folder_rebuild_folder (CamelVeeFolder *vf,
                                  CamelFolder *sub,
                                  GError **error)
 {
+	vee_folder_propagate_skipped_changes (vf);
+
 	return CAMEL_VEE_FOLDER_GET_CLASS (vf)->rebuild_folder (vf, sub, error);
 }
 
@@ -2401,24 +2473,52 @@ camel_vee_folder_get_location (CamelVeeFolder *vf, const CamelVeeMessageInfo *vi
  * camel_vee_folder_mask_event_folder_changed:
  *
  * Since: 2.26
+ *
+ * Deprecated: 3.2: Does nothing, use camel_vee_folder_ignore_next_changed_event().
  **/
 void
 camel_vee_folder_mask_event_folder_changed (CamelVeeFolder *vf,
                                             CamelFolder *sub)
 {
-	g_signal_handlers_block_by_func (sub, folder_changed, vf);
 }
 
 /**
  * camel_vee_folder_unmask_event_folder_changed:
  *
  * Since: 2.26
+ *
+ * Deprecated: 3.2: Does nothing, use camel_vee_folder_ignore_next_changed_event().
  **/
 void
 camel_vee_folder_unmask_event_folder_changed (CamelVeeFolder *vf,
                                               CamelFolder *sub)
 {
-	g_signal_handlers_unblock_by_func (sub, folder_changed, vf);
+}
+
+/**
+ * camel_vee_folder_ignore_next_changed_event:
+ * @vf: a #CamelVeeFolder
+ * @sub: a #CamelFolder folder
+ *
+ * The next @sub folder's 'changed' event will be silently ignored. This
+ * is usually used in virtual folders when the change was done in them,
+ * but it is neither vTrash nor vJunk folder. Doing this avoids unnecessary
+ * removals of messages which don't satisfy search criteria anymore,
+ * which could be done on asynchronous delivery of folder's 'changed' signal.
+ * These ignored changes are accumulated and used on folder refresh.
+ *
+ * Since: 3.2
+ **/
+void
+camel_vee_folder_ignore_next_changed_event (CamelVeeFolder *vf, CamelFolder *sub)
+{
+	g_return_if_fail (vf != NULL);
+	g_return_if_fail (CAMEL_IS_VEE_FOLDER (vf));
+	g_return_if_fail (sub != NULL);
+
+	camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+	g_hash_table_insert (vf->priv->ignore_changed, sub, GINT_TO_POINTER (1));
+	camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
 }
 
 /**
@@ -2449,6 +2549,8 @@ camel_vee_folder_sync_headers (CamelFolder *vf,
  * @folder: a #CamelVeeFolder
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Does nothing, returns always 0.
  **/
 gint
 camel_vee_folder_get_unread_vfolder (CamelVeeFolder *folder)
@@ -2456,7 +2558,7 @@ camel_vee_folder_get_unread_vfolder (CamelVeeFolder *folder)
 	/* FIXME: This shouldn't be needed */
 	g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (folder), 0);
 
-	return folder->priv->unread_vfolder;
+	return 0;
 }
 
 /**
@@ -2465,6 +2567,8 @@ camel_vee_folder_get_unread_vfolder (CamelVeeFolder *folder)
  * @unread_vfolder: %TRUE if %folder is for unread messages
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Does nothing.
  **/
 void
 camel_vee_folder_set_unread_vfolder (CamelVeeFolder *folder,
@@ -2472,8 +2576,6 @@ camel_vee_folder_set_unread_vfolder (CamelVeeFolder *folder,
 {
 	/* FIXME: This shouldn't be needed */
 	g_return_if_fail (CAMEL_IS_VEE_FOLDER (folder));
-
-	folder->priv->unread_vfolder = unread_vfolder;
 }
 
 /**
diff --git a/camel/camel-vee-folder.h b/camel/camel-vee-folder.h
index 6909074..1b08430 100644
--- a/camel/camel-vee-folder.h
+++ b/camel/camel-vee-folder.h
@@ -129,6 +129,7 @@ void	     camel_vee_folder_set_expression	(CamelVeeFolder *vf, const gchar *expr
 
 void	     camel_vee_folder_mask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub);
 void	     camel_vee_folder_unmask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub);
+void	     camel_vee_folder_ignore_next_changed_event (CamelVeeFolder *vf, CamelFolder *sub);
 
 void	     camel_vee_folder_hash_folder	(CamelFolder *folder, gchar buffer[8]);
 void	     camel_vee_folder_sync_headers (CamelFolder *vf, GError **error);
diff --git a/camel/camel-vee-summary.c b/camel/camel-vee-summary.c
index c34eddf..2758c6e 100644
--- a/camel/camel-vee-summary.c
+++ b/camel/camel-vee-summary.c
@@ -36,12 +36,11 @@
 #include "camel-vee-summary.h"
 #include "camel-vee-folder.h"
 #include "camel-vee-store.h"
+#include "camel-vtrash-folder.h"
 #include "camel-string-utils.h"
 
 #define d(x)
 
-static const gchar *unread_str = " (and\n  \n     (match-all (not (system-flag  \"Seen\")))\n    \n  )\n;  (or\n  \n     (match-all (not (system-flag  \"Seen\")))\n    \n  )\n; (match-threads \"all\"  (and\n  \n     (match-all (not (system-flag  \"Seen\")))\n    \n  )\n)\n;  (match-threads \"all\"  (or\n  \n     (match-all (not (system-flag  \"Seen\")))\n    \n  )\n)\n;";
-
 G_DEFINE_TYPE (CamelVeeSummary, camel_vee_summary, CAMEL_TYPE_FOLDER_SUMMARY)
 
 static void
@@ -142,7 +141,6 @@ static gboolean
 vee_info_set_user_flag (CamelMessageInfo *mi, const gchar *name, gboolean value)
 {
 	gint res = FALSE;
-	gboolean hacked_unread_folder = FALSE;
 	CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;
 
 	if (camel_debug("vfolderexp"))
@@ -151,24 +149,17 @@ vee_info_set_user_flag (CamelMessageInfo *mi, const gchar *name, gboolean value)
 			camel_folder_get_full_name (mi->summary->folder),
 			g_strescape (vf->expression, ""));
 
-	if (camel_vee_folder_get_unread_vfolder (vf) == -1)
-		camel_vee_summary_load_check_unread_vfolder (CAMEL_VEE_SUMMARY (mi->summary));
-
-	if (camel_vee_folder_get_unread_vfolder (vf) == 1)
-		hacked_unread_folder = TRUE;
-
 	if (mi->uid) {
 		CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
 		HANDLE_NULL_INFO (FALSE);
 
-		if (hacked_unread_folder)
-			camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);
+		/* ignore changes done in the folder itself,
+		   unless it's a vTrash or vJunk folder */
+		if (!CAMEL_IS_VTRASH_FOLDER (vf))
+			camel_vee_folder_ignore_next_changed_event (vf, rmi->summary->folder);
 
 		res = camel_message_info_set_user_flag (rmi, name, value);
 
-		if (hacked_unread_folder)
-			camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);
-
 		camel_message_info_free (rmi);
 	}
 
@@ -183,6 +174,12 @@ vee_info_set_user_tag (CamelMessageInfo *mi, const gchar *name, const gchar *val
 	if (mi->uid) {
 		CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
 		HANDLE_NULL_INFO (FALSE);
+
+		/* ignore changes done in the folder itself,
+		   unless it's a vTrash or vJunk folder */
+		if (!CAMEL_IS_VTRASH_FOLDER (mi->summary->folder))
+			camel_vee_folder_ignore_next_changed_event ((CamelVeeFolder *) mi->summary->folder, rmi->summary->folder);
+
 		res = camel_message_info_set_user_tag (rmi, name, value);
 		camel_message_info_free (rmi);
 	}
@@ -194,37 +191,12 @@ vee_info_set_user_tag (CamelMessageInfo *mi, const gchar *name, const gchar *val
  * camel_vee_summary_load_check_unread_vfolder:
  *
  * Since: 2.26
+ *
+ * Deprecated: 3.2: Does nothing.
  **/
 void
 camel_vee_summary_load_check_unread_vfolder (CamelVeeSummary *vs)
 {
-	static gint only_once = FALSE;
-	static gchar *exp = NULL;
-	gboolean hacked_unread_folder = FALSE;
-	CamelVeeFolder *vf;
-
-	g_return_if_fail (vs != NULL);
-
-	vf = (CamelVeeFolder *) ((CamelFolderSummary *)vs)->folder;
-
-	/* HACK: Ugliest of all hacks. Its virtually not possible now
-	 * to maintain counts and the non matching uids of unread vfolder here.
-	 * So, I hardcode unread vfolder expression and hack it. */
-	if (!only_once) {
-		exp =  g_getenv("CAMEL_VFOLDER_UNREAD_EXP") ? g_strcompress(g_getenv("CAMEL_VFOLDER_UNREAD_EXP")) : NULL;
-		only_once = TRUE;
-	}
-
-	if (!exp || !*exp)
-		exp = g_strcompress (unread_str);
-
-	if (vf->expression && strstr (exp, vf->expression) &&  (vf->flags & CAMEL_STORE_VEE_FOLDER_SPECIAL) == 0)
-		hacked_unread_folder = TRUE;
-
-	if (hacked_unread_folder)
-		camel_vee_folder_set_unread_vfolder (vf, 1);
-	else
-		camel_vee_folder_set_unread_vfolder (vf, 0);
 }
 
 static gboolean
@@ -234,7 +206,6 @@ vee_info_set_flags (CamelMessageInfo *mi,
 {
 	gint res = FALSE;
 	CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;
-	gboolean hacked_unread_folder = FALSE;
 
 	if (camel_debug("vfolderexp"))
 		printf (
@@ -242,68 +213,32 @@ vee_info_set_flags (CamelMessageInfo *mi,
 			camel_folder_get_full_name (mi->summary->folder),
 			g_strescape (vf->expression, ""));
 
-	if (camel_vee_folder_get_unread_vfolder (vf) == -1)
-		camel_vee_summary_load_check_unread_vfolder (CAMEL_VEE_SUMMARY (mi->summary));
-
-	if (camel_vee_folder_get_unread_vfolder (vf) == 1)
-		hacked_unread_folder = TRUE;
-
 	if (mi->uid) {
-		guint32 old_visible, visible, old_unread;
 		CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
-		CamelVeeSummary *vsummary = (CamelVeeSummary *)mi->summary;
 
 		HANDLE_NULL_INFO (FALSE);
 
-		old_visible = rmi->summary->visible_count;
-		old_unread = mi->summary->unread_count;
 		camel_folder_summary_update_counts_by_flags (mi->summary, camel_message_info_flags (rmi), TRUE);
 
-		if (hacked_unread_folder)
-			camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);
+		/* ignore changes done in the folder itself,
+		   unless it's a vTrash or vJunk folder */
+		if (!CAMEL_IS_VTRASH_FOLDER (vf))
+			camel_vee_folder_ignore_next_changed_event (vf, rmi->summary->folder);
 
 		camel_folder_freeze (rmi->summary->folder);
 		res = camel_message_info_set_flags (rmi, flags, set);
 		((CamelVeeMessageInfo *) mi)->old_flags = camel_message_info_flags (rmi);
 		camel_folder_thaw (rmi->summary->folder);
 
-		if (hacked_unread_folder)
-			camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder);
-
-		visible = rmi->summary->visible_count;
-
 		/* Keep the summary in sync */
 		camel_folder_summary_update_counts_by_flags (mi->summary, camel_message_info_flags (rmi), FALSE);
 
-		if (hacked_unread_folder && !vsummary->fake_visible_count)
-			vsummary->fake_visible_count = mi->summary->visible_count;
-
-		if (vsummary->fake_visible_count || hacked_unread_folder)
-			vsummary->fake_visible_count += visible - old_visible;
-
 		d(printf("VF %d %d %d %d %d\n", mi->summary->unread_count, mi->summary->deleted_count, mi->summary->junk_count, mi->summary->junk_not_deleted_count, mi->summary->visible_count));
 
-		/* This is where the ugly-created-hack is used */
-		if (hacked_unread_folder && mi->summary->unread_count - old_unread != 0) {
+		if (res && mi->summary && mi->summary->folder) {
 			CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
-			GPtrArray *match, *array;
-
-			camel_folder_change_info_change_uid (changes, mi->uid);
-
-			array = g_ptr_array_new ();
-			g_ptr_array_add (array, (gpointer)rmi->uid);
-
-			match = camel_folder_search_by_uids (rmi->summary->folder, vf->expression, array, NULL);
-			if ((match && !match->len) || !match) {
-				vsummary->fake_visible_count--;
-			} else {
-				vsummary->fake_visible_count++;
-			}
-
-			g_ptr_array_free (array, TRUE);
-			if (match)
-				camel_folder_search_free (rmi->summary->folder, match);
 
+			camel_folder_change_info_change_uid (changes, camel_message_info_uid (mi));
 			camel_folder_changed (mi->summary->folder, changes);
 			camel_folder_change_info_free (changes);
 		}



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