[evolution] Bug #223309 - Add "Include Subfolders" to "Search Folder Sources"



commit 0c881254de455c77032b24d419bdabe7a4b5adfd
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jul 11 16:38:27 2012 +0200

    Bug #223309 - Add "Include Subfolders" to "Search Folder Sources"

 libemail-engine/mail-vfolder.c   |  245 ++++++++++++++++++++++++++------------
 libemail-utils/em-vfolder-rule.c |   93 +++++++++++++--
 libemail-utils/em-vfolder-rule.h |   12 ++-
 mail/em-vfolder-editor-rule.c    |   76 +++++++++++--
 mail/mail-vfolder-ui.c           |   13 ++-
 5 files changed, 340 insertions(+), 99 deletions(-)
---
diff --git a/libemail-engine/mail-vfolder.c b/libemail-engine/mail-vfolder.c
index 08e6e22..233e6a0 100644
--- a/libemail-engine/mail-vfolder.c
+++ b/libemail-engine/mail-vfolder.c
@@ -60,6 +60,59 @@ static void rule_changed (EFilterRule *rule, CamelFolder *folder);
 
 /* ********************************************************************** */
 
+static GList *
+vfolder_get_include_subfolders_uris (EMailSession *session,
+				     const gchar *base_uri,
+				     GCancellable *cancellable)
+{
+	GList *uris = NULL;
+	CamelStore *store = NULL;
+	gchar *folder_name = NULL;
+	CamelFolderInfo *fi;
+	const CamelFolderInfo *cur;
+
+	g_return_val_if_fail (session != NULL, NULL);
+	g_return_val_if_fail (base_uri != NULL, NULL);
+	g_return_val_if_fail (*base_uri == '*', NULL);
+
+	if (!e_mail_folder_uri_parse (CAMEL_SESSION (session), base_uri + 1, &store, &folder_name, NULL))
+		return NULL;
+
+	fi = camel_store_get_folder_info_sync (store, folder_name,
+		CAMEL_STORE_FOLDER_INFO_RECURSIVE, cancellable, NULL);
+	cur = fi;
+	while (cur) {
+		if ((cur->flags & CAMEL_FOLDER_NOSELECT) == 0) {
+			gchar *fi_uri = e_mail_folder_uri_build (store, cur->full_name);
+
+			if (fi_uri)
+				uris = g_list_prepend (uris, fi_uri);
+		}
+
+		/* move to the next fi */
+		if (cur->child) {
+			cur = cur->child;
+		} else if (cur->next) {
+			cur = cur->next;
+		} else {
+			while (cur && !cur->next) {
+				cur = cur->parent;
+			}
+
+			if (cur)
+				cur = cur->next;
+		}
+	}
+
+	if (fi)
+		camel_store_free_folder_info (store, fi);
+
+	g_object_unref (store);
+	g_free (folder_name);
+
+	return g_list_reverse (uris);
+}
+
 struct _setup_msg {
 	MailMsg base;
 
@@ -67,7 +120,6 @@ struct _setup_msg {
 	CamelFolder *folder;
 	gchar *query;
 	GList *sources_uri;
-	GList *sources_folder;
 };
 
 static gchar *
@@ -88,34 +140,42 @@ vfolder_setup_exec (struct _setup_msg *m,
 
 	camel_vee_folder_set_expression ((CamelVeeFolder *) m->folder, m->query);
 
-	l = m->sources_uri;
-	while (l && !vfolder_shutdown) {
-		d(printf(" Adding uri: %s\n", (gchar *)l->data));
+	for (l = m->sources_uri;
+	     l && !vfolder_shutdown && !g_cancellable_is_cancelled (cancellable);
+	     l = l->next) {
+		const gchar *uri = l->data;
 
-		/* FIXME Not passing a GCancellable or GError here. */
-		folder = e_mail_session_uri_to_folder_sync (
-			m->session, l->data, 0, NULL, NULL);
-		if (folder != NULL)
-			list = g_list_append (list, folder);
-		l = l->next;
-	}
+		d(printf(" Adding uri: %s\n", uri));
 
-	l = m->sources_folder;
-	while (l && !vfolder_shutdown) {
-		g_object_ref (l->data);
-		list = g_list_append (list, l->data);
-		l = l->next;
+		if (!uri || !*uri || !uri[1])
+			continue;
+
+		if (*uri == '*') {
+			/* include folder and its subfolders */
+			GList *uris, *iter;
+
+			uris = vfolder_get_include_subfolders_uris (m->session, uri, cancellable);
+			for (iter = uris; iter; iter = iter->next) {
+				const gchar *fi_uri = iter->data;
+
+				folder = e_mail_session_uri_to_folder_sync (
+					m->session, fi_uri, 0, cancellable, NULL);
+				if (folder != NULL)
+					list = g_list_append (list, folder);
+			}
+
+			g_list_free_full (uris, g_free);
+		} else {
+			folder = e_mail_session_uri_to_folder_sync (m->session, l->data, 0, cancellable, NULL);
+			if (folder != NULL)
+				list = g_list_append (list, folder);
+		}
 	}
 
-	if (!vfolder_shutdown)
+	if (!vfolder_shutdown && !g_cancellable_is_cancelled (cancellable))
 		camel_vee_folder_set_folders ((CamelVeeFolder *) m->folder, list, cancellable);
 
-	l = list;
-	while (l) {
-		g_object_unref (l->data);
-		l = l->next;
-	}
-	g_list_free (list);
+	g_list_free_full (list, g_object_unref);
 }
 
 static void
@@ -126,27 +186,12 @@ vfolder_setup_done (struct _setup_msg *m)
 static void
 vfolder_setup_free (struct _setup_msg *m)
 {
-	GList *l;
-
 	camel_folder_thaw (m->folder);
 
 	g_object_unref (m->session);
 	g_object_unref (m->folder);
 	g_free (m->query);
-
-	l = m->sources_uri;
-	while (l) {
-		g_free (l->data);
-		l = l->next;
-	}
-	g_list_free (m->sources_uri);
-
-	l = m->sources_folder;
-	while (l) {
-		g_object_unref (l->data);
-		l = l->next;
-	}
-	g_list_free (m->sources_folder);
+	g_list_free_full (m->sources_uri, g_free);
 }
 
 static MailMsgInfo vfolder_setup_info = {
@@ -162,8 +207,7 @@ static gint
 vfolder_setup (EMailSession *session,
                CamelFolder *folder,
                const gchar *query,
-               GList *sources_uri,
-               GList *sources_folder)
+               GList *sources_uri)
 {
 	struct _setup_msg *m;
 	gint id;
@@ -173,7 +217,6 @@ vfolder_setup (EMailSession *session,
 	m->folder = g_object_ref (folder);
 	m->query = g_strdup (query);
 	m->sources_uri = sources_uri;
-	m->sources_folder = sources_folder;
 
 	camel_folder_freeze (m->folder);
 
@@ -185,6 +228,27 @@ vfolder_setup (EMailSession *session,
 
 /* ********************************************************************** */
 
+static void
+vfolder_add_remove_one (GList *vfolders,
+			gboolean remove,
+			CamelFolder *folder,
+			GCancellable *cancellable)
+{
+	GList *iter;
+
+	for (iter = vfolders; iter && !vfolder_shutdown; iter = iter->next) {
+		CamelVeeFolder *vfolder = CAMEL_VEE_FOLDER (iter->data);
+
+		if (!vfolder)
+			continue;
+
+		if (remove)
+			camel_vee_folder_remove_folder (vfolder, folder, cancellable);
+		else
+			camel_vee_folder_add_folder (vfolder, folder, cancellable);
+	}
+}
+
 struct _adduri_msg {
 	MailMsg base;
 
@@ -229,7 +293,6 @@ vfolder_adduri_exec (struct _adduri_msg *m,
                      GCancellable *cancellable,
                      GError **error)
 {
-	GList *l;
 	CamelFolder *folder = NULL;
 	MailFolderCache *folder_cache;
 
@@ -241,29 +304,39 @@ vfolder_adduri_exec (struct _adduri_msg *m,
 	/* we dont try lookup the cache if we are removing it, its no longer there */
 
 	if (!m->remove &&
-	    !mail_folder_cache_get_folder_from_uri (folder_cache, m->uri, NULL)) {
+	    !mail_folder_cache_get_folder_from_uri (folder_cache, m->uri[0] == '*' ? m->uri + 1 : m->uri, NULL)) {
 		g_warning (
 			"Folder '%s' disappeared while I was "
 			"adding/removing it to/from my vfolder", m->uri);
 		return;
 	}
 
-	/* always pick fresh folders - they are
-	 * from CamelStore's folders bag anyway */
-	folder = e_mail_session_uri_to_folder_sync (
-		m->session, m->uri, 0, cancellable, error);
-
-	if (folder != NULL) {
-		l = m->folders;
-		while (l && !vfolder_shutdown) {
-			if (m->remove)
-				camel_vee_folder_remove_folder (
-					CAMEL_VEE_FOLDER (l->data), folder, cancellable);
-			else
-				camel_vee_folder_add_folder ((CamelVeeFolder *) l->data, folder, cancellable);
-			l = l->next;
+	if (m->uri[0] == '*') {
+		GList *uris, *iter;
+
+		uris = vfolder_get_include_subfolders_uris (m->session, m->uri, cancellable);
+		for (iter = uris; iter; iter = iter->next) {
+			const gchar *fi_uri = iter->data;
+
+			folder = e_mail_session_uri_to_folder_sync (
+				m->session, fi_uri, 0, cancellable, NULL);
+			if (folder != NULL) {
+				vfolder_add_remove_one (m->folders, m->remove, folder, cancellable);
+				g_object_unref (folder);
+			}
+		}
+
+		g_list_free_full (uris, g_free);
+	} else {
+		/* always pick fresh folders - they are
+		 * from CamelStore's folders bag anyway */
+		folder = e_mail_session_uri_to_folder_sync (
+			m->session, m->uri, 0, cancellable, error);
+
+		if (folder != NULL) {
+			vfolder_add_remove_one (m->folders, m->remove, folder, cancellable);
+			g_object_unref (folder);
 		}
-		g_object_unref (folder);
 	}
 }
 
@@ -359,10 +432,11 @@ mail_vfolder_add_folder (CamelStore *store,
 	CamelService *service;
 	CamelSession *session;
 	EFilterRule *rule;
+	EMVFolderRule *vrule;
 	const gchar *source;
 	CamelVeeFolder *vf;
 	CamelProvider *provider;
-	GList *folders = NULL;
+	GList *folders = NULL, *folders_include_subfolders = NULL;
 	gint remote;
 	gchar *uri;
 
@@ -395,18 +469,20 @@ mail_vfolder_add_folder (CamelStore *store,
 			d(printf("invalid rule (%p): rule->name is set to NULL\n", rule));
 			continue;
 		}
+
+		vrule = (EMVFolderRule *) rule;
+
 		/* Don't auto-add any sent/drafts folders etc,
 		 * they must be explictly listed as a source. */
 		if (rule->source
 		    && !CAMEL_IS_VEE_STORE (store)
-		    && ((em_vfolder_rule_get_with ((EMVFolderRule *) rule) == EM_VFOLDER_RULE_WITH_LOCAL && !remote)
-			|| (em_vfolder_rule_get_with ((EMVFolderRule *) rule) == EM_VFOLDER_RULE_WITH_REMOTE_ACTIVE && remote)
-			|| (em_vfolder_rule_get_with ((EMVFolderRule *) rule) == EM_VFOLDER_RULE_WITH_LOCAL_REMOTE_ACTIVE)))
+		    && ((em_vfolder_rule_get_with (vrule) == EM_VFOLDER_RULE_WITH_LOCAL && !remote)
+			|| (em_vfolder_rule_get_with (vrule) == EM_VFOLDER_RULE_WITH_REMOTE_ACTIVE && remote)
+			|| (em_vfolder_rule_get_with (vrule) == EM_VFOLDER_RULE_WITH_LOCAL_REMOTE_ACTIVE)))
 			found = TRUE;
 
 		source = NULL;
-		while (!found && (source = em_vfolder_rule_next_source (
-				(EMVFolderRule *) rule, source))) {
+		while (!found && (source = em_vfolder_rule_next_source (vrule, source))) {
 			found = e_mail_folder_uri_equal (session, uri, source);
 		}
 
@@ -417,7 +493,11 @@ mail_vfolder_add_folder (CamelStore *store,
 				continue;
 			}
 			g_object_ref (vf);
-			folders = g_list_prepend (folders, vf);
+
+			if (em_vfolder_rule_source_get_include_subfolders (vrule, uri))
+				folders_include_subfolders = g_list_prepend (folders_include_subfolders, vf);
+			else
+				folders = g_list_prepend (folders, vf);
 		}
 	}
 
@@ -429,6 +509,16 @@ done:
 			E_MAIL_SESSION (session),
 			uri, folders, remove);
 
+	if (folders_include_subfolders) {
+		gchar *exuri = g_strconcat ("*", uri, NULL);
+
+		vfolder_adduri (
+			E_MAIL_SESSION (session),
+			exuri, folders_include_subfolders, remove);
+
+		g_free (exuri);
+	}
+
 	g_free (uri);
 }
 
@@ -671,10 +761,9 @@ static void context_rule_added (ERuleContext *ctx, EFilterRule *rule, EMailSessi
 static void
 rule_add_sources (EMailSession *session,
                   GQueue *queue,
-                  GList **sources_folderp,
-                  GList **sources_urip)
+                  GList **sources_urip,
+		  EMVFolderRule *rule)
 {
-	GList *sources_folder = *sources_folderp;
 	GList *sources_uri = *sources_urip;
 	MailFolderCache *folder_cache;
 	GList *head, *link;
@@ -688,11 +777,14 @@ rule_add_sources (EMailSession *session,
 		/* always pick fresh folders - they are
 		 * from CamelStore's folders bag anyway */
 		if (mail_folder_cache_get_folder_from_uri (folder_cache, uri, NULL)) {
-			sources_uri = g_list_append (sources_uri, g_strdup (uri));
+			/* "tag" uris with subfolders with a star prefix */
+			if (!rule || !em_vfolder_rule_source_get_include_subfolders (rule, uri))
+				sources_uri = g_list_prepend (sources_uri, g_strdup (uri));
+			else
+				sources_uri = g_list_prepend (sources_uri, g_strconcat ("*", uri, NULL));
 		}
 	}
 
-	*sources_folderp = sources_folder;
 	*sources_urip = sources_uri;
 }
 
@@ -713,7 +805,6 @@ rule_changed (EFilterRule *rule,
 	EMailSession *session;
 	CamelService *service;
 	GList *sources_uri = NULL;
-	GList *sources_folder = NULL;
 	GString *query;
 	const gchar *full_name;
 
@@ -764,7 +855,7 @@ rule_changed (EFilterRule *rule,
 		/* find any (currently available) folders, and add them to the ones to open */
 		rule_add_sources (
 			session, em_vfolder_rule_get_sources ((EMVFolderRule *) rule),
-			&sources_folder, &sources_uri);
+			&sources_uri, (EMVFolderRule *) rule);
 	}
 
 	G_LOCK (vfolder);
@@ -778,8 +869,7 @@ rule_changed (EFilterRule *rule,
 		cache = e_mail_session_get_folder_cache (session);
 		mail_folder_cache_get_local_folder_uris (cache, &queue);
 
-		rule_add_sources (
-			session, &queue, &sources_folder, &sources_uri);
+		rule_add_sources (session, &queue, &sources_uri, NULL);
 
 		while (!g_queue_is_empty (&queue))
 			g_free (g_queue_pop_head (&queue));
@@ -794,8 +884,7 @@ rule_changed (EFilterRule *rule,
 		cache = e_mail_session_get_folder_cache (session);
 		mail_folder_cache_get_remote_folder_uris (cache, &queue);
 
-		rule_add_sources (
-			session, &queue, &sources_folder, &sources_uri);
+		rule_add_sources (session, &queue, &sources_uri, NULL);
 
 		while (!g_queue_is_empty (&queue))
 			g_free (g_queue_pop_head (&queue));
@@ -806,7 +895,7 @@ rule_changed (EFilterRule *rule,
 	query = g_string_new("");
 	e_filter_rule_build_code (rule, query);
 
-	vfolder_setup (session, folder, query->str, sources_uri, sources_folder);
+	vfolder_setup (session, folder, query->str, sources_uri);
 
 	g_string_free (query, TRUE);
 }
diff --git a/libemail-utils/em-vfolder-rule.c b/libemail-utils/em-vfolder-rule.c
index 237c99d..ac77e75 100644
--- a/libemail-utils/em-vfolder-rule.c
+++ b/libemail-utils/em-vfolder-rule.c
@@ -49,6 +49,7 @@ struct _EMVFolderRulePrivate {
 	em_vfolder_rule_with_t with;
 	GQueue sources;		/* uri's of the source folders */
 	gboolean autoupdate;
+	GHashTable *include_subfolders;
 };
 
 static gint validate (EFilterRule *, EAlert **alert);
@@ -80,6 +81,8 @@ vfolder_rule_finalize (GObject *object)
 	while ((uri = g_queue_pop_head (&rule->priv->sources)) != NULL)
 		g_free (uri);
 
+	g_hash_table_destroy (rule->priv->include_subfolders);
+
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (em_vfolder_rule_parent_class)->finalize (object);
 }
@@ -110,11 +113,15 @@ em_vfolder_rule_init (EMVFolderRule *rule)
 	rule->priv = EM_VFOLDER_RULE_GET_PRIVATE (rule);
 	rule->priv->with = EM_VFOLDER_RULE_WITH_SPECIFIC;
 	rule->priv->autoupdate = TRUE;
+	/* it's using pointers from priv::sources, and those
+	   included has include_subfolders set to true */
+	rule->priv->include_subfolders = g_hash_table_new (g_direct_hash, g_direct_equal);
+
 	rule->rule.source = g_strdup ("incoming");
 }
 
 EFilterRule *
-em_vfolder_rule_new ()
+em_vfolder_rule_new (void)
 {
 	return g_object_new (
 		EM_TYPE_VFOLDER_RULE, NULL);
@@ -159,6 +166,7 @@ em_vfolder_rule_remove_source (EMVFolderRule *rule,
 	found =(gchar *) em_vfolder_rule_find_source (rule, uri);
 	if (found != NULL) {
 		g_queue_remove (&rule->priv->sources, found);
+		g_hash_table_remove (rule->priv->include_subfolders, found);
 		g_free (found);
 		e_filter_rule_emit_changed (E_FILTER_RULE (rule));
 	}
@@ -183,6 +191,64 @@ em_vfolder_rule_next_source (EMVFolderRule *rule,
 	return (link != NULL) ? link->data : NULL;
 }
 
+GQueue *
+em_vfolder_rule_get_sources (EMVFolderRule *rule)
+{
+	g_return_val_if_fail (rule != NULL, NULL);
+	
+	return &rule->priv->sources;
+}
+
+static gboolean
+check_queue_has_key (gpointer key,
+		     gpointer value,
+		     gpointer user_data)
+{
+	EMVFolderRule *rule = user_data;
+
+	g_return_val_if_fail (rule != NULL, FALSE);
+
+	return g_queue_find (&rule->priv->sources, key) == NULL;
+}
+
+void
+em_vfolder_rule_sources_changed (EMVFolderRule *rule)
+{
+	g_return_if_fail (rule != NULL);
+
+	g_hash_table_foreach_remove (rule->priv->include_subfolders,
+		check_queue_has_key, rule);
+}
+
+gboolean
+em_vfolder_rule_source_get_include_subfolders (EMVFolderRule *rule,
+					       const gchar *source)
+{
+	g_return_val_if_fail (rule != NULL, FALSE);
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	source = em_vfolder_rule_find_source (rule, source);
+
+	return source && g_hash_table_lookup (rule->priv->include_subfolders, source);
+}
+
+void
+em_vfolder_rule_source_set_include_subfolders (EMVFolderRule *rule,
+					       const gchar *source,
+					       gboolean include_subfolders)
+{
+	g_return_if_fail (rule != NULL);
+	g_return_if_fail (source != NULL);
+
+	source = em_vfolder_rule_find_source (rule, source);
+	g_return_if_fail (source != NULL);
+
+	if (include_subfolders)
+		g_hash_table_insert (rule->priv->include_subfolders, (gpointer) source, GINT_TO_POINTER (1));
+	else
+		g_hash_table_remove (rule->priv->include_subfolders, (gpointer) source);
+}
+
 void
 em_vfolder_rule_set_with (EMVFolderRule *rule,
 			  em_vfolder_rule_with_t with)
@@ -200,14 +266,6 @@ em_vfolder_rule_get_with (EMVFolderRule *rule)
 	return rule->priv->with;
 }
 
-GQueue *
-em_vfolder_rule_get_sources (EMVFolderRule *rule)
-{
-	g_return_val_if_fail (rule != NULL, NULL);
-	
-	return &rule->priv->sources;
-}
-
 void
 em_vfolder_rule_set_autoupdate	(EMVFolderRule *rule,
 				 gboolean autoupdate)
@@ -306,6 +364,8 @@ xml_encode (EFilterRule *fr)
 
 		work = xmlNewNode (NULL, (const guchar *) "folder");
 		xmlSetProp (work, (const guchar *) "uri", (guchar *) uri);
+		xmlSetProp (work, (const guchar *) "include-subfolders", (guchar *)
+			(em_vfolder_rule_source_get_include_subfolders (vr, uri) ? "true" : "false"));
 		xmlAddChild (set, work);
 	}
 
@@ -368,7 +428,17 @@ xml_decode (EFilterRule *fr,
 				if (!strcmp((gchar *)work->name, "folder")) {
 					tmp = (gchar *)xmlGetProp(work, (const guchar *)"uri");
 					if (tmp) {
+						gchar *include_subfolders;
+
 						g_queue_push_tail (&vr->priv->sources, g_strdup (tmp));
+
+						include_subfolders = (gchar *) xmlGetProp (work, (const guchar *) "include-subfolders");
+						if (include_subfolders) {
+							em_vfolder_rule_source_set_include_subfolders (vr,
+								tmp, g_str_equal (include_subfolders, "true"));
+							xmlFree (include_subfolders);
+						}
+
 						xmlFree (tmp);
 					}
 				}
@@ -394,10 +464,15 @@ rule_copy (EFilterRule *dest,
 	while ((uri = g_queue_pop_head (&vdest->priv->sources)) != NULL)
 		g_free (uri);
 
+	em_vfolder_rule_sources_changed	(vdest);
+
 	head = g_queue_peek_head_link (&vsrc->priv->sources);
 	for (link = head; link != NULL; link = g_list_next (link)) {
 		const gchar *uri = link->data;
 		g_queue_push_tail (&vdest->priv->sources, g_strdup (uri));
+
+		em_vfolder_rule_source_set_include_subfolders (vdest, uri,
+			em_vfolder_rule_source_get_include_subfolders (vsrc, uri));
 	}
 
 	vdest->priv->with = vsrc->priv->with;
diff --git a/libemail-utils/em-vfolder-rule.h b/libemail-utils/em-vfolder-rule.h
index f6dbfa0..60f3004 100644
--- a/libemail-utils/em-vfolder-rule.h
+++ b/libemail-utils/em-vfolder-rule.h
@@ -71,7 +71,7 @@ struct _EMVFolderRuleClass {
 };
 
 GType		em_vfolder_rule_get_type	(void);
-EFilterRule *	em_vfolder_rule_new		();
+EFilterRule *	em_vfolder_rule_new		(void);
 void		em_vfolder_rule_add_source	(EMVFolderRule *rule,
 						 const gchar *uri);
 void		em_vfolder_rule_remove_source	(EMVFolderRule *rule,
@@ -80,11 +80,19 @@ const gchar *	em_vfolder_rule_find_source	(EMVFolderRule *rule,
 						 const gchar *uri);
 const gchar *	em_vfolder_rule_next_source	(EMVFolderRule *rule,
 						 const gchar *last);
+GQueue *	em_vfolder_rule_get_sources	(EMVFolderRule *rule);
+void		em_vfolder_rule_sources_changed	(EMVFolderRule *rule);
+gboolean	em_vfolder_rule_source_get_include_subfolders
+						(EMVFolderRule *rule,
+						 const gchar *source);
+void		em_vfolder_rule_source_set_include_subfolders
+						(EMVFolderRule *rule,
+						 const gchar *source,
+						 gboolean include_subfolders);
 void		em_vfolder_rule_set_with	(EMVFolderRule *rule,
 						 em_vfolder_rule_with_t with);
 em_vfolder_rule_with_t
 		em_vfolder_rule_get_with	(EMVFolderRule *rule);
-GQueue *	em_vfolder_rule_get_sources	(EMVFolderRule *rule);
 void		em_vfolder_rule_set_autoupdate	(EMVFolderRule *rule,
 						 gboolean autoupdate);
 gboolean	em_vfolder_rule_get_autoupdate	(EMVFolderRule *rule);
diff --git a/mail/em-vfolder-editor-rule.c b/mail/em-vfolder-editor-rule.c
index b1fdadd..78fbd46 100644
--- a/mail/em-vfolder-editor-rule.c
+++ b/mail/em-vfolder-editor-rule.c
@@ -211,7 +211,7 @@ struct _source_data {
 	ERuleContext *rc;
 	EMVFolderRule *vr;
 	GtkListStore *model;
-	GtkTreeView *list;
+	GtkTreeView *tree_view;
 	GtkWidget *source_selector;
 	GtkWidget *buttons[BUTTON_LAST];
 };
@@ -221,7 +221,7 @@ set_sensitive (struct _source_data *data)
 {
 	GtkTreeSelection *selection;
 
-	selection = gtk_tree_view_get_selection (data->list);
+	selection = gtk_tree_view_get_selection (data->tree_view);
 
 	gtk_widget_set_sensitive (
 		GTK_WIDGET (data->buttons[BUTTON_ADD]), TRUE);
@@ -262,6 +262,39 @@ autoupdate_toggled_cb (GtkToggleButton *toggle,
 }
 
 static void
+include_subfolders_toggled_cb (GtkCellRendererToggle *cell_renderer,
+			       const gchar *path_string,
+			       struct _source_data *data)
+{
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	gtk_cell_renderer_toggle_set_active (cell_renderer,
+		!gtk_cell_renderer_toggle_get_active (cell_renderer));
+
+	model = gtk_tree_view_get_model (data->tree_view);
+	path = gtk_tree_path_new_from_string (path_string);
+
+	if (gtk_tree_model_get_iter (model, &iter, path)) {
+		gchar *source = NULL;
+
+		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+			2, gtk_cell_renderer_toggle_get_active (cell_renderer),
+			-1);
+
+		gtk_tree_model_get (model, &iter, 1, &source, -1);
+		if (source) {
+			em_vfolder_rule_source_set_include_subfolders (data->vr, source,
+				gtk_cell_renderer_toggle_get_active (cell_renderer));
+			g_free (source);
+		}
+	}
+
+	gtk_tree_path_free (path);
+}
+
+static void
 vfr_folder_response (EMFolderSelector *selector,
                      gint button,
                      struct _source_data *data)
@@ -282,8 +315,9 @@ vfr_folder_response (EMFolderSelector *selector,
 		GHashTable *known_uris;
 		GtkTreeIter iter;
 		GtkTreeSelection *selection;
+		gboolean changed = FALSE;
 
-		selection = gtk_tree_view_get_selection (data->list);
+		selection = gtk_tree_view_get_selection (data->tree_view);
 		gtk_tree_selection_unselect_all (selection);
 
 		known_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
@@ -309,6 +343,7 @@ vfr_folder_response (EMFolderSelector *selector,
 
 			g_hash_table_insert (known_uris, g_strdup (uri), GINT_TO_POINTER (1));
 
+			changed = TRUE;
 			g_queue_push_tail (em_vfolder_rule_get_sources (data->vr), g_strdup (uri));
 
 			markup = e_mail_folder_uri_to_markup (session, uri, NULL);
@@ -322,6 +357,8 @@ vfr_folder_response (EMFolderSelector *selector,
 		}
 
 		g_hash_table_destroy (known_uris);
+		if (changed)
+			em_vfolder_rule_sources_changed (data->vr);
 
 		set_sensitive (data);
 	}
@@ -377,7 +414,7 @@ source_remove (GtkWidget *widget,
 	gint index = 0, first_selected = -1, removed;
 	gint n;
 
-	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->list));
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->tree_view));
 	to_remove = g_hash_table_new (g_direct_hash, g_direct_equal);
 
 	source = NULL;
@@ -436,7 +473,7 @@ source_remove (GtkWidget *widget,
 		gtk_tree_path_append_index (path, index);
 		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (data->model), &iter, path)) {
 			gtk_tree_selection_select_iter (selection, &iter);
-			gtk_tree_view_set_cursor (data->list, path, NULL, FALSE);
+			gtk_tree_view_set_cursor (data->tree_view, path, NULL, FALSE);
 		}
 		gtk_tree_path_free (path);
 	}
@@ -454,6 +491,7 @@ get_widget (EFilterRule *fr,
 	GtkWidget *autoupdate;
 	GtkListStore *model;
 	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
 	struct _source_data *data;
 	const gchar *source;
 	gchar *tmp;
@@ -538,13 +576,29 @@ get_widget (EFilterRule *fr,
 		NULL);
 	gtk_container_add (GTK_CONTAINER (hgrid), scrolled_window);
 
-	model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+	model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
 	renderer = gtk_cell_renderer_text_new ();
 	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
 	gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
 		-1, "column", renderer, "markup", 0, NULL);
 
+	renderer = gtk_cell_renderer_toggle_new ();
+	column = gtk_tree_view_column_new_with_attributes (
+		"include subfolders", renderer, "active", 2, NULL);
+	g_signal_connect (renderer, "toggled", G_CALLBACK (include_subfolders_toggled_cb), data);
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_object_set (G_OBJECT (renderer),
+		"editable", FALSE,
+		"text", _("include subfolders"),
+		NULL);
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_insert_column (GTK_TREE_VIEW (tree_view), column, -1);
+
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
+	gtk_tree_view_column_set_expand (column, TRUE);
+
 	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), tree_view);
 
 	vgrid = gtk_grid_new ();
@@ -566,7 +620,7 @@ get_widget (EFilterRule *fr,
 	gtk_container_add (GTK_CONTAINER (vgrid), data->buttons[BUTTON_ADD]);
 	gtk_container_add (GTK_CONTAINER (vgrid), data->buttons[BUTTON_REMOVE]);
 
-	data->list = GTK_TREE_VIEW (tree_view);
+	data->tree_view = GTK_TREE_VIEW (tree_view);
 	data->model = model;
 
 	session = em_vfolder_editor_context_get_session (EM_VFOLDER_EDITOR_CONTEXT (rc));
@@ -579,11 +633,15 @@ get_widget (EFilterRule *fr,
 			CAMEL_SESSION (session), source, NULL);
 
 		gtk_list_store_append (data->model, &iter);
-		gtk_list_store_set (data->model, &iter, 0, markup, 1, source, -1);
+		gtk_list_store_set (data->model, &iter,
+			0, markup,
+			1, source,
+			2, em_vfolder_rule_source_get_include_subfolders (vr, source),
+			-1);
 		g_free (markup);
 	}
 
-	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->list));
+	selection = gtk_tree_view_get_selection (data->tree_view);
 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
 
 	g_signal_connect (
diff --git a/mail/mail-vfolder-ui.c b/mail/mail-vfolder-ui.c
index 14b55d1..d9b68ad 100644
--- a/mail/mail-vfolder-ui.c
+++ b/mail/mail-vfolder-ui.c
@@ -256,6 +256,16 @@ vfolder_clone_rule (EMailSession *session,
 	return rule;
 }
 
+static void
+release_rule_notify_cb (gpointer rule)
+{
+	/* disconnect the "changed" signal */
+	g_signal_handlers_disconnect_by_data (rule,
+		g_object_get_data (rule, "editor-dlg"));
+	g_object_set_data (rule, "editor-dlg", NULL);
+	g_object_unref (rule);
+}
+
 /* adds a rule with a gui */
 void
 vfolder_gui_add_rule (EMVFolderRule *rule)
@@ -283,9 +293,10 @@ vfolder_gui_add_rule (EMVFolderRule *rule)
 	gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500);
 	gtk_box_pack_start (GTK_BOX (container), w, TRUE, TRUE, 0);
 	gtk_widget_show ((GtkWidget *) gd);
+	g_object_set_data (G_OBJECT (rule), "editor-dlg", gd);
 	g_object_set_data_full (
 		G_OBJECT (gd), "rule", rule,
-		(GDestroyNotify) g_object_unref);
+		release_rule_notify_cb);
 	g_signal_connect (
 		rule, "changed",
 		G_CALLBACK (new_rule_changed_cb), gd);



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