diff options
-rw-r--r-- | widgets/table/e-tree-model.c | 218 | ||||
-rw-r--r-- | widgets/table/e-tree-model.h | 14 |
2 files changed, 135 insertions, 97 deletions
diff --git a/widgets/table/e-tree-model.c b/widgets/table/e-tree-model.c index a508584a85..8afb1a011c 100644 --- a/widgets/table/e-tree-model.c +++ b/widgets/table/e-tree-model.c @@ -29,10 +29,23 @@ #define PARENT_TYPE E_TABLE_MODEL_TYPE +#define TREEPATH_CHUNK_AREA_SIZE (30 * sizeof (ETreePath)) + static ETableModel *e_tree_model_parent_class; +struct ETreeModelPriv { + GMemChunk *node_chunk; + ETreePath *root; + gboolean root_visible; + GArray *row_array; /* used in the mapping between ETable and our tree */ + GHashTable *expanded_state; /* used for loading/saving expanded state */ + GString *sort_group; /* for caching the last sort group info */ + gboolean expanded_default; /* whether nodes are created expanded or collapsed by default */ +}; + struct ETreePath { gboolean expanded; + gboolean expanded_set; guint visible_descendents; char *save_id; ETreePathCompareFunc compare; @@ -142,7 +155,11 @@ e_tree_path_unlink (ETreePath *path) void e_tree_model_node_traverse (ETreeModel *model, ETreePath *path, ETreePathFunc func, gpointer data) { - ETreePath *child = path->first_child; + ETreePath *child; + + g_return_if_fail (path); + + child = path->first_child; while (child) { ETreePath *next_child = child->next_sibling; @@ -168,20 +185,25 @@ static void etree_destroy (GtkObject *object) { ETreeModel *etree = E_TREE_MODEL (object); + ETreeModelPriv *priv = etree->priv; /* XXX lots of stuff to free here */ - g_array_free (etree->row_array, TRUE); - g_hash_table_foreach_remove (etree->expanded_state, + g_array_free (priv->row_array, TRUE); + g_hash_table_foreach_remove (priv->expanded_state, expanded_remove_func, NULL); - g_string_free(etree->sort_group, TRUE); + g_string_free(priv->sort_group, TRUE); + + g_free (priv); + GTK_OBJECT_CLASS (e_tree_model_parent_class)->destroy (object); } static ETreePath* etree_get_root (ETreeModel *etm) { - return etm->root; + ETreeModelPriv *priv = etm->priv; + return priv->root; } static ETreePath* @@ -269,11 +291,14 @@ etree_is_visible (ETreeModel *etm, ETreePath* node) static void etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded) { + ETreeModelPriv *priv = etm->priv; ETreePath *child; int row; g_return_if_fail (node); + node->expanded_set = TRUE; + if (node->expanded == expanded) return; @@ -286,18 +311,7 @@ etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded) node->expanded = expanded; if (node->save_id) { - g_hash_table_insert (etm->expanded_state, node->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 ++; - } + g_hash_table_insert (priv->expanded_state, node->save_id, (gpointer)expanded); } /* if the node wasn't visible at present */ @@ -333,7 +347,7 @@ etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded) if (e_tree_model_node_is_visible (etm, node)) { for (i = 0; i < node->visible_descendents; i ++) { - etm->row_array = g_array_remove_index (etm->row_array, row); + priv->row_array = g_array_remove_index (priv->row_array, row); e_table_model_row_deleted (E_TABLE_MODEL (etm), row); } } @@ -350,32 +364,35 @@ etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded) } } +void +e_tree_model_set_expanded_default (ETreeModel *etree, + gboolean expanded) +{ + ETreeModelPriv *priv = etree->priv; + + priv->expanded_default = expanded; +} + /* fairly naive implementation */ static void etree_set_expanded_recurse (ETreeModel *etm, ETreePath* node, gboolean expanded) { - ETreePath **paths; - guint num_children; - int i; + ETreePath *child; e_tree_model_node_set_expanded (etm, node, expanded); - num_children = e_tree_model_node_get_children (etm, node, &paths); - if (num_children) { - for (i = 0; i < num_children; i ++) { - e_tree_model_node_set_expanded_recurse (etm, paths[i], expanded); - } - - g_free (paths); - } + for (child = node->first_child; child; child = child->next_sibling) + e_tree_model_node_set_expanded_recurse (etm, child, expanded); } static ETreePath * etree_node_at_row (ETreeModel *etree, int row) { - g_return_val_if_fail (row < etree->row_array->len, NULL); + ETreeModelPriv *priv = etree->priv; + + g_return_val_if_fail (row < priv->row_array->len, NULL); - return g_array_index (etree->row_array, ETreePath*, row); + return g_array_index (priv->row_array, ETreePath*, row); } @@ -417,7 +434,8 @@ static int etable_row_count (ETableModel *etm) { ETreeModel *tree = E_TREE_MODEL (etm); - return tree->row_array->len; + ETreeModelPriv *priv = tree->priv; + return priv->row_array->len; } static void * @@ -474,15 +492,16 @@ static const char * etable_row_sort_group(ETableModel *etm, int row) { ETreeModel *etree = E_TREE_MODEL(etm); + ETreeModelPriv *priv = etree->priv; ETreePath* node = e_tree_model_node_at_row (etree, row); g_return_val_if_fail (node, ""); - g_string_truncate(etree->sort_group, 0); + g_string_truncate(priv->sort_group, 0); if (node) - build_sort_group(etree->sort_group, node); + build_sort_group(priv->sort_group, node); - return etree->sort_group->str; + return priv->sort_group->str; } static gboolean @@ -586,8 +605,7 @@ static void e_tree_init (GtkObject *object) { ETreeModel *etree = (ETreeModel *)object; - - etree->sort_group = g_string_new(""); + e_tree_model_construct (etree); } E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, e_tree_init, PARENT_TYPE) @@ -667,13 +685,20 @@ e_tree_model_node_expanded (ETreeModel *tree_model, ETreePath *node, gboolean * } + void e_tree_model_construct (ETreeModel *etree) { - etree->root = NULL; - etree->root_visible = TRUE; - etree->row_array = g_array_new (FALSE, FALSE, sizeof(ETreePath*)); - etree->expanded_state = g_hash_table_new (g_str_hash, g_str_equal); + ETreeModelPriv *priv = g_new0 (ETreeModelPriv, 1); + + etree->priv = priv; + + priv->node_chunk = g_mem_chunk_create (ETreePath, TREEPATH_CHUNK_AREA_SIZE, G_ALLOC_AND_FREE); + priv->root = NULL; + priv->root_visible = TRUE; + priv->row_array = g_array_new (FALSE, FALSE, sizeof(ETreePath*)); + priv->expanded_state = g_hash_table_new (g_str_hash, g_str_equal); + priv->sort_group = g_string_new(""); } ETreeModel * @@ -707,10 +732,11 @@ e_tree_model_icon_of_node (ETreeModel *etree, ETreePath *path) int e_tree_model_row_of_node (ETreeModel *etree, ETreePath *node) { + ETreeModelPriv *priv = etree->priv; int i; - for (i = 0; i < etree->row_array->len; i ++) - if (g_array_index (etree->row_array, ETreePath*, i) == node) + for (i = 0; i < priv->row_array->len; i ++) + if (g_array_index (priv->row_array, ETreePath*, i) == node) return i; return -1; @@ -719,16 +745,18 @@ e_tree_model_row_of_node (ETreeModel *etree, ETreePath *node) void e_tree_model_root_node_set_visible (ETreeModel *etm, gboolean visible) { - if (visible != etm->root_visible) { - etm->root_visible = visible; - if (etm->root) { + ETreeModelPriv *priv = etm->priv; + + if (visible != priv->root_visible) { + priv->root_visible = visible; + if (priv->root) { if (visible) { - etm->row_array = g_array_insert_val (etm->row_array, 0, etm->root); + priv->row_array = g_array_insert_val (priv->row_array, 0, priv->root); } else { ETreePath *root_path = e_tree_model_get_root (etm); e_tree_model_node_set_expanded (etm, root_path, TRUE); - etm->row_array = g_array_remove_index (etm->row_array, 0); + priv->row_array = g_array_remove_index (priv->row_array, 0); } e_table_model_changed (E_TABLE_MODEL (etm)); @@ -739,7 +767,8 @@ e_tree_model_root_node_set_visible (ETreeModel *etm, gboolean visible) gboolean e_tree_model_root_node_is_visible (ETreeModel *etm) { - return etm->root_visible; + ETreeModelPriv *priv = etm->priv; + return priv->root_visible; } ETreePath * @@ -849,16 +878,29 @@ e_tree_model_node_insert (ETreeModel *tree_model, int position, gpointer node_data) { + ETreeModelPriv *priv; ETreePath *new_path; - g_return_val_if_fail (parent_path != NULL || tree_model->root == NULL, NULL); - new_path = g_new0 (ETreePath, 1); + priv = tree_model->priv; + + g_return_val_if_fail (parent_path != NULL || priv->root == NULL, NULL); + + priv = tree_model->priv; + + new_path = g_chunk_new0 (ETreePath, priv->node_chunk); new_path->expanded = FALSE; new_path->node_data = node_data; if (parent_path != NULL) { + if (parent_path->first_child == NULL + && !parent_path->expanded_set) { + e_tree_model_node_set_expanded (tree_model, + parent_path, + priv->expanded_default); + } + e_tree_path_insert (parent_path, position, new_path); if (e_tree_model_node_is_visible (tree_model, new_path)) { @@ -877,22 +919,23 @@ e_tree_model_node_insert (ETreeModel *tree_model, parent_row = e_tree_model_row_of_node (tree_model, parent_path); - tree_model->row_array = g_array_insert_val (tree_model->row_array, - parent_row + position + 1, new_path); + priv->row_array = g_array_insert_val (priv->row_array, + parent_row + position + 1, new_path); e_table_model_row_inserted (E_TABLE_MODEL(tree_model), parent_row + position + 1); } } else { - tree_model->root = new_path; - if (tree_model->root_visible) { - tree_model->row_array = g_array_insert_val (tree_model->row_array, 0, tree_model->root); + priv->root = new_path; + if (priv->root_visible) { + priv->row_array = g_array_insert_val (priv->row_array, 0, priv->root); e_table_model_row_inserted (E_TABLE_MODEL (tree_model), 0); } else { /* need to mark the new node as expanded or we'll never see it's children */ new_path->expanded = TRUE; + new_path->expanded_set = TRUE; } } @@ -940,6 +983,7 @@ child_remove (ETreeModel *model, ETreePath *node, gpointer data) gpointer e_tree_model_node_remove (ETreeModel *etree, ETreePath *path) { + ETreeModelPriv *priv = etree->priv; ETreePath *parent = path->parent; gpointer ret = path->node_data; @@ -951,7 +995,7 @@ e_tree_model_node_remove (ETreeModel *etree, ETreePath *path) if (e_tree_model_node_is_visible (etree, path)) { int row = e_tree_model_row_of_node (etree, path); e_table_model_row_deleted (E_TABLE_MODEL (etree), row); - etree->row_array = g_array_remove_index (etree->row_array, row); + priv->row_array = g_array_remove_index (priv->row_array, row); /* we need to iterate back up to the root, incrementing the number of visible descendents */ @@ -960,10 +1004,10 @@ e_tree_model_node_remove (ETreeModel *etree, ETreePath *path) } } } - else if (path == etree->root) { - etree->root = NULL; - if (etree->root_visible) { - etree->row_array = g_array_remove_index (etree->row_array, 0); + else if (path == priv->root) { + priv->root = NULL; + if (priv->root_visible) { + priv->row_array = g_array_remove_index (priv->row_array, 0); e_table_model_row_deleted (E_TABLE_MODEL (etree), 0); } } @@ -976,7 +1020,8 @@ e_tree_model_node_remove (ETreeModel *etree, ETreePath *path) e_tree_path_unlink (path); /* now free up the storage from that path */ - g_free (path); + g_free (path->save_id); + g_chunk_free (path, priv->node_chunk); return ret; } @@ -985,8 +1030,10 @@ e_tree_model_node_remove (ETreeModel *etree, ETreePath *path) static void add_visible_descendents_to_array (ETreeModel *etm, ETreePath *node, int *row, int *count) { + ETreeModelPriv *priv = etm->priv; + /* add a row for this node */ - etm->row_array = g_array_insert_val (etm->row_array, (*row), node); + priv->row_array = g_array_insert_val (priv->row_array, (*row), node); e_table_model_row_inserted (E_TABLE_MODEL (etm), (*row)++); (*count) ++; @@ -1021,17 +1068,17 @@ e_tree_model_save_expanded_state (ETreeModel *etm, const char *filename) 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"); + ETreeModelPriv *priv = etm->priv; doc = xmlNewDoc ((xmlChar*) "1.0"); - root = xmlNewDocNode (doc, NULL, (xmlChar *) save_expanded ? "expanded_state" : "collapsed_state", NULL); + root = xmlNewDocNode (doc, NULL, + (xmlChar *) "expanded_state", + NULL); xmlDocSetRootElement (doc, root); - g_hash_table_foreach (etm->expanded_state, (GHFunc)save_expanded_state_func, root); + g_hash_table_foreach (priv->expanded_state, + (GHFunc)save_expanded_state_func, + root); fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0777); @@ -1081,6 +1128,7 @@ get_string_value (xmlNode *node, gboolean e_tree_model_load_expanded_state (ETreeModel *etm, const char *filename) { + ETreeModelPriv *priv = etm->priv; xmlDoc *doc; xmlNode *root; xmlNode *child; @@ -1090,7 +1138,7 @@ e_tree_model_load_expanded_state (ETreeModel *etm, const char *filename) return FALSE; root = xmlDocGetRootElement (doc); - if (root == NULL || strcmp (root->name, "expanded_state") != 0) { + if (root == NULL || strcmp (root->name, "expanded_state")) { xmlFreeDoc (doc); return FALSE; } @@ -1105,7 +1153,7 @@ e_tree_model_load_expanded_state (ETreeModel *etm, const char *filename) id = get_string_value (child, "id"); - g_hash_table_insert (etm->expanded_state, id, (gpointer)TRUE); + g_hash_table_insert (priv->expanded_state, id, (gpointer)TRUE); } xmlFreeDoc (doc); @@ -1119,33 +1167,26 @@ e_tree_model_node_set_save_id (ETreeModel *etm, ETreePath *node, const char *id) { char *key; gboolean expanded_state; + ETreeModelPriv *priv; g_return_if_fail (E_TREE_MODEL (etm)); g_return_if_fail (node); - if (g_hash_table_lookup_extended (etm->expanded_state, + priv = etm->priv; + + if (g_hash_table_lookup_extended (priv->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 */ node->save_id = key; } else { node->save_id = g_strdup (id); - g_hash_table_insert (etm->expanded_state, node->save_id, (gpointer)node->expanded); - - if (node->expanded) - etm->num_expanded_to_save ++; - else - etm->num_collapsed_to_save ++; + g_hash_table_insert (priv->expanded_state, node->save_id, (gpointer)node->expanded); } } @@ -1191,7 +1232,8 @@ e_tree_model_node_sort (ETreeModel *tree_model, int i; int child_index; gboolean node_expanded = e_tree_model_node_is_expanded (tree_model, node); - + ETreeModelPriv *priv = tree_model->priv;; + g_return_if_fail (E_TREE_MODEL (tree_model)); g_return_if_fail (node); @@ -1213,7 +1255,7 @@ e_tree_model_node_sort (ETreeModel *tree_model, e_tree_model_node_set_expanded(tree_model, sort_info[i].path, FALSE); if (node_expanded) - tree_model->row_array = g_array_remove_index (tree_model->row_array, child_index); + priv->row_array = g_array_remove_index (priv->row_array, child_index); e_tree_path_unlink (sort_info[i].path); } @@ -1224,8 +1266,8 @@ e_tree_model_node_sort (ETreeModel *tree_model, for (i = 0; i < num_nodes; i ++) { e_tree_path_insert (node, i, sort_info[i].path); if (node_expanded) - tree_model->row_array = g_array_insert_val (tree_model->row_array, child_index + i, - sort_info[i].path); + priv->row_array = g_array_insert_val (priv->row_array, child_index + i, + sort_info[i].path); } /* make another pass expanding the children as needed. diff --git a/widgets/table/e-tree-model.h b/widgets/table/e-tree-model.h index 13857e6707..d3cfa6665b 100644 --- a/widgets/table/e-tree-model.h +++ b/widgets/table/e-tree-model.h @@ -13,19 +13,14 @@ typedef struct ETreePath ETreePath; typedef struct ETreeModel ETreeModel; +typedef struct ETreeModelPriv ETreeModelPriv; typedef struct ETreeModelClass ETreeModelClass; typedef gint (*ETreePathCompareFunc)(ETreeModel *model, ETreePath *path1, ETreePath *path2); typedef gboolean (*ETreePathFunc)(ETreeModel *model, ETreePath *path, gpointer data); struct ETreeModel { ETableModel base; - ETreePath *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 */ - GString *sort_group; /* for caching the last sort group info */ + ETreeModelPriv *priv; }; struct ETreeModelClass { @@ -71,9 +66,9 @@ struct ETreeModelClass { }; -GtkType e_tree_model_get_type (void); +GtkType e_tree_model_get_type (void); void e_tree_model_construct (ETreeModel *etree); -ETreeModel *e_tree_model_new (void); +ETreeModel *e_tree_model_new (void); /* tree traversal operations */ ETreePath *e_tree_model_get_root (ETreeModel *etree); @@ -93,6 +88,7 @@ gboolean e_tree_model_node_is_root (ETreeModel *etree, ETreePath gboolean e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath *path); gboolean e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path); gboolean e_tree_model_node_is_visible (ETreeModel *etree, ETreePath *path); +void e_tree_model_set_expanded_default (ETreeModel *etree, gboolean expanded); void e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded); void e_tree_model_node_set_expanded_recurse (ETreeModel *etree, ETreePath *path, gboolean expanded); guint e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths); |