Updated Spanish translation
[anjuta-git-plugin.git] / libegg / eggtreemodelunion.c
blob15efc68aba94a284d397d634e6051163c077028d
1 /**
2 * eggtreemodelunion.c: Union treemodel implementation
4 * Copyright (C) 2003, Kristian Rietveld
5 */
8 /* Notes/ToDo:
9 * - there is a nasty bug in here which I can't easily repro. Need to
10 * investigate
11 * - need to implement_set_child
12 * - fix bugs
15 #include "eggtreemodelunion.h"
17 #include <glib/gprintf.h>
18 #include <string.h> /* for memcpy */
21 typedef struct _ModelMap ModelMap;
23 struct _ModelMap
25 GtkTreeModel *model;
26 gint nodes;
27 gint offset;
29 gint *column_mapping;
32 #define MODEL_MAP(map) ((ModelMap *)map)
34 /* iter format:
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);
51 /* helpers */
52 static void egg_tree_model_union_set_n_columns (EggTreeModelUnion *umodel,
53 gint n_columns);
54 static void egg_tree_model_union_set_column_type (EggTreeModelUnion *umodel,
55 gint column,
56 GType type);
57 static void model_map_free (ModelMap *map);
58 static GtkTreePath *get_path_from_hash (EggTreeModelUnion *umodel,
59 gchar *str);
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,
63 gint offset);
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,
69 GtkTreeIter *iter,
70 gint column);
71 static gboolean egg_tree_model_union_column_check (EggTreeModelUnion *umodel,
72 GtkTreeModel *model,
73 gint *column_mapping);
74 static void egg_tree_model_union_emit_inserted (EggTreeModelUnion *umodel,
75 gint start,
76 gint length);
77 static void egg_tree_model_union_emit_deleted (EggTreeModelUnion *umodel,
78 gint start,
79 gint length);
81 /* TreeModel signals */
82 static void egg_tree_model_union_row_changed (GtkTreeModel *c_model,
83 GtkTreePath *c_path,
84 GtkTreeIter *c_iter,
85 gpointer data);
86 static void egg_tree_model_union_row_inserted (GtkTreeModel *c_model,
87 GtkTreePath *c_path,
88 GtkTreeIter *c_iter,
89 gpointer data);
90 static void egg_tree_model_union_row_deleted (GtkTreeModel *c_model,
91 GtkTreePath *c_path,
92 gpointer data);
93 static void egg_tree_model_union_row_has_child_toggled (GtkTreeModel *c_model,
94 GtkTreePath *c_path,
95 GtkTreeIter *c_iter,
96 gpointer data);
97 static void egg_tree_model_union_rows_reordered (GtkTreeModel *c_model,
98 GtkTreePath *c_path,
99 GtkTreeIter *c_iter,
100 gint *new_order,
101 gpointer data);
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,
106 gint index);
107 static gboolean egg_tree_model_union_get_iter (GtkTreeModel *model,
108 GtkTreeIter *iter,
109 GtkTreePath *path);
110 static GtkTreePath *egg_tree_model_union_get_path (GtkTreeModel *model,
111 GtkTreeIter *iter);
112 static void egg_tree_model_union_get_value (GtkTreeModel *model,
113 GtkTreeIter *iter,
114 gint column,
115 GValue *value);
116 static gboolean egg_tree_model_union_iter_next (GtkTreeModel *model,
117 GtkTreeIter *iter);
118 static gboolean egg_tree_model_union_iter_children (GtkTreeModel *model,
119 GtkTreeIter *iter,
120 GtkTreeIter *parent);
121 static gboolean egg_tree_model_union_iter_has_child (GtkTreeModel *model,
122 GtkTreeIter *iter);
123 static gint egg_tree_model_union_iter_n_children (GtkTreeModel *model,
124 GtkTreeIter *iter);
125 static gboolean egg_tree_model_union_iter_nth_child (GtkTreeModel *model,
126 GtkTreeIter *iter,
127 GtkTreeIter *parent,
128 gint n);
129 static gboolean egg_tree_model_union_iter_parent (GtkTreeModel *model,
130 GtkTreeIter *iter,
131 GtkTreeIter *child);
132 static void egg_tree_model_union_ref_node (GtkTreeModel *model,
133 GtkTreeIter *iter);
134 static void egg_tree_model_union_unref_node (GtkTreeModel *model,
135 GtkTreeIter *iter);
138 static GObjectClass *parent_class = NULL;
140 GType
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),
150 NULL,
151 NULL,
152 (GClassInitFunc) egg_tree_model_union_class_init,
153 NULL,
154 NULL,
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,
163 NULL,
164 NULL
167 tree_model_union_type = g_type_register_static (G_TYPE_OBJECT,
168 "EggTreeModelUnion",
169 &tree_model_union_info, 0);
171 g_type_add_interface_static (tree_model_union_type,
172 GTK_TYPE_TREE_MODEL,
173 &tree_model_info);
176 return tree_model_union_type;
179 static void
180 egg_tree_model_union_init (EggTreeModelUnion *umodel)
182 umodel->root = NULL;
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 ();
194 static void
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;
205 static void
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;
225 static void
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);
238 /* chain */
239 parent_class->finalize (object);
242 /* Helpers */
243 static void
244 egg_tree_model_union_set_n_columns (EggTreeModelUnion *umodel,
245 gint n_columns)
247 GType *new_columns;
249 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel));
251 if (umodel->n_columns == n_columns)
252 return;
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 *));
260 else
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;
270 static void
271 egg_tree_model_union_set_column_type (EggTreeModelUnion *umodel,
272 gint column,
273 GType type)
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;
281 static void
282 model_map_free (ModelMap *map)
284 if (map->column_mapping)
285 g_free (map->column_mapping);
287 g_free (map);
290 static GtkTreePath *
291 get_path_from_hash (EggTreeModelUnion *umodel,
292 gchar *str)
294 gpointer ret;
296 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel), NULL);
298 ret = g_hash_table_lookup (umodel->child_paths, str);
300 if (ret)
301 return ret;
303 ret = gtk_tree_path_new_from_string (str);
304 g_hash_table_insert (umodel->child_paths, g_strdup (str), ret);
306 return ret;
309 static gchar *
310 path_to_string_without_first (GtkTreePath *path)
312 gint i;
313 gchar *str, *ptr;
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]);
321 while (*ptr != '\0')
322 ptr++;
324 for (i = 2; i < depth; i++)
326 g_sprintf (ptr, ":%d", indices[i]);
327 while (*ptr != '\0')
328 ptr++;
331 return str;
334 static void
335 egg_tree_model_union_update_stamp (EggTreeModelUnion *umodel)
339 umodel->stamp++;
341 while (!umodel->stamp);
344 static ModelMap *
345 egg_tree_model_union_get_map_from_offset (EggTreeModelUnion *umodel,
346 gint offset)
348 GList *i;
350 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (umodel), NULL);
352 if (offset < 0 || offset >= umodel->length)
353 return NULL;
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)
361 return map;
364 return NULL;
367 static ModelMap *
368 egg_tree_model_union_get_map_from_iter (GtkTreeIter *iter)
370 return MODEL_MAP (iter->user_data);
373 static ModelMap *
374 egg_tree_model_union_get_map_from_model (EggTreeModelUnion *umodel,
375 GtkTreeModel *model)
377 GList *i;
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);
385 return NULL;
388 static void
389 egg_tree_model_union_convert_iter_to_union_iter (EggTreeModelUnion *umodel,
390 GtkTreeModel *model,
391 GtkTreeIter *child_iter,
392 GtkTreeIter *union_iter)
394 ModelMap *map;
395 GtkTreePath *path;
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);
402 if (!map)
404 union_iter->stamp = 0;
405 return;
408 path = gtk_tree_model_get_path (model, child_iter);
409 if (!path)
411 union_iter->stamp = 0;
412 return;
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);
424 g_free (str);
426 else
427 union_iter->user_data3 = NULL;
429 gtk_tree_path_free (path);
432 static void
433 egg_tree_model_union_convert_iter_to_child_iter (EggTreeModelUnion *umodel,
434 GtkTreeIter *child_iter,
435 GtkTreeIter *union_iter)
437 ModelMap *map;
438 GtkTreePath *path;
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);
447 else
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);
456 static gint
457 egg_tree_model_union_convert_to_child_column (EggTreeModelUnion *umodel,
458 GtkTreeIter *iter,
459 gint column)
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)
466 return column;
468 return (MODEL_MAP (iter->user_data))->column_mapping[column];
471 static gboolean
472 egg_tree_model_union_column_check (EggTreeModelUnion *umodel,
473 GtkTreeModel *model,
474 gint *column_mapping)
476 gint i;
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++)
483 GType type;
485 if (column_mapping)
486 type = gtk_tree_model_get_column_type (model, column_mapping[i]);
487 else
488 type = gtk_tree_model_get_column_type (model, i);
490 if (type != umodel->column_headers[i])
491 return FALSE;
494 return TRUE;
497 static void
498 egg_tree_model_union_emit_inserted (EggTreeModelUnion *umodel,
499 gint start,
500 gint length)
502 gint i;
503 GtkTreeIter iter;
504 GtkTreePath *path;
506 if (!length)
507 return;
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);
526 static void
527 egg_tree_model_union_emit_deleted (EggTreeModelUnion *umodel,
528 gint start,
529 gint length)
531 gint i;
532 GtkTreePath *path;
534 if (!length)
535 return;
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 */
553 static void
554 egg_tree_model_union_row_changed (GtkTreeModel *c_model,
555 GtkTreePath *c_path,
556 GtkTreeIter *c_iter,
557 gpointer data)
559 EggTreeModelUnion *umodel = EGG_TREE_MODEL_UNION (data);
560 GtkTreeIter uiter;
561 GtkTreePath *path;
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,
568 c_iter, &uiter);
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);
575 static void
576 egg_tree_model_union_row_inserted (GtkTreeModel *c_model,
577 GtkTreePath *c_path,
578 GtkTreeIter *c_iter,
579 gpointer data)
581 gint position;
582 GList *i;
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)
590 GtkTreeIter uiter;
591 GtkTreePath *path;
593 /* translate and propagate */
594 egg_tree_model_union_convert_iter_to_union_iter (umodel,
595 c_model,
596 c_iter,
597 &uiter);
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);
602 return;
605 for (i = umodel->root; i; i = i->next)
606 if (MODEL_MAP (i->data)->model == c_model)
607 break;
609 if (!i)
610 return;
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];
620 umodel->length++;
622 egg_tree_model_union_update_stamp (umodel);
623 egg_tree_model_union_emit_inserted (umodel, position, 1);
626 static void
627 egg_tree_model_union_row_deleted (GtkTreeModel *c_model,
628 GtkTreePath *c_path,
629 gpointer data)
631 GList *i;
632 gint position;
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)
640 break;
642 if (!i)
643 return;
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);
653 return;
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];
664 umodel->length--;
666 egg_tree_model_union_update_stamp (umodel);
667 egg_tree_model_union_emit_deleted (umodel, position, 1);
670 static void
671 egg_tree_model_union_row_has_child_toggled (GtkTreeModel *c_model,
672 GtkTreePath *c_path,
673 GtkTreeIter *c_iter,
674 gpointer data)
676 GtkTreeIter uiter;
677 GtkTreePath *path;
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,
685 c_iter, &uiter);
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);
692 typedef struct
694 GtkTreePath *root;
695 gint level;
696 gint *order;
697 } ReorderInfo;
699 static void
700 reorder_func (GtkTreePath *path,
701 ReorderInfo *ri)
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))
706 return;
708 gtk_tree_path_get_indices (path)[ri->level] = ri->order[gtk_tree_path_get_indices (path)[ri->level]];
711 static void
712 egg_tree_model_union_rows_reordered (GtkTreeModel *c_model,
713 GtkTreePath *c_path,
714 GtkTreeIter *c_iter,
715 gint *new_order,
716 gpointer data)
718 gint i;
719 gint *order;
720 ModelMap *map;
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);
727 if (!map)
728 return;
730 if (gtk_tree_path_get_depth (c_path) > 0)
732 GtkTreePath *path;
733 GtkTreeIter uiter;
734 ReorderInfo ri;
736 ri.root = c_path;
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,
744 c_iter, &uiter);
746 path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &uiter);
747 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), path,
748 &uiter, new_order);
749 gtk_tree_path_free (path);
751 return;
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)
757 order[i] = i;
758 else
759 order[i] = new_order[i] + map->offset;
761 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (data), NULL, NULL, order);
762 g_free (order);
765 /* TreeModelIface implementation */
766 static guint
767 egg_tree_model_union_get_flags (GtkTreeModel *model)
769 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model), 0);
771 return 0;
774 static gint
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;
784 static GType
785 egg_tree_model_union_get_column_type (GtkTreeModel *model,
786 gint index)
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];
796 static gboolean
797 egg_tree_model_union_get_iter (GtkTreeModel *model,
798 GtkTreeIter *iter,
799 GtkTreePath *path)
801 ModelMap *map;
802 GtkTreeIter c_iter;
803 GtkTreePath *c_path;
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 */
810 if (!umodel->root)
812 iter->stamp = 0;
813 return FALSE;
816 map = egg_tree_model_union_get_map_from_offset (umodel, gtk_tree_path_get_indices (path)[0]);
818 if (!map)
820 iter->stamp = 0;
821 return FALSE;
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);
831 return FALSE;
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);
845 g_free (str);
847 else
848 iter->user_data3 = NULL;
850 return TRUE;
853 static GtkTreePath *
854 egg_tree_model_union_get_path (GtkTreeModel *model,
855 GtkTreeIter *iter)
857 EggTreeModelUnion *umodel = (EggTreeModelUnion *)model;
858 GtkTreePath *path;
859 ModelMap *map;
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);
871 else
872 path = gtk_tree_path_new ();
874 gtk_tree_path_prepend_index (path, map->offset + GPOINTER_TO_INT (iter->user_data2));
876 return path;
879 static void
880 egg_tree_model_union_get_value (GtkTreeModel *model,
881 GtkTreeIter *iter,
882 gint column,
883 GValue *value)
885 EggTreeModelUnion *umodel = (EggTreeModelUnion *)model;
886 GtkTreeIter child_iter;
887 gint col;
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);
899 static gboolean
900 egg_tree_model_union_iter_next (GtkTreeModel *model,
901 GtkTreeIter *iter)
903 EggTreeModelUnion *umodel = (EggTreeModelUnion *)model;
904 GtkTreePath *path;
905 gboolean ret;
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);
918 return ret;
921 static gboolean
922 egg_tree_model_union_iter_children (GtkTreeModel *model,
923 GtkTreeIter *iter,
924 GtkTreeIter *parent)
926 ModelMap *map;
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);
933 if (!parent)
935 gtk_tree_model_get_iter_first (model, iter);
936 return TRUE;
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,
944 parent);
946 if (!gtk_tree_model_iter_children (map->model, &child_iter2, &child_iter))
948 iter->stamp = 0;
949 return FALSE;
952 egg_tree_model_union_convert_iter_to_union_iter (umodel, map->model,
953 &child_iter2, iter);
955 return TRUE;
958 static gboolean
959 egg_tree_model_union_iter_has_child (GtkTreeModel *model,
960 GtkTreeIter *iter)
962 ModelMap *map;
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);
968 if (!iter)
969 return TRUE;
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,
976 iter);
978 return gtk_tree_model_iter_has_child (map->model, &child_iter);
981 static gint
982 egg_tree_model_union_iter_n_children (GtkTreeModel *model,
983 GtkTreeIter *iter)
985 ModelMap *map;
986 GtkTreeIter child_iter;
987 EggTreeModelUnion *umodel = (EggTreeModelUnion *)model;
989 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model), 0);
991 if (!iter)
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,
999 iter);
1001 return gtk_tree_model_iter_n_children (map->model, &child_iter);
1004 static gboolean
1005 egg_tree_model_union_iter_nth_child (GtkTreeModel *model,
1006 GtkTreeIter *iter,
1007 GtkTreeIter *parent,
1008 gint n)
1010 EggTreeModelUnion *umodel = (EggTreeModelUnion *)model;
1011 GtkTreePath *path;
1012 gboolean ret;
1014 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model), FALSE);
1016 if (!parent)
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);
1022 return TRUE;
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);
1034 return ret;
1037 static gboolean
1038 egg_tree_model_union_iter_parent (GtkTreeModel *model,
1039 GtkTreeIter *iter,
1040 GtkTreeIter *child)
1042 EggTreeModelUnion *umodel = (EggTreeModelUnion *)model;
1043 GtkTreePath *path;
1044 gboolean ret;
1046 g_return_val_if_fail (EGG_IS_TREE_MODEL_UNION (model), FALSE);
1048 if (!child)
1050 iter->stamp = 0;
1051 return 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);
1062 iter->stamp = 0;
1063 return FALSE;
1066 gtk_tree_path_up (path);
1068 ret = gtk_tree_model_get_iter (model, iter, path);
1069 gtk_tree_path_free (path);
1071 return ret;
1074 static void
1075 egg_tree_model_union_ref_node (GtkTreeModel *model,
1076 GtkTreeIter *iter)
1080 static void
1081 egg_tree_model_union_unref_node (GtkTreeModel *model,
1082 GtkTreeIter *iter)
1086 /* public API */
1087 GtkTreeModel *
1088 egg_tree_model_union_new (gint n_columns,
1089 ...)
1091 EggTreeModelUnion *retval;
1092 va_list args;
1093 gint i;
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);
1108 va_end (args);
1110 return GTK_TREE_MODEL (retval);
1113 GtkTreeModel *
1114 egg_tree_model_union_newv (gint n_columns,
1115 GType *types)
1117 EggTreeModelUnion *retval;
1118 gint i;
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);
1131 void
1132 egg_tree_model_union_set_column_types (EggTreeModelUnion *umodel,
1133 gint n_types,
1134 GType *types)
1136 /* FIXME */
1140 void
1141 egg_tree_model_union_append (EggTreeModelUnion *umodel,
1142 GtkTreeModel *model)
1144 egg_tree_model_union_insert (umodel, model, -1);
1147 void
1148 egg_tree_model_union_prepend (EggTreeModelUnion *umodel,
1149 GtkTreeModel *model)
1151 egg_tree_model_union_insert (umodel, model, 0);
1154 void
1155 egg_tree_model_union_insert (EggTreeModelUnion *umodel,
1156 GtkTreeModel *model,
1157 gint position)
1159 egg_tree_model_union_insert_with_mappingv (umodel, model, position, NULL);
1162 void
1163 egg_tree_model_union_append_with_mapping (EggTreeModelUnion *umodel,
1164 GtkTreeModel *model,
1165 ...)
1167 gint *column_mapping;
1168 va_list args;
1169 gint i;
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);
1178 va_end (args);
1180 egg_tree_model_union_insert_with_mappingv (umodel, model, -1, column_mapping);
1182 g_free (column_mapping);
1186 void
1187 egg_tree_model_union_prepend_with_mapping (EggTreeModelUnion *umodel,
1188 GtkTreeModel *model,
1189 ...)
1191 gint *column_mapping;
1192 va_list args;
1193 gint i;
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);
1202 va_end (args);
1204 egg_tree_model_union_insert_with_mappingv (umodel, model, 0, column_mapping);
1206 g_free (column_mapping);
1209 void
1210 egg_tree_model_union_insert_with_mapping (EggTreeModelUnion *umodel,
1211 GtkTreeModel *model,
1212 gint position,
1213 ...)
1215 gint *column_mapping;
1216 va_list args;
1217 gint i;
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);
1226 va_end (args);
1228 egg_tree_model_union_insert_with_mappingv (umodel, model, position, column_mapping);
1230 g_free (column_mapping);
1233 void
1234 egg_tree_model_union_insert_with_mappingv (EggTreeModelUnion *umodel,
1235 GtkTreeModel *model,
1236 gint position,
1237 gint *column_mapping)
1239 ModelMap *map;
1241 g_return_if_fail (EGG_IS_TREE_MODEL_UNION (umodel));
1242 g_return_if_fail (GTK_IS_TREE_MODEL (model));
1244 /* leaks ... */
1245 if (column_mapping)
1246 g_return_if_fail (egg_tree_model_union_column_check (umodel, model, column_mapping));
1247 else
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);
1253 map->model = model;
1254 map->nodes = gtk_tree_model_iter_n_children (model, NULL);
1255 if (column_mapping)
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),
1271 umodel);
1272 g_signal_connect (model, "rows_reordered",
1273 G_CALLBACK (egg_tree_model_union_rows_reordered), umodel);
1275 if (position == 0)
1277 GList *j;
1279 umodel->root = g_list_prepend (umodel->root, map);
1280 map->offset = 0;
1282 /* fix up offsets */
1283 for (j = umodel->root->next; j; j = j->next)
1284 MODEL_MAP (j->data)->offset += map->nodes;
1286 /* update stamp */
1287 egg_tree_model_union_update_stamp (umodel);
1289 /* emit signals */
1290 egg_tree_model_union_emit_inserted (umodel, 0, map->nodes);
1292 else if (position == -1)
1294 GList *j;
1296 map->offset = 0;
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);
1303 /* update stamp */
1304 egg_tree_model_union_update_stamp (umodel);
1306 /* emit signals */
1307 egg_tree_model_union_emit_inserted (umodel, map->offset, map->nodes);
1309 else
1311 GList *j;
1313 umodel->root = g_list_insert (umodel->root, map, position);
1315 map->offset = 0;
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;
1323 /* update stamp */
1324 egg_tree_model_union_update_stamp (umodel);
1326 /* emit signals */
1327 egg_tree_model_union_emit_inserted (umodel, map->offset, map->nodes);
1331 void
1332 egg_tree_model_union_clear (EggTreeModelUnion *umodel)
1334 gint length;
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;
1343 umodel->length = 0;
1345 egg_tree_model_union_update_stamp (umodel);
1347 egg_tree_model_union_emit_deleted (umodel, 0, length);
1350 void
1351 egg_tree_model_union_remove (EggTreeModelUnion *umodel,
1352 GtkTreeModel *model)
1354 GList *i;
1355 GList *next;
1356 ModelMap *map;
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)
1364 break;
1366 g_return_if_fail (i);
1368 next = i->next;
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,
1380 umodel);
1381 g_signal_handlers_disconnect_by_func (map->model,
1382 egg_tree_model_union_row_deleted,
1383 umodel);
1384 g_signal_handlers_disconnect_by_func (map->model,
1385 egg_tree_model_union_row_changed,
1386 umodel);
1387 g_signal_handlers_disconnect_by_func (map->model,
1388 egg_tree_model_union_row_has_child_toggled,
1389 umodel);
1390 g_signal_handlers_disconnect_by_func (map->model,
1391 egg_tree_model_union_rows_reordered,
1392 umodel);
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);