1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* e-tree-model-generator.c - Model wrapper that permutes underlying rows.
5 * Copyright (C) 2005 Novell, Inc.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * Authors: Hans Petter Jansson <hpj@novell.com>
28 #include <glib/gi18n-lib.h>
29 #include <gtk/gtktreemodel.h>
30 #include <gtk/gtksignal.h>
31 #include "e-tree-model-generator.h"
35 #define ITER_IS_VALID(tree_model_generator, iter) ((iter)->stamp == (tree_model_generator)->stamp)
36 #define ITER_GET(iter, group, index) \
38 *(group) = (iter)->user_data; \
39 *(index) = GPOINTER_TO_INT ((iter)->user_data2); \
42 #define ITER_SET(tree_model_generator, iter, group, index) \
44 (iter)->stamp = (tree_model_generator)->stamp; \
45 (iter)->user_data = group; \
46 (iter)->user_data2 = GINT_TO_POINTER (index); \
49 static void e_tree_model_generator_init (ETreeModelGenerator *tree_model_generator);
50 static void e_tree_model_generator_class_init (ETreeModelGeneratorClass *class);
51 static void e_tree_model_generator_tree_model_init (GtkTreeModelIface *iface);
52 static void e_tree_model_generator_finalize (GObject *object);
53 static GtkTreeModelFlags e_tree_model_generator_get_flags (GtkTreeModel *tree_model);
54 static gint e_tree_model_generator_get_n_columns (GtkTreeModel *tree_model);
55 static GType e_tree_model_generator_get_column_type (GtkTreeModel *tree_model,
57 static gboolean e_tree_model_generator_get_iter (GtkTreeModel *tree_model,
60 static GtkTreePath *e_tree_model_generator_get_path (GtkTreeModel *tree_model,
62 static void e_tree_model_generator_get_value (GtkTreeModel *tree_model,
66 static gboolean e_tree_model_generator_iter_next (GtkTreeModel *tree_model,
68 static gboolean e_tree_model_generator_iter_children (GtkTreeModel *tree_model,
71 static gboolean e_tree_model_generator_iter_has_child (GtkTreeModel *tree_model,
73 static gint e_tree_model_generator_iter_n_children (GtkTreeModel *tree_model,
75 static gboolean e_tree_model_generator_iter_nth_child (GtkTreeModel *tree_model,
79 static gboolean e_tree_model_generator_iter_parent (GtkTreeModel *tree_model,
83 static GArray *build_node_map (ETreeModelGenerator *tree_model_generator, GtkTreeIter *parent_iter,
84 GArray *parent_group, gint parent_index);
85 static void release_node_map (GArray *group);
87 static void child_row_changed (ETreeModelGenerator *tree_model_generator, GtkTreePath *path, GtkTreeIter *iter);
88 static void child_row_inserted (ETreeModelGenerator *tree_model_generator, GtkTreePath *path, GtkTreeIter *iter);
89 static void child_row_deleted (ETreeModelGenerator *tree_model_generator, GtkTreePath *path);
105 /* ------------------ *
106 * Class/object setup *
107 * ------------------ */
109 static GObjectClass *parent_class = NULL;
112 e_tree_model_generator_get_property (GObject *object, guint prop_id,
113 GValue *value, GParamSpec *pspec)
115 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (object);
119 case PROP_CHILD_MODEL:
120 g_value_set_object (value, tree_model_generator->child_model);
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
130 e_tree_model_generator_set_property (GObject *object, guint prop_id,
131 const GValue *value, GParamSpec *pspec)
133 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (object);
137 case PROP_CHILD_MODEL:
138 tree_model_generator->child_model = g_value_get_object (value);
139 g_object_ref (tree_model_generator->child_model);
141 if (tree_model_generator->root_nodes)
142 release_node_map (tree_model_generator->root_nodes);
143 tree_model_generator->root_nodes =
144 build_node_map (tree_model_generator, NULL, NULL, -1);
146 g_signal_connect_swapped (tree_model_generator->child_model, "row-changed",
147 G_CALLBACK (child_row_changed), tree_model_generator);
148 g_signal_connect_swapped (tree_model_generator->child_model, "row-deleted",
149 G_CALLBACK (child_row_deleted), tree_model_generator);
150 g_signal_connect_swapped (tree_model_generator->child_model, "row-inserted",
151 G_CALLBACK (child_row_inserted), tree_model_generator);
155 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
161 e_tree_model_generator_get_type (void)
163 static GType tree_model_generator_type = 0;
165 if (!tree_model_generator_type) {
166 static const GTypeInfo tree_model_generator_info =
168 sizeof (ETreeModelGeneratorClass),
169 NULL, /* base_init */
170 NULL, /* base_finalize */
171 (GClassInitFunc) e_tree_model_generator_class_init,
172 NULL, /* class_finalize */
173 NULL, /* class_data */
174 sizeof (ETreeModelGenerator),
176 (GInstanceInitFunc) e_tree_model_generator_init,
179 static const GInterfaceInfo tree_model_info =
181 (GInterfaceInitFunc) e_tree_model_generator_tree_model_init,
186 tree_model_generator_type = g_type_register_static (G_TYPE_OBJECT, "ETreeModelGenerator",
187 &tree_model_generator_info, 0);
188 g_type_add_interface_static (tree_model_generator_type,
193 return tree_model_generator_type;
197 e_tree_model_generator_class_init (ETreeModelGeneratorClass *class)
199 GObjectClass *object_class;
201 parent_class = g_type_class_peek_parent (class);
202 object_class = (GObjectClass *) class;
204 object_class->get_property = e_tree_model_generator_get_property;
205 object_class->set_property = e_tree_model_generator_set_property;
206 object_class->finalize = e_tree_model_generator_finalize;
208 g_object_class_install_property (object_class, PROP_CHILD_MODEL,
209 g_param_spec_object ("child-model",
211 "The child model to extend",
213 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
217 e_tree_model_generator_tree_model_init (GtkTreeModelIface *iface)
219 iface->get_flags = e_tree_model_generator_get_flags;
220 iface->get_n_columns = e_tree_model_generator_get_n_columns;
221 iface->get_column_type = e_tree_model_generator_get_column_type;
222 iface->get_iter = e_tree_model_generator_get_iter;
223 iface->get_path = e_tree_model_generator_get_path;
224 iface->get_value = e_tree_model_generator_get_value;
225 iface->iter_next = e_tree_model_generator_iter_next;
226 iface->iter_children = e_tree_model_generator_iter_children;
227 iface->iter_has_child = e_tree_model_generator_iter_has_child;
228 iface->iter_n_children = e_tree_model_generator_iter_n_children;
229 iface->iter_nth_child = e_tree_model_generator_iter_nth_child;
230 iface->iter_parent = e_tree_model_generator_iter_parent;
234 e_tree_model_generator_init (ETreeModelGenerator *tree_model_generator)
236 tree_model_generator->stamp = g_random_int ();
237 tree_model_generator->root_nodes = g_array_new (FALSE, FALSE, sizeof (Node));
241 e_tree_model_generator_finalize (GObject *object)
243 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (object);
245 if (tree_model_generator->child_model) {
246 g_signal_handlers_disconnect_matched (tree_model_generator->child_model,
247 G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
248 tree_model_generator);
249 g_object_unref (tree_model_generator->child_model);
252 if (tree_model_generator->root_nodes)
253 release_node_map (tree_model_generator->root_nodes);
255 if (G_OBJECT_CLASS (parent_class)->finalize)
256 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
259 /* ------------------ *
260 * Row update helpers *
261 * ------------------ */
264 row_deleted (ETreeModelGenerator *tree_model_generator, GtkTreePath *path)
268 ETMG_DEBUG (g_print ("row_deleted emitting\n"));
269 gtk_tree_model_row_deleted (GTK_TREE_MODEL (tree_model_generator), path);
273 row_inserted (ETreeModelGenerator *tree_model_generator, GtkTreePath *path)
279 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model_generator), &iter, path)) {
280 ETMG_DEBUG (g_print ("row_inserted emitting\n"));
281 gtk_tree_model_row_inserted (GTK_TREE_MODEL (tree_model_generator), path, &iter);
283 ETMG_DEBUG (g_print ("row_inserted could not get iter!\n"));
288 row_changed (ETreeModelGenerator *tree_model_generator, GtkTreePath *path)
294 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model_generator), &iter, path)) {
295 ETMG_DEBUG (g_print ("row_changed emitting\n"));
296 gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_model_generator), path, &iter);
298 ETMG_DEBUG (g_print ("row_changed could not get iter!\n"));
302 /* -------------------- *
303 * Node map translation *
304 * -------------------- */
307 generated_offset_to_child_offset (GArray *group, gint offset, gint *internal_offset)
309 gboolean success = FALSE;
310 gint accum_offset = 0;
313 for (i = 0; i < group->len; i++) {
314 Node *node = &g_array_index (group, Node, i);
316 accum_offset += node->n_generated;
317 if (accum_offset > offset) {
318 accum_offset -= node->n_generated;
328 *internal_offset = offset - accum_offset;
334 child_offset_to_generated_offset (GArray *group, gint offset)
336 gint accum_offset = 0;
339 for (i = 0; i < group->len && i < offset; i++) {
340 Node *node = &g_array_index (group, Node, i);
342 accum_offset += node->n_generated;
349 count_generated_nodes (GArray *group)
351 gint accum_offset = 0;
354 for (i = 0; i < group->len; i++) {
355 Node *node = &g_array_index (group, Node, i);
357 accum_offset += node->n_generated;
363 /* ------------------- *
364 * Node map management *
365 * ------------------- */
368 release_node_map (GArray *group)
372 for (i = 0; i < group->len; i++) {
373 Node *node = &g_array_index (group, Node, i);
375 if (node->child_nodes)
376 release_node_map (node->child_nodes);
379 g_array_free (group, TRUE);
383 append_node (GArray *group)
385 g_array_set_size (group, group->len + 1);
386 return group->len - 1;
390 build_node_map (ETreeModelGenerator *tree_model_generator, GtkTreeIter *parent_iter,
391 GArray *parent_group, gint parent_index)
398 result = gtk_tree_model_iter_children (tree_model_generator->child_model, &iter, parent_iter);
400 result = gtk_tree_model_get_iter_first (tree_model_generator->child_model, &iter);
405 group = g_array_new (FALSE, FALSE, sizeof (Node));
411 i = append_node (group);
412 node = &g_array_index (group, Node, i);
414 node->parent_group = parent_group;
415 node->parent_index = parent_index;
417 if (tree_model_generator->generate_func)
419 tree_model_generator->generate_func (tree_model_generator->child_model,
420 &iter, tree_model_generator->generate_func_data);
422 node->n_generated = 1;
424 node->child_nodes = build_node_map (tree_model_generator, &iter, group, i);
425 } while (gtk_tree_model_iter_next (tree_model_generator->child_model, &iter));
431 get_first_visible_index_from (GArray *group, gint index)
435 for (i = index; i < group->len; i++) {
436 Node *node = &g_array_index (group, Node, i);
438 if (node->n_generated)
449 get_node_by_child_path (ETreeModelGenerator *tree_model_generator, GtkTreePath *path, GArray **node_group)
455 group = tree_model_generator->root_nodes;
457 for (depth = 0; depth < gtk_tree_path_get_depth (path); depth++) {
461 g_warning ("ETreeModelGenerator got unknown child element!");
465 index = gtk_tree_path_get_indices (path) [depth];
466 node = &g_array_index (group, Node, index);
468 if (depth + 1 < gtk_tree_path_get_depth (path))
469 group = node->child_nodes;
482 create_node_at_child_path (ETreeModelGenerator *tree_model_generator, GtkTreePath *path)
484 GtkTreePath *parent_path;
486 GArray *parent_group;
491 parent_path = gtk_tree_path_copy (path);
492 gtk_tree_path_up (parent_path);
493 node = get_node_by_child_path (tree_model_generator, parent_path, &parent_group);
496 if (!node->child_nodes)
497 node->child_nodes = g_array_new (FALSE, FALSE, sizeof (Node));
499 group = node->child_nodes;
500 parent_index = gtk_tree_path_get_indices (parent_path) [gtk_tree_path_get_depth (parent_path) - 1];
502 if (!tree_model_generator->root_nodes)
503 tree_model_generator->root_nodes = g_array_new (FALSE, FALSE, sizeof (Node));
505 group = tree_model_generator->root_nodes;
509 gtk_tree_path_free (parent_path);
511 index = gtk_tree_path_get_indices (path) [gtk_tree_path_get_depth (path) - 1];
512 ETMG_DEBUG (g_print ("Inserting index %d into group of length %d\n", index, group->len));
513 index = MIN (index, group->len);
517 if (group->len - 1 - index > 0) {
520 memmove ((Node *) group->data + index + 1,
521 (Node *) group->data + index,
522 (group->len - 1 - index) * sizeof (Node));
524 /* Update parent pointers */
525 for (i = index + 1; i < group->len; i++) {
526 Node *pnode = &g_array_index (group, Node, i);
530 child_group = pnode->child_nodes;
534 for (j = 0; j < child_group->len; j++) {
535 Node *child_node = &g_array_index (child_group, Node, j);
536 child_node->parent_index = i;
541 node = &g_array_index (group, Node, index);
542 node->parent_group = parent_group;
543 node->parent_index = parent_index;
544 node->n_generated = 0;
545 node->child_nodes = NULL;
547 ETMG_DEBUG (g_print ("Created node at offset %d, parent_group = %p, parent_index = %d\n",
548 index, node->parent_group, node->parent_index));
556 dump_group (GArray *group)
560 g_print ("\nGroup %p:\n", group);
562 for (i = 0; i < group->len; i++) {
563 Node *node = &g_array_index (group, Node, i);
564 g_print (" %04d: pgroup=%p, pindex=%d, n_generated=%d, child_nodes=%p\n",
565 i, node->parent_group, node->parent_index, node->n_generated, node->child_nodes);
572 delete_node_at_child_path (ETreeModelGenerator *tree_model_generator, GtkTreePath *path)
574 GtkTreePath *parent_path;
576 GArray *parent_group;
582 parent_path = gtk_tree_path_copy (path);
583 gtk_tree_path_up (parent_path);
584 node = get_node_by_child_path (tree_model_generator, parent_path, &parent_group);
587 group = node->child_nodes;
588 parent_index = gtk_tree_path_get_indices (parent_path) [gtk_tree_path_get_depth (parent_path) - 1];
590 group = tree_model_generator->root_nodes;
594 gtk_tree_path_free (parent_path);
599 index = gtk_tree_path_get_indices (path) [gtk_tree_path_get_depth (path) - 1];
600 if (index >= group->len)
603 node = &g_array_index (group, Node, index);
604 if (node->child_nodes)
605 release_node_map (node->child_nodes);
606 g_array_remove_index (group, index);
608 /* Update parent pointers */
609 for (i = index; i < group->len; i++) {
610 Node *pnode = &g_array_index (group, Node, i);
614 child_group = pnode->child_nodes;
618 for (j = 0; j < child_group->len; j++) {
619 Node *child_node = &g_array_index (child_group, Node, j);
620 child_node->parent_index = i;
626 child_row_changed (ETreeModelGenerator *tree_model_generator, GtkTreePath *path, GtkTreeIter *iter)
628 GtkTreePath *generated_path;
633 if (tree_model_generator->generate_func)
635 tree_model_generator->generate_func (tree_model_generator->child_model,
636 iter, tree_model_generator->generate_func_data);
640 node = get_node_by_child_path (tree_model_generator, path, NULL);
644 generated_path = e_tree_model_generator_convert_child_path_to_path (tree_model_generator, path);
646 /* FIXME: Converting the path to an iter every time is inefficient */
648 for (i = 0; i < n_generated && i < node->n_generated; i++) {
649 row_changed (tree_model_generator, generated_path);
650 gtk_tree_path_next (generated_path);
653 for ( ; i < node->n_generated; ) {
655 row_deleted (tree_model_generator, generated_path);
658 for ( ; i < n_generated; i++) {
660 row_inserted (tree_model_generator, generated_path);
661 gtk_tree_path_next (generated_path);
664 gtk_tree_path_free (generated_path);
668 child_row_inserted (ETreeModelGenerator *tree_model_generator, GtkTreePath *path, GtkTreeIter *iter)
670 GtkTreePath *generated_path;
674 if (tree_model_generator->generate_func)
676 tree_model_generator->generate_func (tree_model_generator->child_model,
677 iter, tree_model_generator->generate_func_data);
681 node = create_node_at_child_path (tree_model_generator, path);
685 generated_path = e_tree_model_generator_convert_child_path_to_path (tree_model_generator, path);
687 /* FIXME: Converting the path to an iter every time is inefficient */
689 for (node->n_generated = 0; node->n_generated < n_generated; ) {
691 row_inserted (tree_model_generator, generated_path);
692 gtk_tree_path_next (generated_path);
695 gtk_tree_path_free (generated_path);
699 child_row_deleted (ETreeModelGenerator *tree_model_generator, GtkTreePath *path)
701 GtkTreePath *generated_path;
704 node = get_node_by_child_path (tree_model_generator, path, NULL);
708 generated_path = e_tree_model_generator_convert_child_path_to_path (tree_model_generator, path);
710 /* FIXME: Converting the path to an iter every time is inefficient */
712 for ( ; node->n_generated; ) {
714 row_deleted (tree_model_generator, generated_path);
717 delete_node_at_child_path (tree_model_generator, path);
718 gtk_tree_path_free (generated_path);
721 /* ----------------------- *
722 * ETreeModelGenerator API *
723 * ----------------------- */
726 * e_tree_model_generator_new:
727 * @child_model: a #GtkTreeModel
729 * Creates a new #ETreeModelGenerator wrapping @child_model.
731 * Return value: A new #ETreeModelGenerator.
733 ETreeModelGenerator *
734 e_tree_model_generator_new (GtkTreeModel *child_model)
736 g_return_val_if_fail (GTK_IS_TREE_MODEL (child_model), NULL);
738 return E_TREE_MODEL_GENERATOR (g_object_new (E_TYPE_TREE_MODEL_GENERATOR,
739 "child-model", child_model, NULL));
743 * e_tree_model_generator_get_model:
744 * @tree_model_generator: an #ETreeModelGenerator
746 * Gets the child model being wrapped by @tree_model_generator.
748 * Return value: A #GtkTreeModel being wrapped.
751 e_tree_model_generator_get_model (ETreeModelGenerator *tree_model_generator)
753 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator), NULL);
755 return tree_model_generator->child_model;
759 * e_tree_model_generator_set_generate_func:
760 * @tree_model_generator: an #ETreeModelGenerator
761 * @func: an #ETreeModelGeneratorGenerateFunc, or %NULL
762 * @data: user data to pass to @func
765 * Sets the callback function used to filter or generate additional rows
766 * based on the child model's data. This function is called for each child
767 * row, and returns a value indicating the number of rows that will be
768 * used to represent the child row - 0 or more.
770 * If @func is %NULL, a filtering/generating function will not be applied.
773 e_tree_model_generator_set_generate_func (ETreeModelGenerator *tree_model_generator,
774 ETreeModelGeneratorGenerateFunc func,
775 gpointer data, GtkDestroyNotify destroy)
777 g_return_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator));
779 tree_model_generator->generate_func = func;
780 tree_model_generator->generate_func_data = data;
784 * e_tree_model_generator_set_modify_func:
785 * @tree_model_generator: an #ETreeModelGenerator
786 * @func: an @ETreeModelGeneratorModifyFunc, or %NULL
787 * @data: user data to pass to @func
790 * Sets the callback function used to override values for the child row's
791 * columns and specify values for generated rows' columns.
793 * If @func is %NULL, the child model's values will always be used.
796 e_tree_model_generator_set_modify_func (ETreeModelGenerator *tree_model_generator,
797 ETreeModelGeneratorModifyFunc func,
798 gpointer data, GtkDestroyNotify destroy)
800 g_return_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator));
802 tree_model_generator->modify_func = func;
803 tree_model_generator->modify_func_data = data;
807 * e_tree_model_generator_convert_child_path_to_path:
808 * @tree_model_generator: an #ETreeModelGenerator
809 * @child_path: a #GtkTreePath
811 * Convert a path to a child row to a path to a @tree_model_generator row.
813 * Return value: A new GtkTreePath, owned by the caller.
816 e_tree_model_generator_convert_child_path_to_path (ETreeModelGenerator *tree_model_generator,
817 GtkTreePath *child_path)
823 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator), NULL);
824 g_return_val_if_fail (child_path != NULL, NULL);
826 path = gtk_tree_path_new ();
828 group = tree_model_generator->root_nodes;
830 for (depth = 0; depth < gtk_tree_path_get_depth (child_path); depth++) {
833 gint generated_index;
836 g_warning ("ETreeModelGenerator was asked for path to unknown child element!");
840 index = gtk_tree_path_get_indices (child_path) [depth];
841 generated_index = child_offset_to_generated_offset (group, index);
842 node = &g_array_index (group, Node, index);
843 group = node->child_nodes;
845 gtk_tree_path_append_index (path, generated_index);
852 * e_tree_model_generator_convert_child_iter_to_iter:
853 * @tree_model_generator: an #ETreeModelGenerator
854 * @generator_iter: a #GtkTreeIter to set
855 * @child_iter: a #GtkTreeIter to convert
857 * Convert @child_iter to a corresponding #GtkTreeIter for @tree_model_generator,
858 * storing the result in @generator_iter.
861 e_tree_model_generator_convert_child_iter_to_iter (ETreeModelGenerator *tree_model_generator,
862 GtkTreeIter *generator_iter,
863 GtkTreeIter *child_iter)
870 g_return_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator));
872 path = gtk_tree_model_get_path (tree_model_generator->child_model, child_iter);
876 group = tree_model_generator->root_nodes;
878 for (depth = 0; depth < gtk_tree_path_get_depth (path); depth++) {
881 index = gtk_tree_path_get_indices (path) [depth];
882 node = &g_array_index (group, Node, index);
884 if (depth + 1 < gtk_tree_path_get_depth (path))
885 group = node->child_nodes;
888 g_warning ("ETreeModelGenerator was asked for iter to unknown child element!");
893 index = child_offset_to_generated_offset (group, index);
894 ITER_SET (tree_model_generator, generator_iter, group, index);
895 gtk_tree_path_free (path);
899 * e_tree_model_generator_convert_path_to_child_path:
900 * @tree_model_generator: an #ETreeModelGenerator
901 * @generator_path: a #GtkTreePath to a @tree_model_generator row
903 * Converts @generator_path to a corresponding #GtkTreePath in the child model.
905 * Return value: A new #GtkTreePath, owned by the caller.
908 e_tree_model_generator_convert_path_to_child_path (ETreeModelGenerator *tree_model_generator,
909 GtkTreePath *generator_path)
915 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator), NULL);
916 g_return_val_if_fail (generator_path != NULL, NULL);
918 path = gtk_tree_path_new ();
920 group = tree_model_generator->root_nodes;
922 for (depth = 0; depth < gtk_tree_path_get_depth (generator_path); depth++) {
928 g_warning ("ETreeModelGenerator was asked for path to unknown child element!");
932 index = gtk_tree_path_get_indices (generator_path) [depth];
933 child_index = generated_offset_to_child_offset (group, index, NULL);
934 node = &g_array_index (group, Node, child_index);
935 group = node->child_nodes;
937 gtk_tree_path_append_index (path, child_index);
944 * e_tree_model_generator_convert_iter_to_child_iter:
945 * @tree_model_generator: an #ETreeModelGenerator
946 * @child_iter: a #GtkTreeIter to set
947 * @permutation_n: a permutation index to set
948 * @generator_iter: a #GtkTreeIter indicating the row to convert
950 * Converts a @tree_model_generator row into a child row and permutation index.
951 * The permutation index is the index of the generated row based on this
952 * child row, with the first generated row based on this child row being 0.
955 e_tree_model_generator_convert_iter_to_child_iter (ETreeModelGenerator *tree_model_generator,
956 GtkTreeIter *child_iter,
958 GtkTreeIter *generator_iter)
962 gint generator_index;
964 gint internal_offset;
966 g_return_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model_generator));
967 g_return_if_fail (ITER_IS_VALID (tree_model_generator, generator_iter));
969 path = gtk_tree_path_new ();
970 ITER_GET (generator_iter, &group, &index);
972 generator_index = index;
973 index = generated_offset_to_child_offset (group, index, &internal_offset);
974 gtk_tree_path_prepend_index (path, index);
976 ETMG_DEBUG (g_print ("iter_to_child_iter: %d -> %d (%d)\n", generator_index, index, internal_offset));
979 Node *node = &g_array_index (group, Node, index);
981 group = node->parent_group;
982 index = node->parent_index;
985 gtk_tree_path_prepend_index (path, index);
989 gtk_tree_model_get_iter (tree_model_generator->child_model, child_iter, path);
991 *permutation_n = internal_offset;
993 gtk_tree_path_free (path);
996 /* ---------------- *
998 * ---------------- */
1000 static GtkTreeModelFlags
1001 e_tree_model_generator_get_flags (GtkTreeModel *tree_model)
1003 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1005 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), 0);
1007 return gtk_tree_model_get_flags (tree_model_generator->child_model);
1011 e_tree_model_generator_get_n_columns (GtkTreeModel *tree_model)
1013 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1015 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), 0);
1017 return gtk_tree_model_get_n_columns (tree_model_generator->child_model);
1021 e_tree_model_generator_get_column_type (GtkTreeModel *tree_model,
1024 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1026 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), G_TYPE_INVALID);
1028 return gtk_tree_model_get_column_type (tree_model_generator->child_model, index);
1032 e_tree_model_generator_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
1034 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1039 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1040 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
1042 group = tree_model_generator->root_nodes;
1046 for (depth = 0; depth < gtk_tree_path_get_depth (path); depth++) {
1050 index = gtk_tree_path_get_indices (path) [depth];
1051 child_index = generated_offset_to_child_offset (group, index, NULL);
1052 if (child_index < 0)
1055 node = &g_array_index (group, Node, child_index);
1057 if (depth + 1 < gtk_tree_path_get_depth (path)) {
1058 group = node->child_nodes;
1064 ITER_SET (tree_model_generator, iter, group, index);
1068 static GtkTreePath *
1069 e_tree_model_generator_get_path (GtkTreeModel *tree_model,
1072 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1077 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), NULL);
1078 g_return_val_if_fail (ITER_IS_VALID (tree_model_generator, iter), NULL);
1080 ITER_GET (iter, &group, &index);
1081 path = gtk_tree_path_new ();
1083 /* FIXME: Converting a path to an iter is a destructive operation, because
1084 * we don't store a node for each generated entry... Doesn't matter for
1085 * lists, not sure about trees. */
1087 gtk_tree_path_prepend_index (path, index);
1088 index = generated_offset_to_child_offset (group, index, NULL);
1091 Node *node = &g_array_index (group, Node, index);
1092 gint generated_index;
1094 group = node->parent_group;
1095 index = node->parent_index;
1096 generated_index = child_offset_to_generated_offset (group, index);
1099 gtk_tree_path_prepend_index (path, generated_index);
1106 e_tree_model_generator_iter_next (GtkTreeModel *tree_model,
1109 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1114 gint internal_offset;
1116 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1117 g_return_val_if_fail (ITER_IS_VALID (tree_model_generator, iter), FALSE);
1119 ITER_GET (iter, &group, &index);
1120 child_index = generated_offset_to_child_offset (group, index, &internal_offset);
1121 node = &g_array_index (group, Node, child_index);
1123 if (internal_offset + 1 < node->n_generated ||
1124 get_first_visible_index_from (group, child_index + 1) >= 0) {
1125 ITER_SET (tree_model_generator, iter, group, index + 1);
1133 e_tree_model_generator_iter_children (GtkTreeModel *tree_model,
1135 GtkTreeIter *parent)
1137 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1142 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1145 if (!tree_model_generator->root_nodes ||
1146 !count_generated_nodes (tree_model_generator->root_nodes))
1149 ITER_SET (tree_model_generator, iter, tree_model_generator->root_nodes, 0);
1153 ITER_GET (parent, &group, &index);
1154 index = generated_offset_to_child_offset (group, index, NULL);
1158 node = &g_array_index (group, Node, index);
1160 if (!node->child_nodes)
1163 if (!count_generated_nodes (node->child_nodes))
1166 ITER_SET (tree_model_generator, iter, node->child_nodes, 0);
1171 e_tree_model_generator_iter_has_child (GtkTreeModel *tree_model,
1174 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1179 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1182 if (!tree_model_generator->root_nodes ||
1183 !count_generated_nodes (tree_model_generator->root_nodes))
1189 ITER_GET (iter, &group, &index);
1190 index = generated_offset_to_child_offset (group, index, NULL);
1194 node = &g_array_index (group, Node, index);
1196 if (!node->child_nodes)
1199 if (!count_generated_nodes (node->child_nodes))
1206 e_tree_model_generator_iter_n_children (GtkTreeModel *tree_model,
1209 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1214 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1217 return tree_model_generator->root_nodes ?
1218 count_generated_nodes (tree_model_generator->root_nodes) : 0;
1220 ITER_GET (iter, &group, &index);
1221 index = generated_offset_to_child_offset (group, index, NULL);
1225 node = &g_array_index (group, Node, index);
1227 if (!node->child_nodes)
1230 return count_generated_nodes (node->child_nodes);
1234 e_tree_model_generator_iter_nth_child (GtkTreeModel *tree_model,
1236 GtkTreeIter *parent,
1239 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1244 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1247 if (!tree_model_generator->root_nodes)
1250 if (n >= count_generated_nodes (tree_model_generator->root_nodes))
1253 ITER_SET (tree_model_generator, iter, tree_model_generator->root_nodes, n);
1257 ITER_GET (parent, &group, &index);
1258 index = generated_offset_to_child_offset (group, index, NULL);
1262 node = &g_array_index (group, Node, index);
1264 if (!node->child_nodes)
1267 if (n >= count_generated_nodes (node->child_nodes))
1270 ITER_SET (tree_model_generator, iter, node->child_nodes, n);
1275 e_tree_model_generator_iter_parent (GtkTreeModel *tree_model,
1279 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1284 g_return_val_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model), FALSE);
1285 g_return_val_if_fail (ITER_IS_VALID (tree_model_generator, iter), FALSE);
1287 ITER_GET (child, &group, &index);
1288 index = generated_offset_to_child_offset (group, index, NULL);
1292 node = &g_array_index (group, Node, index);
1294 group = node->parent_group;
1298 ITER_SET (tree_model_generator, iter, group, node->parent_index);
1303 e_tree_model_generator_get_value (GtkTreeModel *tree_model,
1308 ETreeModelGenerator *tree_model_generator = E_TREE_MODEL_GENERATOR (tree_model);
1309 GtkTreeIter child_iter;
1312 g_return_if_fail (E_IS_TREE_MODEL_GENERATOR (tree_model));
1313 g_return_if_fail (ITER_IS_VALID (tree_model_generator, iter));
1315 e_tree_model_generator_convert_iter_to_child_iter (tree_model_generator, &child_iter,
1316 &permutation_n, iter);
1318 if (tree_model_generator->modify_func) {
1319 tree_model_generator->modify_func (tree_model_generator->child_model,
1320 &child_iter, permutation_n,
1322 tree_model_generator->modify_func_data);
1326 gtk_tree_model_get_value (tree_model_generator->child_model, &child_iter, column, value);