aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
authorMatt McCutchen <matt@mattmccutchen.net>2009-09-09 17:20:25 +0800
committerMilan Crha <mcrha@redhat.com>2009-09-09 17:20:25 +0800
commitf41979c499aa770e81441c66eb316abbcd8c4f7a (patch)
tree5632f063f976173046239332303aa9acb810743e /mail
parent8f3e43fb7d94f2b120b3e3e53e0af3dd7c5e248c (diff)
downloadgsoc2013-evolution-f41979c499aa770e81441c66eb316abbcd8c4f7a.tar.gz
gsoc2013-evolution-f41979c499aa770e81441c66eb316abbcd8c4f7a.tar.zst
gsoc2013-evolution-f41979c499aa770e81441c66eb316abbcd8c4f7a.zip
Bug #571881 - Make messages inherit labels from collapsed subtree
Diffstat (limited to 'mail')
-rw-r--r--mail/message-list.c347
1 files changed, 149 insertions, 198 deletions
diff --git a/mail/message-list.c b/mail/message-list.c
index 714768ef21..24390719ce 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -1136,57 +1136,57 @@ ml_tree_icon_at (ETreeModel *etm, ETreePath path, gpointer model_data)
return NULL;
}
-/* return true if there are any unread messages in the subtree */
-static gint
-subtree_unread(MessageList *ml, ETreePath node)
+static void
+for_node_and_subtree_if_collapsed (MessageList *ml, ETreePath node,
+ ETreePathFunc func, gpointer data)
{
- CamelMessageInfo *info;
+ ETreeModel *etm = ml->model;
ETreePath child;
- while (node) {
- info = e_tree_memory_node_get_data((ETreeMemory *)ml->model, node);
- g_return_val_if_fail (info != NULL, FALSE);
+ func (etm, node, data);
- if (!(camel_message_info_flags(info) & CAMEL_MESSAGE_SEEN))
- return TRUE;
-
- if ((child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->model), node)))
- if (subtree_unread(ml, child))
- return TRUE;
- node = e_tree_model_node_get_next (ml->model, node);
- }
- return FALSE;
+ child = e_tree_model_node_get_first_child (etm, node);
+ if (child && !e_tree_node_is_expanded (ml->tree, node))
+ e_tree_model_node_traverse (etm, node, func, data);
}
-static time_t
-subtree_latest(MessageList *ml, ETreePath node, gint sent)
+static gboolean
+unread_foreach (ETreeModel *etm, ETreePath node, gpointer data)
{
+ gboolean *saw_unread = data;
CamelMessageInfo *info;
- time_t latest = 0, date;
- ETreePath *child;
- while (node) {
- info = e_tree_memory_node_get_data((ETreeMemory *)ml->model, node);
- g_return_val_if_fail (info != NULL, 0);
+ info = e_tree_memory_node_get_data ((ETreeMemory *)etm, node);
+ g_return_val_if_fail (info != NULL, FALSE);
- if (sent)
- date = camel_message_info_date_sent(info);
- else
- date = camel_message_info_date_received(info);
+ if (!(camel_message_info_flags (info) & CAMEL_MESSAGE_SEEN))
+ *saw_unread = TRUE;
- if (latest == 0 || date > latest)
- latest = date;
+ return FALSE;
+}
- if ((child = e_tree_model_node_get_first_child (ml->model, node))) {
- date = subtree_latest(ml, child, sent);
- if (latest == 0 || (date != 0 && date > latest))
- latest = date;
- }
+struct LatestData {
+ gboolean sent;
+ time_t latest;
+};
- node = e_tree_model_node_get_next (ml->model, node);
- }
+static gboolean
+latest_foreach (ETreeModel *etm, ETreePath node, gpointer data)
+{
+ struct LatestData *ld = data;
+ CamelMessageInfo *info;
+ time_t date;
+
+ info = e_tree_memory_node_get_data ((ETreeMemory *)etm, node);
+ g_return_val_if_fail (info != NULL, FALSE);
- return latest;
+ date = ld->sent ? camel_message_info_date_sent (info)
+ : camel_message_info_date_received (info);
+
+ if (ld->latest == 0 || date > ld->latest)
+ ld->latest = date;
+
+ return FALSE;
}
static gchar *
@@ -1232,122 +1232,65 @@ sanitize_recipients (const gchar *string)
return g_string_free (recipients, FALSE);
}
-static gint
-get_all_labels (MessageList *message_list,
- CamelMessageInfo *msg_info,
- gchar **label_str,
- gboolean get_tags)
-{
- EShell *shell;
- EShellBackend *shell_backend;
- EShellSettings *shell_settings;
+struct LabelsData {
EMailLabelListStore *store;
- GtkTreeIter iter;
- GString *str;
- const gchar *property_name;
- const gchar *old_label;
- gchar *new_label;
- gint count = 0;
- const CamelFlag *flag;
-
- shell_backend = message_list_get_shell_backend (message_list);
- shell = e_shell_backend_get_shell (shell_backend);
- shell_settings = e_shell_get_shell_settings (shell);
-
- property_name = "mail-label-list-store";
- store = e_shell_settings_get_object (shell_settings, property_name);
-
- str = g_string_new ("");
-
- for (flag = camel_message_info_user_flags (msg_info); flag; flag = flag->next) {
- gchar *item;
-
- if (!e_mail_label_list_store_lookup (store, flag->name, &iter))
- continue;
-
- if (get_tags)
- item = e_mail_label_list_store_get_tag (store, &iter);
- else
- item = e_mail_label_list_store_get_name (store, &iter);
-
- if (str->len)
- g_string_append (str, ", ");
+ GHashTable *labels_tag2iter;
+};
- g_string_append (str, item);
- count++;
+static void
+add_label_if_known (struct LabelsData *ld, const gchar *tag)
+{
+ GtkTreeIter label_defn;
- g_free (item);
+ if (e_mail_label_list_store_lookup (ld->store, tag, &label_defn)) {
+ g_hash_table_insert (ld->labels_tag2iter,
+ /* Should be the same as the "tag" arg */
+ e_mail_label_list_store_get_tag (ld->store, &label_defn),
+ gtk_tree_iter_copy (&label_defn));
}
+}
- old_label = camel_message_info_user_tag (msg_info, "label");
- if (old_label == NULL)
- goto exit;
-
- /* Convert old-style labels ("<name>") to "$Label<name>". */
- new_label = g_alloca (strlen (old_label) + 10);
- g_stpcpy (g_stpcpy (new_label, "$Label"), old_label);
-
- if (e_mail_label_list_store_lookup (store, new_label, &iter)) {
- gchar *name = NULL;
+static gboolean
+add_all_labels_foreach (ETreeModel *etm, ETreePath node, gpointer data)
+{
+ struct LabelsData *ld = data;
+ CamelMessageInfo *msg_info;
+ const gchar *old_label;
+ gchar *new_label;
+ const CamelFlag *flag;
- if (str->len)
- g_string_append (str, ", ");
+ msg_info = e_tree_memory_node_get_data ((ETreeMemory *)etm, node);
+ g_return_val_if_fail (msg_info != NULL, FALSE);
- if (!get_tags)
- name = e_mail_label_list_store_get_name (store, &iter);
+ for (flag = camel_message_info_user_flags (msg_info); flag; flag = flag->next)
+ add_label_if_known (ld, flag->name);
- g_string_append (str, (get_tags || !name) ? old_label : name);
- count++;
+ old_label = camel_message_info_user_tag (msg_info, "label");
+ if (old_label != NULL) {
+ /* Convert old-style labels ("<name>") to "$Label<name>". */
+ new_label = g_alloca (strlen (old_label) + 10);
+ g_stpcpy (g_stpcpy (new_label, "$Label"), old_label);
- g_free (name);
+ add_label_if_known (ld, new_label);
}
-exit:
- *label_str = g_string_free (str, FALSE);
-
- g_object_unref (store);
-
- return count;
+ return FALSE;
}
-static const gchar *
-get_label_color (MessageList *message_list,
- const gchar *tag)
+static EMailLabelListStore *
+ml_get_label_list_store (MessageList *message_list)
{
- EShell *shell;
EShellBackend *shell_backend;
+ EShell *shell;
EShellSettings *shell_settings;
EMailLabelListStore *store;
- GtkTreeIter iter;
- GdkColor color;
- const gchar *property_name;
- const gchar *interned = NULL;
- gchar *color_spec;
-
- /* FIXME get_all_labels() should return an array of tree iterators,
- * not strings. Now we just have to lookup the tag again. */
shell_backend = message_list_get_shell_backend (message_list);
shell = e_shell_backend_get_shell (shell_backend);
shell_settings = e_shell_get_shell_settings (shell);
+ store = e_shell_settings_get_object (shell_settings, "mail-label-list-store");
- property_name = "mail-label-list-store";
- store = e_shell_settings_get_object (shell_settings, property_name);
-
- if (!e_mail_label_list_store_lookup (store, tag, &iter))
- goto exit;
-
- e_mail_label_list_store_get_color (store, &iter, &color);
-
- /* XXX Hack to avoid returning an allocated string. */
- color_spec = gdk_color_to_string (&color);
- interned = g_intern_string (color_spec);
- g_free (color_spec);
-
-exit:
- g_object_unref (store);
-
- return interned;
+ return store;
}
static const gchar *
@@ -1495,23 +1438,22 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model_data
case COL_SUBJECT_NORM:
return (gpointer) get_normalised_string (message_list, msg_info, col);
case COL_SENT: {
- ETreePath child;
+ struct LatestData ld;
+ ld.sent = TRUE;
+ ld.latest = 0;
- child = e_tree_model_node_get_first_child(etm, path);
- if (child && !e_tree_node_is_expanded(message_list->tree, path)) {
- return GINT_TO_POINTER (subtree_latest (message_list, child, 1));
- }
+ for_node_and_subtree_if_collapsed (message_list, path, latest_foreach, &ld);
- return GINT_TO_POINTER (camel_message_info_date_sent(msg_info));
+ return GINT_TO_POINTER (ld.latest);
}
case COL_RECEIVED: {
- ETreePath child;
+ struct LatestData ld;
+ ld.sent = FALSE;
+ ld.latest = 0;
- child = e_tree_model_node_get_first_child(etm, path);
- if (child && !e_tree_node_is_expanded(message_list->tree, path)) {
- return GINT_TO_POINTER (subtree_latest (message_list, child, 0));
- }
- return GINT_TO_POINTER (camel_message_info_date_received(msg_info));
+ for_node_and_subtree_if_collapsed (message_list, path, latest_foreach, &ld);
+
+ return GINT_TO_POINTER (ld.latest);
}
case COL_TO:
str = camel_message_info_to (msg_info);
@@ -1523,21 +1465,14 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model_data
case COL_DELETED:
return GINT_TO_POINTER ((camel_message_info_flags(msg_info) & CAMEL_MESSAGE_DELETED) != 0);
case COL_UNREAD: {
- ETreePath child;
- flags = camel_message_info_flags(msg_info);
+ gboolean saw_unread = FALSE;
- child = e_tree_model_node_get_first_child(etm, path);
- if (child && !e_tree_node_is_expanded(message_list->tree, path)
- && (flags & CAMEL_MESSAGE_SEEN)) {
- return GINT_TO_POINTER (subtree_unread (message_list, child));
- }
+ for_node_and_subtree_if_collapsed (message_list, path, unread_foreach, &saw_unread);
- return GINT_TO_POINTER (!(flags & CAMEL_MESSAGE_SEEN));
+ return GINT_TO_POINTER (saw_unread);
}
case COL_COLOUR: {
const gchar *colour, *due_by, *completed, *followup;
- gchar *labels_string = NULL;
- gint n;
/* Priority: colour tag; label tag; important flag; due-by tag */
@@ -1551,8 +1486,29 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model_data
completed = camel_message_info_user_tag(msg_info, "completed-on");
followup = camel_message_info_user_tag(msg_info, "follow-up");
if (colour == NULL) {
- if ((n = get_all_labels (message_list, msg_info, &labels_string, TRUE)) == 1) {
- colour = get_label_color (message_list, labels_string);
+ /* Get all applicable labels. */
+ struct LabelsData ld;
+
+ ld.store = ml_get_label_list_store (message_list);
+ ld.labels_tag2iter = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_iter_free);
+ for_node_and_subtree_if_collapsed (message_list, path, add_all_labels_foreach, &ld);
+
+ if (g_hash_table_size (ld.labels_tag2iter) == 1) {
+ GHashTableIter iter;
+ GtkTreeIter *label_defn;
+ GdkColor colour_val;
+ gchar *colour_alloced;
+
+ /* Extract the single label from the hashtable. */
+ g_hash_table_iter_init (&iter, ld.labels_tag2iter);
+ g_hash_table_iter_next (&iter, NULL, (gpointer *) &label_defn);
+
+ e_mail_label_list_store_get_color (ld.store, label_defn, &colour_val);
+
+ /* XXX Hack to avoid returning an allocated string. */
+ colour_alloced = gdk_color_to_string (&colour_val);
+ colour = g_intern_string (colour_alloced);
+ g_free (colour_alloced);
} else if (camel_message_info_flags(msg_info) & CAMEL_MESSAGE_FLAGGED) {
/* FIXME: extract from the important.xpm somehow. */
colour = "#A7453E";
@@ -1562,9 +1518,10 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model_data
if ((followup && *followup) || now >= camel_header_decode_date (due_by, NULL))
colour = "#A7453E";
}
- }
- g_free (labels_string);
+ g_hash_table_destroy (ld.labels_tag2iter);
+ g_object_unref (ld.store);
+ }
return (gpointer) colour;
}
@@ -1626,21 +1583,37 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model_data
return (gpointer)("");
}
case COL_LABELS:{
- gchar *str = NULL;
- GString *cleansed_str;
+ struct LabelsData ld;
+ GString *result = g_string_new ("");
- cleansed_str = g_string_new ("");
+ ld.store = ml_get_label_list_store (message_list);
+ ld.labels_tag2iter = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_iter_free);
+ for_node_and_subtree_if_collapsed (message_list, path, add_all_labels_foreach, &ld);
- if (get_all_labels (message_list, msg_info, &str, FALSE)) {
- gint i;
- for (i = 0; str[i] != '\0'; ++i) {
- if (str[i] != '_') {
- g_string_append_c (cleansed_str, str[i]);
- }
+ if (g_hash_table_size (ld.labels_tag2iter) > 0) {
+ GHashTableIter iter;
+ GtkTreeIter *label_defn;
+
+ g_hash_table_iter_init (&iter, ld.labels_tag2iter);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &label_defn)) {
+ gchar *label_name, *label_name_clean;
+
+ if (result->len > 0)
+ g_string_append (result, ", ");
+
+ label_name = e_mail_label_list_store_get_name (ld.store, label_defn);
+ label_name_clean = e_str_without_underscores (label_name);
+
+ g_string_append (result, label_name_clean);
+
+ g_free(label_name_clean);
+ g_free(label_name);
}
- return (gpointer) (g_string_free (cleansed_str, FALSE));
- } else
- return (gpointer) ("");
+ }
+
+ g_hash_table_destroy (ld.labels_tag2iter);
+ g_object_unref (ld.store);
+ return (gpointer) g_string_free (result, FALSE);
}
default:
g_warning ("This shouldn't be reached\n");
@@ -1652,7 +1625,7 @@ static gpointer
ml_tree_sort_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model_data)
{
MessageList *message_list = model_data;
- CamelMessageInfo *msg_info;
+ struct LatestData ld;
if (!(col == COL_SENT || col == COL_RECEIVED))
return ml_tree_value_at (etm, path, col, model_data);
@@ -1660,36 +1633,14 @@ ml_tree_sort_value_at (ETreeModel *etm, ETreePath path, gint col, gpointer model
if (e_tree_model_node_is_root (etm, path))
return NULL;
- /* retrieve the message information array */
- msg_info = e_tree_memory_node_get_data (E_TREE_MEMORY(etm), path);
- g_return_val_if_fail (msg_info != NULL, NULL);
-
- if (col == COL_SENT) {
- if (message_list->priv->thread_latest) {
- ETreePath child;
-
- child = e_tree_model_node_get_first_child (etm, path);
- if (child) {
- return GINT_TO_POINTER (subtree_latest (message_list, child, 1));
- }
- }
-
- return GINT_TO_POINTER (camel_message_info_date_sent(msg_info));
- } else if (col == COL_RECEIVED) {
- if (message_list->priv->thread_latest) {
- ETreePath child;
-
- child = e_tree_model_node_get_first_child (etm, path);
- if (child) {
- return GINT_TO_POINTER (subtree_latest (message_list, child, 0));
- }
- }
-
- return GINT_TO_POINTER (camel_message_info_date_received(msg_info));
- }
+ ld.sent = (col == COL_SENT);
+ ld.latest = 0;
- return ml_tree_value_at (etm, path, col, model_data);
+ latest_foreach (etm, path, &ld);
+ if (message_list->priv->thread_latest)
+ e_tree_model_node_traverse (etm, path, latest_foreach, &ld);
+ return GINT_TO_POINTER (ld.latest);
}
static void