aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/ChangeLog15
-rw-r--r--mail/message-list.c173
-rw-r--r--mail/message-thread.h2
3 files changed, 174 insertions, 16 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index e3e3ccdb46..648b921d80 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,18 @@
+2000-09-25 Not Zed <NotZed@HelixCode.com>
+
+ * message-list.c (folder_to_cachename): Function to convert a
+ folder name/path to a filename for per-folder data.
+ (save_tree_state):
+ (load_tree_state):
+ (free_tree_state): For loading/saving the state of the expansion
+ of nodes in the tree.
+ (message_list_destroy): Save the tree state when done.
+ (save_node_state): Changed logic, we save when the node should be
+ closed on startup. i.e. any new nodes with children automatically
+ default to being open.
+ (subtree_unread): Check for unread messages in a subtree. So
+ false messages (for tree roots) are properly displayed.
+
2000-09-25 Jeffrey Stedfast <fejj@helixcode.com>
* message-list.c (address_compare): Updated to use Nat's
diff --git a/mail/message-list.c b/mail/message-list.c
index 82915ea528..bceaee60aa 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -88,6 +88,8 @@ static void select_msg (MessageList *message_list, gint row);
static char *filter_date (const void *data);
static void nuke_uids (GtkObject *o);
+static void save_tree_state(MessageList *ml);
+
static struct {
char **image_base;
GdkPixbuf *pixbuf;
@@ -632,6 +634,28 @@ ml_tree_icon_at (ETreeModel *etm, ETreePath *path, void *model_data)
return NULL;
}
+/* return true if there are any unread messages in the subtree */
+static int
+subtree_unread(MessageList *ml, ETreePath *node)
+{
+ const CamelMessageInfo *info;
+ char *uid;
+
+ while (node) {
+ uid = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node);
+ if (strncmp (uid, "uid:", 4) == 0) {
+ info = camel_folder_get_message_info(ml->folder, uid+4);
+ if (!(info->flags & CAMEL_MESSAGE_SEEN))
+ return TRUE;
+ }
+ if (node->children)
+ if (subtree_unread(ml, node->children))
+ return TRUE;
+ node = node->next;
+ }
+ return FALSE;
+}
+
static void *
ml_tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data)
{
@@ -719,12 +743,15 @@ ml_tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data)
fake:
/* This is a fake tree parent */
switch (col){
+ case COL_UNREAD:
+ /* this value should probably be cached, as it could take a bit
+ of processing to evaluate all the time */
+ return (void *)subtree_unread(message_list, path->children);
case COL_MESSAGE_STATUS:
case COL_SCORE:
case COL_ATTACHMENT:
case COL_DELETED:
case COL_COLOUR:
- case COL_UNREAD:
case COL_SENT:
case COL_RECEIVED:
return (void *) 0;
@@ -1076,6 +1103,7 @@ message_list_destroy (GtkObject *object)
MessageList *message_list = MESSAGE_LIST (object);
int i;
+ save_tree_state(message_list);
gtk_object_unref (GTK_OBJECT (message_list->table_model));
gtk_object_unref (GTK_OBJECT (message_list->header_model));
@@ -1234,41 +1262,156 @@ clear_tree (MessageList *ml)
e_tree_model_node_set_expanded (etm, ml->tree_root, TRUE);
}
+static char *
+folder_to_cachename(CamelFolder *folder, const char *prefix)
+{
+ char *url, *p, *filename;
+
+ url = camel_url_to_string (CAMEL_SERVICE (folder->parent_store)->url, FALSE);
+ for (p = url; *p; p++) {
+ if (!isprint((unsigned char)*p) || strchr(" /'\"`&();|<>${}!", *p))
+ *p = '_';
+ }
+
+ filename = g_strdup_printf("%s/config/%s%s", evolution_dir, prefix, url);
+ g_free(url);
+ return filename;
+}
+
+/* we save the node id to the file if the node should be closed when
+ we start up. We only save nodeid's for messages with children */
+static void
+save_node_state(MessageList *ml, FILE *out, ETreePath *node)
+{
+ char *data;
+ const CamelMessageInfo *info;
+
+ while (node) {
+ if (node->children
+ && !e_tree_model_node_is_expanded((ETreeModel *)ml->table_model, node)) {
+ data = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node);
+ if (data) {
+ if (!strncmp(data, "uid:", 4)) {
+ info = camel_folder_get_message_info(ml->folder, data+4);
+ if (info) {
+ fprintf(out, "%s\n", info->message_id);
+ }
+ } else {
+ fprintf(out, "%s\n", data);
+ }
+ }
+ }
+ if (node->children) {
+ save_node_state(ml, out, node->children);
+ }
+ node = node->next;
+ }
+}
+
+static GHashTable *
+load_tree_state(MessageList *ml)
+{
+ char *filename, linebuf[10240];
+ GHashTable *result;
+ FILE *in;
+ int len;
+
+ result = g_hash_table_new(g_str_hash, g_str_equal);
+ filename = folder_to_cachename(ml->folder, "treestate-");
+ in = fopen(filename, "r");
+ if (in) {
+ while (fgets(linebuf, sizeof(linebuf), in) != NULL) {
+ len = strlen(linebuf);
+ if (len) {
+ linebuf[len-1] = 0;
+ g_hash_table_insert(result, g_strdup(linebuf), (void *)1);
+ }
+ }
+ fclose(in);
+ }
+ g_free(filename);
+ return result;
+}
+
+/* save tree info */
+static void
+save_tree_state(MessageList *ml)
+{
+ char *filename;
+ ETreePath *node;
+ FILE *out;
+
+ filename = folder_to_cachename(ml->folder, "treestate-");
+ out = fopen(filename, "w");
+ if (out) {
+ node = e_tree_model_get_root((ETreeModel *)ml->table_model);
+ if (node && node->children) {
+ save_node_state(ml, out, node->children);
+ }
+ fclose(out);
+ }
+ g_free(filename);
+}
+
+static void
+free_node_state(void *key, void *value, void *data)
+{
+ g_free(key);
+}
+
+static void
+free_tree_state(GHashTable *expanded_nodes)
+{
+ g_hash_table_foreach(expanded_nodes, free_node_state, 0);
+ g_hash_table_destroy(expanded_nodes);
+}
+
/* only call if we have a tree model */
/* builds the tree structure */
-static void build_subtree (MessageList *ml, ETreePath *parent,
- struct _container *c, int *row);
+static void build_subtree (MessageList *ml, ETreePath *parent, struct _container *c, int *row, GHashTable *);
static void
build_tree (MessageList *ml, struct _container *c)
{
int row = 0;
+ GHashTable *expanded_nodes;
clear_tree (ml);
- build_subtree (ml, ml->tree_root, c, &row);
+ expanded_nodes = load_tree_state(ml);
+ build_subtree (ml, ml->tree_root, c, &row, expanded_nodes);
+ free_tree_state(expanded_nodes);
}
static void
-build_subtree (MessageList *ml, ETreePath *parent,
- struct _container *c, int *row)
+build_subtree (MessageList *ml, ETreePath *parent, struct _container *c, int *row, GHashTable *expanded_nodes)
{
ETreeModel *tree = E_TREE_MODEL (ml->table_model);
ETreePath *node;
char *id;
+ int expanded;
while (c) {
if (c->message) {
- id = g_strdup_printf ("uid:%s", c->message->uid);
- g_hash_table_insert (ml->uid_rowmap,
- g_strdup (c->message->uid),
- GINT_TO_POINTER ((*row)++));
- } else
- id = g_strdup_printf ("subject:%s", c->root_subject);
- node = e_tree_model_node_insert (tree, parent, 0, id);
+ id = g_strdup_printf("uid:%s", c->message->uid);
+ g_hash_table_insert(ml->uid_rowmap, g_strdup (c->message->uid), GINT_TO_POINTER ((*row)++));
+ if (c->child) {
+ if (c->message && c->message->message_id)
+ expanded = !g_hash_table_lookup(expanded_nodes, c->message->message_id) != 0;
+ else
+ expanded = TRUE;
+ }
+ } else {
+ id = g_strdup_printf("subject:%s", c->root_subject);
+ if (c->child) {
+ expanded = !g_hash_table_lookup(expanded_nodes, id) != 0;
+ }
+ }
+ node = e_tree_model_node_insert(tree, parent, 0, id);
if (c->child) {
/* by default, open all trees */
- e_tree_model_node_set_expanded (tree, node, TRUE);
- build_subtree (ml, node, c->child, row);
+ if (expanded)
+ e_tree_model_node_set_expanded(tree, node, expanded);
+ build_subtree(ml, node, c->child, row, expanded_nodes);
}
c = c->next;
}
diff --git a/mail/message-thread.h b/mail/message-thread.h
index daff7451d4..cf4665663f 100644
--- a/mail/message-thread.h
+++ b/mail/message-thread.h
@@ -12,7 +12,7 @@ struct _container {
const CamelMessageInfo *message;
char *root_subject; /* cached root equivalent subject */
int re; /* re version of subject? */
- int order; /* the order of this message in the folder */
+ int order;
};
void mail_do_thread_messages (MessageList *ml, GPtrArray *uids,