diff options
-rw-r--r-- | widgets/table/e-tree-model.c | 210 | ||||
-rw-r--r-- | widgets/table/e-tree-model.h | 10 |
2 files changed, 213 insertions, 7 deletions
diff --git a/widgets/table/e-tree-model.c b/widgets/table/e-tree-model.c index e5ea2a2867..baf8d40416 100644 --- a/widgets/table/e-tree-model.c +++ b/widgets/table/e-tree-model.c @@ -10,9 +10,19 @@ * (C) 2000 Helix Code, Inc. */ #include <config.h> + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <gnome-xml/parser.h> +#include <gnome-xml/xmlmemory.h> + #include <gtk/gtksignal.h> #include <stdlib.h> #include "gal/util/e-util.h" +#include "gal/util/e-xml-utils.h" #include "e-tree-model.h" #define ETM_CLASS(e) ((ETreeModelClass *)((GtkObject *)e)->klass) @@ -24,6 +34,7 @@ static ETableModel *e_tree_model_parent_class; typedef struct { gboolean expanded; guint visible_descendents; + char *save_id; gpointer node_data; } ENode; @@ -43,6 +54,13 @@ static void add_visible_descendents_to_array (ETreeModel *etm, GNode *gnode, int /* virtual methods */ +static gboolean +expanded_remove_func (gpointer key, gpointer value, gpointer user_data) +{ + g_free (key); + return TRUE; +} + static void etree_destroy (GtkObject *object) { @@ -50,7 +68,9 @@ etree_destroy (GtkObject *object) /* XXX lots of stuff to free here */ g_array_free (etree->row_array, TRUE); - + g_hash_table_foreach_remove (etree->expanded_state, + expanded_remove_func, NULL); + GTK_OBJECT_CLASS (e_tree_model_parent_class)->destroy (object); } @@ -147,6 +167,20 @@ etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded) } enode->expanded = expanded; + if (enode->save_id) { + g_hash_table_insert (etm->expanded_state, enode->save_id, (gpointer)expanded); + + if (expanded) { + /* the node previously was collapsed */ + etm->num_collapsed_to_save --; + etm->num_expanded_to_save ++; + } + else { + /* the node previously was expanded */ + etm->num_expanded_to_save --; + etm->num_collapsed_to_save ++; + } + } /* if the node wasn't visible at present */ if ((row = e_tree_model_row_of_node (etm, node)) == -1) { @@ -464,6 +498,7 @@ e_tree_model_construct (ETreeModel *etree) etree->root = NULL; etree->root_visible = TRUE; etree->row_array = g_array_new (FALSE, FALSE, sizeof(GNode*)); + etree->expanded_state = g_hash_table_new (g_str_hash, g_str_equal); } ETreeModel * @@ -693,6 +728,21 @@ e_tree_model_node_insert (ETreeModel *tree_model, return new_path; } + +ETreePath* +e_tree_model_node_insert_id (ETreeModel *tree_model, + ETreePath *parent_path, + int position, + gpointer node_data, + const char *save_id) +{ + ETreePath *path = e_tree_model_node_insert (tree_model, parent_path, position, node_data); + + e_tree_model_node_set_save_id (tree_model, path, save_id); + + return path; +} + ETreePath * e_tree_model_node_insert_before (ETreeModel *etree, @@ -799,17 +849,12 @@ e_tree_model_node_sort (ETreeModel *tree_model, child_index = e_tree_model_row_of_node (tree_model, node) + 1; - printf ("====== before sort ==== \n"); for (i = 0; i < num_nodes; i ++) { path_array[i] = g_node_first_child(node); - printf ("i: %s\n", e_tree_model_node_get_data (tree_model, path_array[i])); - g_node_unlink (path_array[i]); - } - - for (i = 0; i < num_nodes; i ++) { expanded[i] = e_tree_model_node_is_expanded (tree_model, path_array[i]); e_tree_model_node_set_expanded(tree_model, path_array[i], FALSE); tree_model->row_array = g_array_remove_index (tree_model->row_array, child_index); + g_node_unlink (path_array[i]); } qsort (path_array, num_nodes, sizeof(ETreePath*), compare); @@ -825,3 +870,154 @@ e_tree_model_node_sort (ETreeModel *tree_model, e_table_model_changed (E_TABLE_MODEL (tree_model)); } + +static void +save_expanded_state_func (char *key, gboolean expanded, gpointer user_data) +{ + if (expanded) { + xmlNode *root = (xmlNode*)user_data; + xmlNode *node_root = xmlNewNode (NULL, (xmlChar*) "node"); + + xmlAddChild (root, node_root); + xmlNewChild (node_root, NULL, (xmlChar *) "id", (xmlChar*) key); + } +} + +gboolean +e_tree_model_save_expanded_state (ETreeModel *etm, const char *filename) +{ + xmlDoc *doc; + xmlNode *root; + int fd, rv; + xmlChar *buf; + int buf_size; + gboolean save_expanded = etm->num_expanded_to_save < etm->num_collapsed_to_save; + + g_print ("saving expanded state: %d expanded, %d collapsed, should save %s\n", + etm->num_expanded_to_save, etm->num_collapsed_to_save, + save_expanded ? "expanded" : "collapsed"); + + doc = xmlNewDoc ((xmlChar*) "1.0"); + root = xmlNewDocNode (doc, NULL, (xmlChar *) save_expanded ? "expanded_state" : "collapsed_state", NULL); + xmlDocSetRootElement (doc, root); + + g_hash_table_foreach (etm->expanded_state, (GHFunc)save_expanded_state_func, root); + + fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0777); + + xmlDocDumpMemory (doc, &buf, &buf_size); + + if (buf == NULL) { + g_error ("Failed to write %s: xmlBufferCreate() == NULL", filename); + return FALSE; + } + + rv = write (fd, buf, buf_size); + xmlFree (buf); + close (fd); + + if (0 > rv) { + g_error ("Failed to write new %s: %d\n", filename, errno); + unlink (filename); + return FALSE; + } + + return TRUE; +} + +static char * +get_string_value (xmlNode *node, + const char *name) +{ + xmlNode *p; + xmlChar *xml_string; + char *retval; + + p = e_xml_get_child_by_name (node, (xmlChar *) name); + if (p == NULL) + return NULL; + + p = e_xml_get_child_by_name (p, (xmlChar *) "text"); + if (p == NULL) /* there's no text between the tags, return the empty string */ + return g_strdup(""); + + xml_string = xmlNodeListGetString (node->doc, p, 1); + retval = g_strdup ((char *) xml_string); + xmlFree (xml_string); + + return retval; +} + +gboolean +e_tree_model_load_expanded_state (ETreeModel *etm, const char *filename) +{ + xmlDoc *doc; + xmlNode *root; + xmlNode *child; + + doc = xmlParseFile (filename); + if (!doc) + return FALSE; + + root = xmlDocGetRootElement (doc); + if (root == NULL || strcmp (root->name, "expanded_state") != 0) { + xmlFreeDoc (doc); + return FALSE; + } + + for (child = root->childs; child; child = child->next) { + char *id; + + if (strcmp (child->name, "node")) { + g_warning ("unknown node '%s' in %s", child->name, filename); + continue; + } + + id = get_string_value (child, "id"); + + g_hash_table_insert (etm->expanded_state, id, (gpointer)TRUE); + } + + xmlFreeDoc (doc); + + return TRUE; +} + + +void +e_tree_model_node_set_save_id (ETreeModel *etm, ETreePath *node, const char *id) +{ + ENode *enode; + char *key; + gboolean expanded_state; + + g_return_if_fail (E_TREE_MODEL (etm)); + g_return_if_fail (node && node->data); + + enode = (ENode*)node->data; + + if (g_hash_table_lookup_extended (etm->expanded_state, + id, (gpointer*)&key, (gpointer*)&expanded_state)) { + + e_tree_model_node_set_expanded (etm, node, + expanded_state); + + if (expanded_state) + etm->num_expanded_to_save ++; + else + etm->num_collapsed_to_save ++; + + /* important that this comes after the e_tree_model_node_set_expanded */ + enode->save_id = key; + } + else { + enode->save_id = g_strdup (id); + + g_hash_table_insert (etm->expanded_state, enode->save_id, (gpointer)enode->expanded); + + if (enode->expanded) + etm->num_expanded_to_save ++; + else + etm->num_collapsed_to_save ++; + } +} diff --git a/widgets/table/e-tree-model.h b/widgets/table/e-tree-model.h index 318faaa0a4..b00101ca8e 100644 --- a/widgets/table/e-tree-model.h +++ b/widgets/table/e-tree-model.h @@ -18,6 +18,9 @@ typedef struct { GNode *root; gboolean root_visible; GArray *row_array; /* used in the mapping between ETable and our tree */ + guint32 num_expanded_to_save; + guint32 num_collapsed_to_save; + GHashTable *expanded_state; /* used for loading/saving expanded state */ } ETreeModel; typedef struct { @@ -108,4 +111,11 @@ void e_tree_model_node_removed (ETreeModel *tree_model, ETreePath *parent_node void e_tree_model_node_collapsed (ETreeModel *tree_model, ETreePath *node); void e_tree_model_node_expanded (ETreeModel *tree_model, ETreePath *node, gboolean *allow_expand); +/* expanded state saving stuff */ +gboolean e_tree_model_save_expanded_state (ETreeModel *etm, const char *filename); +gboolean e_tree_model_load_expanded_state (ETreeModel *etm, const char *filename); +void e_tree_model_node_set_save_id (ETreeModel *etm, ETreePath *node, const char *id); +ETreePath* e_tree_model_node_insert_id (ETreeModel *tree_model, ETreePath *parent_path, + int position, gpointer node_data, const char *save_id); + #endif /* _E_TREE_MODEL_H */ |