2 * eggtreemodelunion.c: Union treemodel implementation
4 * Copyright (C) 2003, Kristian Rietveld
9 * - there is a nasty bug in here which I can't easily repro. Need to
11 * - need to implement_set_child
15 #include "eggtreemodelunion.h"
17 #include <glib/gprintf.h>
18 #include <string.h> /* for memcpy */
21 typedef struct _ModelMap ModelMap
;
32 #define MODEL_MAP(map) ((ModelMap *)map)
35 * iter->stamp = umodel->stamp
36 * iter->user_data = ModelMap
37 * iter->user_data2 = offset relative to child_model
38 * iter->user_data3 = index in the child hash.
40 * Iters will be invalidated on insertion/deletion of rows.
44 /* object construction/deconstruction */
45 static void egg_tree_model_union_init (EggTreeModelUnion
*umodel
);
46 static void egg_tree_model_union_class_init (EggTreeModelUnionClass
*u_class
);
47 static void egg_tree_model_union_model_init (GtkTreeModelIface
*iface
);
49 static void egg_tree_model_union_finalize (GObject
*object
);
52 static void egg_tree_model_union_set_n_columns (EggTreeModelUnion
*umodel
,
54 static void egg_tree_model_union_set_column_type (EggTreeModelUnion
*umodel
,
57 static void model_map_free (ModelMap
*map
);
58 static GtkTreePath
*get_path_from_hash (EggTreeModelUnion
*umodel
,
60 static gchar
*path_to_string_without_first (GtkTreePath
*path
);
61 static void egg_tree_model_union_update_stamp (EggTreeModelUnion
*umodel
);
62 static ModelMap
*egg_tree_model_union_get_map_from_offset (EggTreeModelUnion
*umodel
,
64 static ModelMap
*egg_tree_model_union_get_map_from_iter (GtkTreeIter
*iter
);
65 static void egg_tree_model_union_convert_iter_to_child_iter(EggTreeModelUnion
*umodel
,
66 GtkTreeIter
*child_iter
,
67 GtkTreeIter
*union_iter
);
68 static gint
egg_tree_model_union_convert_to_child_column (EggTreeModelUnion
*umodel
,
71 static gboolean
egg_tree_model_union_column_check (EggTreeModelUnion
*umodel
,
73 gint
*column_mapping
);
74 static void egg_tree_model_union_emit_inserted (EggTreeModelUnion
*umodel
,
77 static void egg_tree_model_union_emit_deleted (EggTreeModelUnion
*umodel
,
81 /* TreeModel signals */
82 static void egg_tree_model_union_row_changed (GtkTreeModel
*c_model
,
86 static void egg_tree_model_union_row_inserted (GtkTreeModel
*c_model
,
90 static void egg_tree_model_union_row_deleted (GtkTreeModel
*c_model
,
93 static void egg_tree_model_union_row_has_child_toggled (GtkTreeModel
*c_model
,
97 static void egg_tree_model_union_rows_reordered (GtkTreeModel
*c_model
,
102 /* TreeModelIface impl */
103 static guint
egg_tree_model_union_get_flags (GtkTreeModel
*model
);
104 static gint
egg_tree_model_union_get_n_columns (GtkTreeModel
*model
);
105 static GType
egg_tree_model_union_get_column_type (GtkTreeModel
*model
,
107 static gboolean
egg_tree_model_union_get_iter (GtkTreeModel
*model
,
110 static GtkTreePath
*egg_tree_model_union_get_path (GtkTreeModel
*model
,
112 static void egg_tree_model_union_get_value (GtkTreeModel
*model
,
116 static gboolean
egg_tree_model_union_iter_next (GtkTreeModel
*model
,
118 static gboolean
egg_tree_model_union_iter_children (GtkTreeModel
*model
,
120 GtkTreeIter
*parent
);
121 static gboolean
egg_tree_model_union_iter_has_child (GtkTreeModel
*model
,
123 static gint
egg_tree_model_union_iter_n_children (GtkTreeModel
*model
,
125 static gboolean
egg_tree_model_union_iter_nth_child (GtkTreeModel
*model
,
129 static gboolean
egg_tree_model_union_iter_parent (GtkTreeModel
*model
,
132 static void egg_tree_model_union_ref_node (GtkTreeModel
*model
,
134 static void egg_tree_model_union_unref_node (GtkTreeModel
*model
,
138 static GObjectClass
*parent_class
= NULL
;
141 egg_tree_model_union_get_type (void)
143 static GType tree_model_union_type
= 0;
145 if (!tree_model_union_type
)
147 static const GTypeInfo tree_model_union_info
=
149 sizeof (EggTreeModelUnionClass
),
152 (GClassInitFunc
) egg_tree_model_union_class_init
,
155 sizeof (EggTreeModelUnion
),
157 (GInstanceInitFunc
) egg_tree_model_union_init
160 static const GInterfaceInfo tree_model_info
=
162 (GInterfaceInitFunc
) egg_tree_model_union_model_init
,
167 tree_model_union_type
= g_type_register_static (G_TYPE_OBJECT
,
169 &tree_model_union_info
, 0);
171 g_type_add_interface_static (tree_model_union_type
,
176 return tree_model_union_type
;
180 egg_tree_model_union_init (EggTreeModelUnion
*umodel
)
183 umodel
->childs
= NULL
;
185 umodel
->child_paths
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
186 g_free
, (GDestroyNotify
)gtk_tree_path_free
);
188 umodel
->n_columns
= 0;
189 umodel
->column_headers
= NULL
;
191 umodel
->stamp
= g_random_int ();
195 egg_tree_model_union_class_init (EggTreeModelUnionClass
*u_class
)
197 GObjectClass
*object_class
;
199 object_class
= G_OBJECT_CLASS (u_class
);
200 parent_class
= g_type_class_peek_parent (u_class
);
202 object_class
->finalize
= egg_tree_model_union_finalize
;
206 egg_tree_model_union_model_init (GtkTreeModelIface
*iface
)
208 iface
->get_flags
= egg_tree_model_union_get_flags
;
209 iface
->get_n_columns
= egg_tree_model_union_get_n_columns
;
210 iface
->get_column_type
= egg_tree_model_union_get_column_type
;
211 iface
->get_iter
= egg_tree_model_union_get_iter
;
212 iface
->get_path
= egg_tree_model_union_get_path
;
213 iface
->get_value
= egg_tree_model_union_get_value
;
214 iface
->iter_next
= egg_tree_model_union_iter_next
;
215 iface
->iter_children
= egg_tree_model_union_iter_children
;
216 iface
->iter_has_child
= egg_tree_model_union_iter_has_child
;
217 iface
->iter_n_children
= egg_tree_model_union_iter_n_children
;
218 iface
->iter_nth_child
= egg_tree_model_union_iter_nth_child
;
219 iface
->iter_parent
= egg_tree_model_union_iter_parent
;
220 iface
->ref_node
= egg_tree_model_union_ref_node
;
221 iface
->unref_node
= egg_tree_model_union_unref_node
;
226 egg_tree_model_union_finalize (GObject
*object
)
228 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*) object
;
230 egg_tree_model_union_clear (umodel
);
232 if (umodel
->column_headers
)
233 g_free (umodel
->column_headers
);
235 if (umodel
->child_paths
)
236 g_hash_table_destroy (umodel
->child_paths
);
239 parent_class
->finalize (object
);
244 egg_tree_model_union_set_n_columns (EggTreeModelUnion
*umodel
,
249 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
251 if (umodel
->n_columns
== n_columns
)
254 new_columns
= g_new0 (GType
, n_columns
);
255 if (umodel
->column_headers
)
257 /* copy the old header orders over */
258 if (n_columns
>= umodel
->n_columns
)
259 memcpy (new_columns
, umodel
->column_headers
, umodel
->n_columns
* sizeof (gchar
*));
261 memcpy (new_columns
, umodel
->column_headers
, n_columns
* sizeof (GType
));
263 g_free (umodel
->column_headers
);
266 umodel
->column_headers
= new_columns
;
267 umodel
->n_columns
= n_columns
;
271 egg_tree_model_union_set_column_type (EggTreeModelUnion
*umodel
,
275 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
276 g_return_if_fail (column
>= 0 && column
< umodel
->n_columns
);
278 umodel
->column_headers
[column
] = type
;
282 model_map_free (ModelMap
*map
)
284 if (map
->column_mapping
)
285 g_free (map
->column_mapping
);
291 get_path_from_hash (EggTreeModelUnion
*umodel
,
296 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
), NULL
);
298 ret
= g_hash_table_lookup (umodel
->child_paths
, str
);
303 ret
= gtk_tree_path_new_from_string (str
);
304 g_hash_table_insert (umodel
->child_paths
, g_strdup (str
), ret
);
310 path_to_string_without_first (GtkTreePath
*path
)
315 gint depth
= gtk_tree_path_get_depth (path
);
316 gint
*indices
= gtk_tree_path_get_indices (path
);
318 /* NOTE: we skip the first index here */
319 str
= ptr
= (gchar
*)g_new0 (gchar
, depth
* 8);
320 g_sprintf (str
, "%d", indices
[1]);
324 for (i
= 2; i
< depth
; i
++)
326 g_sprintf (ptr
, ":%d", indices
[i
]);
335 egg_tree_model_union_update_stamp (EggTreeModelUnion
*umodel
)
341 while (!umodel
->stamp
);
345 egg_tree_model_union_get_map_from_offset (EggTreeModelUnion
*umodel
,
350 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
), NULL
);
352 if (offset
< 0 || offset
>= umodel
->length
)
355 for (i
= umodel
->root
; i
; i
= i
->next
)
357 ModelMap
*map
= MODEL_MAP (i
->data
);
359 if (map
->offset
<= offset
360 && offset
< map
->offset
+ map
->nodes
)
368 egg_tree_model_union_get_map_from_iter (GtkTreeIter
*iter
)
370 return MODEL_MAP (iter
->user_data
);
374 egg_tree_model_union_get_map_from_model (EggTreeModelUnion
*umodel
,
379 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
), NULL
);
381 for (i
= umodel
->root
; i
; i
= i
->next
)
382 if (MODEL_MAP (i
->data
)->model
== model
)
383 return MODEL_MAP (i
->data
);
389 egg_tree_model_union_convert_iter_to_union_iter (EggTreeModelUnion
*umodel
,
391 GtkTreeIter
*child_iter
,
392 GtkTreeIter
*union_iter
)
397 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
398 g_return_if_fail (GTK_IS_TREE_MODEL (model
));
400 map
= egg_tree_model_union_get_map_from_model (umodel
, model
);
404 union_iter
->stamp
= 0;
408 path
= gtk_tree_model_get_path (model
, child_iter
);
411 union_iter
->stamp
= 0;
415 union_iter
->stamp
= umodel
->stamp
;
416 union_iter
->user_data
= map
;
417 union_iter
->user_data2
= GINT_TO_POINTER (gtk_tree_path_get_indices (path
)[0]);
419 if (gtk_tree_path_get_depth (path
) > 1)
421 gchar
*str
= path_to_string_without_first (path
);
423 union_iter
->user_data3
= get_path_from_hash (umodel
, str
);
427 union_iter
->user_data3
= NULL
;
429 gtk_tree_path_free (path
);
433 egg_tree_model_union_convert_iter_to_child_iter (EggTreeModelUnion
*umodel
,
434 GtkTreeIter
*child_iter
,
435 GtkTreeIter
*union_iter
)
440 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
441 g_return_if_fail (umodel
->stamp
== union_iter
->stamp
);
443 map
= egg_tree_model_union_get_map_from_iter (union_iter
);
445 if (union_iter
->user_data3
)
446 path
= gtk_tree_path_copy (union_iter
->user_data3
);
448 path
= gtk_tree_path_new ();
450 gtk_tree_path_prepend_index (path
, GPOINTER_TO_INT (union_iter
->user_data2
));
451 gtk_tree_model_get_iter (map
->model
, child_iter
, path
);
453 gtk_tree_path_free (path
);
457 egg_tree_model_union_convert_to_child_column (EggTreeModelUnion
*umodel
,
461 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
), 0);
462 g_return_val_if_fail (umodel
->stamp
== iter
->stamp
, 0);
463 g_return_val_if_fail (column
>= 0 && column
< umodel
->n_columns
, 0);
465 if (!MODEL_MAP (iter
->user_data
)->column_mapping
)
468 return (MODEL_MAP (iter
->user_data
))->column_mapping
[column
];
472 egg_tree_model_union_column_check (EggTreeModelUnion
*umodel
,
474 gint
*column_mapping
)
478 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
), FALSE
);
479 g_return_val_if_fail (GTK_IS_TREE_MODEL (model
), FALSE
);
481 for (i
= 0; i
< umodel
->n_columns
; i
++)
486 type
= gtk_tree_model_get_column_type (model
, column_mapping
[i
]);
488 type
= gtk_tree_model_get_column_type (model
, i
);
490 if (type
!= umodel
->column_headers
[i
])
498 egg_tree_model_union_emit_inserted (EggTreeModelUnion
*umodel
,
509 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
511 path
= gtk_tree_path_new_from_indices (start
, -1);
512 egg_tree_model_union_get_iter (GTK_TREE_MODEL (umodel
), &iter
, path
);
514 /* FIXME: do we need to emit inserted for child nodes? */
516 for (i
= 0; i
< length
; i
++)
518 gtk_tree_model_row_inserted (GTK_TREE_MODEL (umodel
), path
, &iter
);
519 gtk_tree_path_next (path
);
520 egg_tree_model_union_iter_next (GTK_TREE_MODEL (umodel
), &iter
);
523 gtk_tree_path_free (path
);
527 egg_tree_model_union_emit_deleted (EggTreeModelUnion
*umodel
,
537 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
539 path
= gtk_tree_path_new_from_indices (start
, -1);
541 /* FIXME: do we need to emit deleted for child nodes? */
543 for (i
= 0; i
< length
; i
++)
545 gtk_tree_model_row_deleted (GTK_TREE_MODEL (umodel
), path
);
546 gtk_tree_path_next (path
);
549 gtk_tree_path_free (path
);
552 /* TreeModel signals */
554 egg_tree_model_union_row_changed (GtkTreeModel
*c_model
,
559 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (data
);
563 g_return_if_fail (GTK_IS_TREE_MODEL (c_model
));
564 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (data
));
566 /* translate the iter to a union iter and pass the event on */
567 egg_tree_model_union_convert_iter_to_union_iter (umodel
, c_model
,
570 path
= egg_tree_model_union_get_path (GTK_TREE_MODEL (data
), &uiter
);
571 gtk_tree_model_row_changed (GTK_TREE_MODEL (data
), path
, &uiter
);
572 gtk_tree_path_free (path
);
576 egg_tree_model_union_row_inserted (GtkTreeModel
*c_model
,
583 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (data
);
585 g_return_if_fail (GTK_IS_TREE_MODEL (c_model
));
586 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (data
));
588 if (gtk_tree_path_get_depth (c_path
) > 1)
593 /* translate and propagate */
594 egg_tree_model_union_convert_iter_to_union_iter (umodel
,
598 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (data
), &uiter
);
599 gtk_tree_model_row_inserted (GTK_TREE_MODEL (data
), path
, &uiter
);
600 gtk_tree_path_free (path
);
605 for (i
= umodel
->root
; i
; i
= i
->next
)
606 if (MODEL_MAP (i
->data
)->model
== c_model
)
612 MODEL_MAP (i
->data
)->nodes
++;
613 position
= MODEL_MAP (i
->data
)->offset
;
615 for (i
= i
->next
; i
; i
= i
->next
)
616 MODEL_MAP (i
->data
)->offset
++;
618 position
+= gtk_tree_path_get_indices (c_path
)[0];
622 egg_tree_model_union_update_stamp (umodel
);
623 egg_tree_model_union_emit_inserted (umodel
, position
, 1);
627 egg_tree_model_union_row_deleted (GtkTreeModel
*c_model
,
633 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (data
);
635 g_return_if_fail (GTK_IS_TREE_MODEL (c_model
));
636 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (data
));
638 for (i
= umodel
->root
; i
; i
= i
->next
)
639 if (MODEL_MAP (i
->data
)->model
== c_model
)
645 if (gtk_tree_path_get_depth (c_path
) > 1)
647 GtkTreePath
*path
= gtk_tree_path_copy (c_path
);
649 gtk_tree_path_get_indices (path
)[0] += MODEL_MAP (i
->data
)->offset
;
650 gtk_tree_model_row_deleted (GTK_TREE_MODEL (data
), path
);
651 gtk_tree_path_free (path
);
656 MODEL_MAP (i
->data
)->nodes
--;
657 position
= MODEL_MAP (i
->data
)->offset
;
659 for (i
= i
->next
; i
; i
= i
->next
)
660 MODEL_MAP (i
->data
)->offset
--;
662 position
+= gtk_tree_path_get_indices (c_path
)[0];
666 egg_tree_model_union_update_stamp (umodel
);
667 egg_tree_model_union_emit_deleted (umodel
, position
, 1);
671 egg_tree_model_union_row_has_child_toggled (GtkTreeModel
*c_model
,
678 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (data
);
680 g_return_if_fail (GTK_IS_TREE_MODEL (c_model
));
681 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (data
));
683 /* translate the iter to a union iter and pass the event on */
684 egg_tree_model_union_convert_iter_to_union_iter (umodel
, c_model
,
687 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (data
), &uiter
);
688 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (data
), path
, &uiter
);
689 gtk_tree_path_free (path
);
700 reorder_func (GtkTreePath
*path
,
703 gtk_tree_path_get_indices (path
)[0] = gtk_tree_path_get_indices (ri
->root
)[0];
705 if (!gtk_tree_path_is_descendant (path
, ri
->root
))
708 gtk_tree_path_get_indices (path
)[ri
->level
] = ri
->order
[gtk_tree_path_get_indices (path
)[ri
->level
]];
712 egg_tree_model_union_rows_reordered (GtkTreeModel
*c_model
,
721 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (data
);
723 g_return_if_fail (GTK_IS_TREE_MODEL (c_model
));
724 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (data
));
726 map
= egg_tree_model_union_get_map_from_model (umodel
, c_model
);
730 if (gtk_tree_path_get_depth (c_path
) > 0)
737 ri
.level
= gtk_tree_path_get_depth (c_path
);
738 ri
.order
= new_order
;
740 g_hash_table_foreach (umodel
->child_paths
, (GHFunc
)reorder_func
, &ri
);
742 /* convert the iter and emit the signal */
743 egg_tree_model_union_convert_iter_to_union_iter (umodel
, c_model
,
746 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (data
), &uiter
);
747 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data
), path
,
749 gtk_tree_path_free (path
);
754 order
= g_new (gint
, umodel
->length
);
755 for (i
= 0; i
< umodel
->length
; i
++)
756 if (i
< map
->offset
|| i
>= map
->offset
+ map
->nodes
)
759 order
[i
] = new_order
[i
] + map
->offset
;
761 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data
), NULL
, NULL
, order
);
765 /* TreeModelIface implementation */
767 egg_tree_model_union_get_flags (GtkTreeModel
*model
)
769 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), 0);
775 egg_tree_model_union_get_n_columns (GtkTreeModel
*model
)
777 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
779 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), 0);
781 return umodel
->n_columns
;
785 egg_tree_model_union_get_column_type (GtkTreeModel
*model
,
788 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
790 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), G_TYPE_INVALID
);
791 g_return_val_if_fail (index
>= 0 && index
< umodel
->n_columns
, G_TYPE_INVALID
);
793 return umodel
->column_headers
[index
];
797 egg_tree_model_union_get_iter (GtkTreeModel
*model
,
804 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
806 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), FALSE
);
807 g_return_val_if_fail (iter
, FALSE
);
809 /* we don't want a warning on the screen if this fails */
816 map
= egg_tree_model_union_get_map_from_offset (umodel
, gtk_tree_path_get_indices (path
)[0]);
824 /* check if the iter actually exists in the child model */
825 c_path
= gtk_tree_path_copy (path
);
826 gtk_tree_path_get_indices (c_path
)[0] -= map
->offset
;
828 if (!gtk_tree_model_get_iter (map
->model
, &c_iter
, c_path
))
830 gtk_tree_path_free (c_path
);
834 gtk_tree_path_free (c_path
);
836 iter
->stamp
= umodel
->stamp
;
837 iter
->user_data
= map
;
838 iter
->user_data2
= GINT_TO_POINTER (gtk_tree_path_get_indices (path
)[0] - map
->offset
);
840 if (gtk_tree_path_get_depth (path
) > 1)
842 gchar
*str
= path_to_string_without_first (path
);
844 iter
->user_data3
= get_path_from_hash (umodel
, str
);
848 iter
->user_data3
= NULL
;
854 egg_tree_model_union_get_path (GtkTreeModel
*model
,
857 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
861 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), NULL
);
862 g_return_val_if_fail (umodel
->stamp
== iter
->stamp
, NULL
);
863 g_return_val_if_fail (umodel
->root
, NULL
);
865 map
= egg_tree_model_union_get_map_from_iter (iter
);
867 if (iter
->user_data3
)
869 path
= gtk_tree_path_copy (iter
->user_data3
);
872 path
= gtk_tree_path_new ();
874 gtk_tree_path_prepend_index (path
, map
->offset
+ GPOINTER_TO_INT (iter
->user_data2
));
880 egg_tree_model_union_get_value (GtkTreeModel
*model
,
885 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
886 GtkTreeIter child_iter
;
889 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (model
));
890 g_return_if_fail (umodel
->stamp
== iter
->stamp
);
891 g_return_if_fail (umodel
->root
);
893 egg_tree_model_union_convert_iter_to_child_iter (umodel
, &child_iter
, iter
);
894 col
= egg_tree_model_union_convert_to_child_column (umodel
, iter
, column
);
895 gtk_tree_model_get_value (MODEL_MAP (iter
->user_data
)->model
,
896 &child_iter
, col
, value
);
900 egg_tree_model_union_iter_next (GtkTreeModel
*model
,
903 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
907 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), FALSE
);
908 g_return_val_if_fail (umodel
->stamp
== iter
->stamp
, FALSE
);
909 g_return_val_if_fail (umodel
->root
, FALSE
);
911 /* let's do it the lazy and easy way */
912 path
= egg_tree_model_union_get_path (model
, iter
);
913 gtk_tree_path_next (path
);
915 ret
= egg_tree_model_union_get_iter (model
, iter
, path
);
916 gtk_tree_path_free (path
);
922 egg_tree_model_union_iter_children (GtkTreeModel
*model
,
927 GtkTreeIter child_iter
;
928 GtkTreeIter child_iter2
;
929 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (model
);
931 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), FALSE
);
935 gtk_tree_model_get_iter_first (model
, iter
);
939 g_return_val_if_fail (umodel
->stamp
== parent
->stamp
, FALSE
);
941 map
= egg_tree_model_union_get_map_from_iter (parent
);
943 egg_tree_model_union_convert_iter_to_child_iter (umodel
, &child_iter
,
946 if (!gtk_tree_model_iter_children (map
->model
, &child_iter2
, &child_iter
))
952 egg_tree_model_union_convert_iter_to_union_iter (umodel
, map
->model
,
959 egg_tree_model_union_iter_has_child (GtkTreeModel
*model
,
963 GtkTreeIter child_iter
;
964 EggTreeModelUnion
*umodel
= EGG_TREE_MODEL_UNION (model
);
966 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), FALSE
);
971 g_return_val_if_fail (umodel
->stamp
== iter
->stamp
, FALSE
);
973 map
= egg_tree_model_union_get_map_from_iter (iter
);
975 egg_tree_model_union_convert_iter_to_child_iter (umodel
, &child_iter
,
978 return gtk_tree_model_iter_has_child (map
->model
, &child_iter
);
982 egg_tree_model_union_iter_n_children (GtkTreeModel
*model
,
986 GtkTreeIter child_iter
;
987 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
989 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), 0);
992 return umodel
->length
;
994 g_return_val_if_fail (umodel
->stamp
== iter
->stamp
, FALSE
);
996 map
= egg_tree_model_union_get_map_from_iter (iter
);
998 egg_tree_model_union_convert_iter_to_child_iter (umodel
, &child_iter
,
1001 return gtk_tree_model_iter_n_children (map
->model
, &child_iter
);
1005 egg_tree_model_union_iter_nth_child (GtkTreeModel
*model
,
1007 GtkTreeIter
*parent
,
1010 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
1014 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), FALSE
);
1018 path
= gtk_tree_path_new_from_indices (n
, -1);
1019 ret
= egg_tree_model_union_get_iter (model
, iter
, path
);
1020 gtk_tree_path_free (path
);
1025 g_return_val_if_fail (umodel
->stamp
== parent
->stamp
, FALSE
);
1027 path
= gtk_tree_model_get_path (model
, parent
);
1028 gtk_tree_path_append_index (path
, n
);
1030 ret
= gtk_tree_model_get_iter (model
, iter
, path
);
1032 gtk_tree_path_free (path
);
1038 egg_tree_model_union_iter_parent (GtkTreeModel
*model
,
1042 EggTreeModelUnion
*umodel
= (EggTreeModelUnion
*)model
;
1046 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model
), FALSE
);
1054 g_return_val_if_fail (umodel
->stamp
== child
->stamp
, FALSE
);
1056 path
= gtk_tree_model_get_path (model
, child
);
1058 if (gtk_tree_path_get_depth (path
) <= 1)
1060 gtk_tree_path_free (path
);
1066 gtk_tree_path_up (path
);
1068 ret
= gtk_tree_model_get_iter (model
, iter
, path
);
1069 gtk_tree_path_free (path
);
1075 egg_tree_model_union_ref_node (GtkTreeModel
*model
,
1081 egg_tree_model_union_unref_node (GtkTreeModel
*model
,
1088 egg_tree_model_union_new (gint n_columns
,
1091 EggTreeModelUnion
*retval
;
1095 g_return_val_if_fail (n_columns
> 0, NULL
);
1097 retval
= g_object_new (EGG_TYPE_TREE_MODEL_UNION
, NULL
);
1098 egg_tree_model_union_set_n_columns (retval
, n_columns
);
1100 va_start (args
, n_columns
);
1102 for (i
= 0; i
< n_columns
; i
++)
1104 GType type
= va_arg (args
, GType
);
1105 egg_tree_model_union_set_column_type (retval
, i
, type
);
1110 return GTK_TREE_MODEL (retval
);
1114 egg_tree_model_union_newv (gint n_columns
,
1117 EggTreeModelUnion
*retval
;
1120 g_return_val_if_fail (n_columns
> 0, NULL
);
1122 retval
= g_object_new (EGG_TYPE_TREE_MODEL_UNION
, NULL
);
1123 egg_tree_model_union_set_n_columns (retval
, n_columns
);
1125 for (i
= 0; i
< n_columns
; i
++)
1126 egg_tree_model_union_set_column_type (retval
, i
, types
[i
]);
1128 return GTK_TREE_MODEL (retval
);
1132 egg_tree_model_union_set_column_types (EggTreeModelUnion
*umodel
,
1141 egg_tree_model_union_append (EggTreeModelUnion
*umodel
,
1142 GtkTreeModel
*model
)
1144 egg_tree_model_union_insert (umodel
, model
, -1);
1148 egg_tree_model_union_prepend (EggTreeModelUnion
*umodel
,
1149 GtkTreeModel
*model
)
1151 egg_tree_model_union_insert (umodel
, model
, 0);
1155 egg_tree_model_union_insert (EggTreeModelUnion
*umodel
,
1156 GtkTreeModel
*model
,
1159 egg_tree_model_union_insert_with_mappingv (umodel
, model
, position
, NULL
);
1163 egg_tree_model_union_append_with_mapping (EggTreeModelUnion
*umodel
,
1164 GtkTreeModel
*model
,
1167 gint
*column_mapping
;
1171 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
1173 column_mapping
= g_new0 (gint
, umodel
->n_columns
);
1175 va_start (args
, model
);
1176 for (i
= 0; i
< umodel
->n_columns
; i
++)
1177 column_mapping
[i
] = va_arg (args
, gint
);
1180 egg_tree_model_union_insert_with_mappingv (umodel
, model
, -1, column_mapping
);
1182 g_free (column_mapping
);
1187 egg_tree_model_union_prepend_with_mapping (EggTreeModelUnion
*umodel
,
1188 GtkTreeModel
*model
,
1191 gint
*column_mapping
;
1195 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
1197 column_mapping
= g_new0 (gint
, umodel
->n_columns
);
1199 va_start (args
, model
);
1200 for (i
= 0; i
< umodel
->n_columns
; i
++)
1201 column_mapping
[i
] = va_arg (args
, gint
);
1204 egg_tree_model_union_insert_with_mappingv (umodel
, model
, 0, column_mapping
);
1206 g_free (column_mapping
);
1210 egg_tree_model_union_insert_with_mapping (EggTreeModelUnion
*umodel
,
1211 GtkTreeModel
*model
,
1215 gint
*column_mapping
;
1219 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
1221 column_mapping
= g_new0 (gint
, umodel
->n_columns
);
1223 va_start (args
, position
);
1224 for (i
= 0; i
< umodel
->n_columns
; i
++)
1225 column_mapping
[i
] = va_arg (args
, gint
);
1228 egg_tree_model_union_insert_with_mappingv (umodel
, model
, position
, column_mapping
);
1230 g_free (column_mapping
);
1234 egg_tree_model_union_insert_with_mappingv (EggTreeModelUnion
*umodel
,
1235 GtkTreeModel
*model
,
1237 gint
*column_mapping
)
1241 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
1242 g_return_if_fail (GTK_IS_TREE_MODEL (model
));
1246 g_return_if_fail (egg_tree_model_union_column_check (umodel
, model
, column_mapping
));
1248 g_return_if_fail (egg_tree_model_union_column_check (umodel
, model
, NULL
));
1250 g_object_ref (G_OBJECT (model
));
1252 map
= g_new0 (ModelMap
, 1);
1254 map
->nodes
= gtk_tree_model_iter_n_children (model
, NULL
);
1257 map
->column_mapping
= g_new0 (gint
, umodel
->n_columns
);
1258 memcpy (map
->column_mapping
, column_mapping
, sizeof (gint
) * umodel
->n_columns
);
1261 umodel
->length
+= map
->nodes
;
1263 g_signal_connect (model
, "row_inserted",
1264 G_CALLBACK (egg_tree_model_union_row_inserted
), umodel
);
1265 g_signal_connect (model
, "row_changed",
1266 G_CALLBACK (egg_tree_model_union_row_changed
), umodel
);
1267 g_signal_connect (model
, "row_deleted",
1268 G_CALLBACK (egg_tree_model_union_row_deleted
), umodel
);
1269 g_signal_connect (model
, "row_has_child_toggled",
1270 G_CALLBACK (egg_tree_model_union_row_has_child_toggled
),
1272 g_signal_connect (model
, "rows_reordered",
1273 G_CALLBACK (egg_tree_model_union_rows_reordered
), umodel
);
1279 umodel
->root
= g_list_prepend (umodel
->root
, map
);
1282 /* fix up offsets */
1283 for (j
= umodel
->root
->next
; j
; j
= j
->next
)
1284 MODEL_MAP (j
->data
)->offset
+= map
->nodes
;
1287 egg_tree_model_union_update_stamp (umodel
);
1290 egg_tree_model_union_emit_inserted (umodel
, 0, map
->nodes
);
1292 else if (position
== -1)
1298 for (j
= umodel
->root
; j
; j
= j
->next
)
1299 map
->offset
+= MODEL_MAP (j
->data
)->nodes
;
1301 umodel
->root
= g_list_append (umodel
->root
, map
);
1304 egg_tree_model_union_update_stamp (umodel
);
1307 egg_tree_model_union_emit_inserted (umodel
, map
->offset
, map
->nodes
);
1313 umodel
->root
= g_list_insert (umodel
->root
, map
, position
);
1317 for (j
= umodel
->root
; j
->data
!= map
; j
= j
->next
)
1318 map
->offset
+= MODEL_MAP (j
->data
)->nodes
;
1320 for (j
= j
->next
; j
; j
= j
->next
)
1321 MODEL_MAP (j
->data
)->offset
+= map
->nodes
;
1324 egg_tree_model_union_update_stamp (umodel
);
1327 egg_tree_model_union_emit_inserted (umodel
, map
->offset
, map
->nodes
);
1332 egg_tree_model_union_clear (EggTreeModelUnion
*umodel
)
1336 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
1338 g_list_foreach (umodel
->root
, (GFunc
)model_map_free
, NULL
);
1339 g_list_free (umodel
->root
);
1340 umodel
->root
= NULL
;
1342 length
= umodel
->length
;
1345 egg_tree_model_union_update_stamp (umodel
);
1347 egg_tree_model_union_emit_deleted (umodel
, 0, length
);
1351 egg_tree_model_union_remove (EggTreeModelUnion
*umodel
,
1352 GtkTreeModel
*model
)
1358 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel
));
1359 g_return_if_fail (GTK_IS_TREE_MODEL (model
));
1360 g_return_if_fail (umodel
->root
);
1362 for (i
= umodel
->root
; i
; i
= i
->next
)
1363 if (MODEL_MAP (i
->data
)->model
== model
)
1366 g_return_if_fail (i
);
1370 map
= MODEL_MAP (i
->data
);
1372 umodel
->root
= g_list_remove_link (umodel
->root
, i
);
1373 umodel
->length
-= map
->nodes
;
1375 for (i
= next
; i
; i
= i
->next
)
1376 MODEL_MAP (i
->data
)->offset
-= map
->nodes
;
1378 g_signal_handlers_disconnect_by_func (map
->model
,
1379 egg_tree_model_union_row_inserted
,
1381 g_signal_handlers_disconnect_by_func (map
->model
,
1382 egg_tree_model_union_row_deleted
,
1384 g_signal_handlers_disconnect_by_func (map
->model
,
1385 egg_tree_model_union_row_changed
,
1387 g_signal_handlers_disconnect_by_func (map
->model
,
1388 egg_tree_model_union_row_has_child_toggled
,
1390 g_signal_handlers_disconnect_by_func (map
->model
,
1391 egg_tree_model_union_rows_reordered
,
1394 g_object_unref (G_OBJECT (map
->model
));
1396 egg_tree_model_union_update_stamp (umodel
);
1398 egg_tree_model_union_emit_deleted (umodel
, map
->offset
, map
->nodes
);
1400 model_map_free (map
);