]> Pileus Git - ~andy/gtk/blob - tests/testtreeview.c
4dc4b586f34ddcc8ff662462c6fd8eb77e4c5b32
[~andy/gtk] / tests / testtreeview.c
1 #undef GTK_DISABLE_DEPRECATED
2 #include <string.h>
3 #include "prop-editor.h"
4 #include <gtk/gtk.h>
5
6
7 /* Don't copy this bad example; inline RGB data is always a better
8  * idea than inline XPMs.
9  */
10 static char  *book_closed_xpm[] = {
11 "16 16 6 1",
12 "       c None s None",
13 ".      c black",
14 "X      c red",
15 "o      c yellow",
16 "O      c #808080",
17 "#      c white",
18 "                ",
19 "       ..       ",
20 "     ..XX.      ",
21 "   ..XXXXX.     ",
22 " ..XXXXXXXX.    ",
23 ".ooXXXXXXXXX.   ",
24 "..ooXXXXXXXXX.  ",
25 ".X.ooXXXXXXXXX. ",
26 ".XX.ooXXXXXX..  ",
27 " .XX.ooXXX..#O  ",
28 "  .XX.oo..##OO. ",
29 "   .XX..##OO..  ",
30 "    .X.#OO..    ",
31 "     ..O..      ",
32 "      ..        ",
33 "                "
34 };
35
36 static void run_automated_tests (void);
37
38 /* This custom model is to test custom model use. */
39
40 #define GTK_TYPE_MODEL_TYPES                            (gtk_tree_model_types_get_type ())
41 #define GTK_TREE_MODEL_TYPES(obj)                       (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_MODEL_TYPES, GtkTreeModelTypes))
42 #define GTK_TREE_MODEL_TYPES_CLASS(klass)               (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_MODEL_TYPES, GtkTreeModelTypesClass))
43 #define GTK_IS_TREE_MODEL_TYPES(obj)                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_MODEL_TYPES))
44 #define GTK_IS_TREE_MODEL_TYPES_GET_CLASS(klass)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MODEL_TYPES))
45
46 typedef struct _GtkTreeModelTypes       GtkTreeModelTypes;
47 typedef struct _GtkTreeModelTypesClass  GtkTreeModelTypesClass;
48
49 struct _GtkTreeModelTypes
50 {
51   GObject parent;
52
53   gint stamp;
54 };
55
56 struct _GtkTreeModelTypesClass
57 {
58   GObjectClass parent_class;
59
60   guint        (* get_flags)       (GtkTreeModel *tree_model);   
61   gint         (* get_n_columns)   (GtkTreeModel *tree_model);
62   GType        (* get_column_type) (GtkTreeModel *tree_model,
63                                     gint          index);
64   gboolean     (* get_iter)        (GtkTreeModel *tree_model,
65                                     GtkTreeIter  *iter,
66                                     GtkTreePath  *path);
67   GtkTreePath *(* get_path)        (GtkTreeModel *tree_model,
68                                     GtkTreeIter  *iter);
69   void         (* get_value)       (GtkTreeModel *tree_model,
70                                     GtkTreeIter  *iter,
71                                     gint          column,
72                                     GValue       *value);
73   gboolean     (* iter_next)       (GtkTreeModel *tree_model,
74                                     GtkTreeIter  *iter);
75   gboolean     (* iter_children)   (GtkTreeModel *tree_model,
76                                     GtkTreeIter  *iter,
77                                     GtkTreeIter  *parent);
78   gboolean     (* iter_has_child)  (GtkTreeModel *tree_model,
79                                     GtkTreeIter  *iter);
80   gint         (* iter_n_children) (GtkTreeModel *tree_model,
81                                     GtkTreeIter  *iter);
82   gboolean     (* iter_nth_child)  (GtkTreeModel *tree_model,
83                                     GtkTreeIter  *iter,
84                                     GtkTreeIter  *parent,
85                                     gint          n);
86   gboolean     (* iter_parent)     (GtkTreeModel *tree_model,
87                                     GtkTreeIter  *iter,
88                                     GtkTreeIter  *child);
89   void         (* ref_iter)        (GtkTreeModel *tree_model,
90                                     GtkTreeIter  *iter);
91   void         (* unref_iter)      (GtkTreeModel *tree_model,
92                                     GtkTreeIter  *iter);
93
94   /* These will be moved into the GtkTreeModelIface eventually */
95   void         (* changed)         (GtkTreeModel *tree_model,
96                                     GtkTreePath  *path,
97                                     GtkTreeIter  *iter);
98   void         (* inserted)        (GtkTreeModel *tree_model,
99                                     GtkTreePath  *path,
100                                     GtkTreeIter  *iter);
101   void         (* child_toggled)   (GtkTreeModel *tree_model,
102                                     GtkTreePath  *path,
103                                     GtkTreeIter  *iter);
104   void         (* deleted)         (GtkTreeModel *tree_model,
105                                     GtkTreePath  *path);
106 };
107
108 GType              gtk_tree_model_types_get_type      (void) G_GNUC_CONST;
109 GtkTreeModelTypes *gtk_tree_model_types_new           (void);
110
111 typedef enum
112 {
113   COLUMNS_NONE,
114   COLUMNS_ONE,
115   COLUMNS_LOTS,
116   COLUMNS_LAST
117 } ColumnsType;
118
119 static gchar *column_type_names[] = {
120   "No columns",
121   "One column",
122   "Many columns"
123 };
124
125 #define N_COLUMNS 9
126
127 static GType*
128 get_model_types (void)
129 {
130   static GType column_types[N_COLUMNS] = { 0 };
131   
132   if (column_types[0] == 0)
133     {
134       column_types[0] = G_TYPE_STRING;
135       column_types[1] = G_TYPE_STRING;
136       column_types[2] = GDK_TYPE_PIXBUF;
137       column_types[3] = G_TYPE_FLOAT;
138       column_types[4] = G_TYPE_UINT;
139       column_types[5] = G_TYPE_UCHAR;
140       column_types[6] = G_TYPE_CHAR;
141 #define BOOL_COLUMN 7
142       column_types[BOOL_COLUMN] = G_TYPE_BOOLEAN;
143       column_types[8] = G_TYPE_INT;
144     }
145
146   return column_types;
147 }
148
149 static void
150 col_clicked_cb (GtkTreeViewColumn *col, gpointer data)
151 {
152   GtkWindow *win;
153
154   win = GTK_WINDOW (create_prop_editor (G_OBJECT (col), GTK_TYPE_TREE_VIEW_COLUMN));
155
156   gtk_window_set_title (win, gtk_tree_view_column_get_title (col));
157 }
158
159 static void
160 setup_column (GtkTreeViewColumn *col)
161 {
162   gtk_tree_view_column_set_clickable (col, TRUE);
163   g_signal_connect (col,
164                     "clicked",
165                     G_CALLBACK (col_clicked_cb),
166                     NULL);
167 }
168
169 static void
170 toggled_callback (GtkCellRendererToggle *celltoggle,
171                   gchar                 *path_string,
172                   GtkTreeView           *tree_view)
173 {
174   GtkTreeModel *model = NULL;
175   GtkTreeModelSort *sort_model = NULL;
176   GtkTreePath *path;
177   GtkTreeIter iter;
178   gboolean active = FALSE;
179   
180   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
181
182   model = gtk_tree_view_get_model (tree_view);
183   
184   if (GTK_IS_TREE_MODEL_SORT (model))
185     {
186       sort_model = GTK_TREE_MODEL_SORT (model);
187       model = gtk_tree_model_sort_get_model (sort_model);
188     }
189
190   if (model == NULL)
191     return;
192
193   if (sort_model)
194     {
195       g_warning ("FIXME implement conversion from TreeModelSort iter to child model iter");
196       return;
197     }
198       
199   path = gtk_tree_path_new_from_string (path_string);
200   if (!gtk_tree_model_get_iter (model,
201                                 &iter, path))
202     {
203       g_warning ("%s: bad path?", G_STRLOC);
204       return;
205     }
206   gtk_tree_path_free (path);
207   
208   if (GTK_IS_LIST_STORE (model))
209     {
210       gtk_tree_model_get (GTK_TREE_MODEL (model),
211                           &iter,
212                           BOOL_COLUMN,
213                           &active,
214                           -1);
215       
216       gtk_list_store_set (GTK_LIST_STORE (model),
217                           &iter,
218                           BOOL_COLUMN,
219                           !active,
220                           -1);
221     }
222   else if (GTK_IS_TREE_STORE (model))
223     {
224       gtk_tree_model_get (GTK_TREE_MODEL (model),
225                           &iter,
226                           BOOL_COLUMN,
227                           &active,
228                           -1);
229             
230       gtk_tree_store_set (GTK_TREE_STORE (model),
231                           &iter,
232                           BOOL_COLUMN,
233                           !active,
234                           -1);
235     }
236   else
237     g_warning ("don't know how to actually toggle value for model type %s",
238                g_type_name (G_TYPE_FROM_INSTANCE (model)));
239 }
240
241
242 static ColumnsType current_column_type = COLUMNS_LOTS;
243
244 static void
245 set_columns_type (GtkTreeView *tree_view, ColumnsType type)
246 {
247   GtkTreeViewColumn *col;
248   GtkCellRenderer *rend;
249   GdkPixbuf *pixbuf;
250   GtkWidget *image;
251   
252   current_column_type = type;
253   
254   col = gtk_tree_view_get_column (tree_view, 0);
255   while (col)
256     {
257       gtk_tree_view_remove_column (tree_view, col);
258
259       col = gtk_tree_view_get_column (tree_view, 0);
260     }
261
262   gtk_tree_view_set_rules_hint (tree_view, FALSE);
263   
264   switch (type)
265     {
266     case COLUMNS_NONE:
267       break;
268
269     case COLUMNS_LOTS:
270       /* with lots of columns we need to turn on rules */
271       gtk_tree_view_set_rules_hint (tree_view, TRUE);
272       
273       rend = gtk_cell_renderer_text_new ();
274       
275       col = gtk_tree_view_column_new_with_attributes ("Column 1",
276                                                       rend,
277                                                       "text", 1,
278                                                       NULL);
279       setup_column (col);
280       
281       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
282       
283       col = gtk_tree_view_column_new();
284       gtk_tree_view_column_set_title (col, "Column 2");
285       
286       rend = gtk_cell_renderer_pixbuf_new ();
287       gtk_tree_view_column_pack_start (col, rend, FALSE);
288       gtk_tree_view_column_add_attribute (col, rend, "pixbuf", 2);
289       rend = gtk_cell_renderer_text_new ();
290       gtk_tree_view_column_pack_start (col, rend, TRUE);
291       gtk_tree_view_column_add_attribute (col, rend, "text", 0);
292
293       setup_column (col);
294       
295       
296       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
297       gtk_tree_view_set_expander_column (tree_view, col);
298       
299       rend = gtk_cell_renderer_toggle_new ();
300
301       g_signal_connect (rend, "toggled",
302                         G_CALLBACK (toggled_callback), tree_view);
303       
304       col = gtk_tree_view_column_new_with_attributes ("Column 3",
305                                                       rend,
306                                                       "active", BOOL_COLUMN,
307                                                       NULL);
308
309       setup_column (col);
310       
311       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
312
313       pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)book_closed_xpm);
314
315       image = gtk_image_new_from_pixbuf (pixbuf);
316
317       g_object_unref (pixbuf);
318       
319       gtk_widget_show (image);
320       
321       gtk_tree_view_column_set_widget (col, image);
322       
323       rend = gtk_cell_renderer_toggle_new ();
324
325       /* you could also set this per-row by tying it to a column
326        * in the model of course.
327        */
328       g_object_set (rend, "radio", TRUE, NULL);
329       
330       g_signal_connect (rend, "toggled",
331                         G_CALLBACK (toggled_callback), tree_view);
332       
333       col = gtk_tree_view_column_new_with_attributes ("Column 4",
334                                                       rend,
335                                                       "active", BOOL_COLUMN,
336                                                       NULL);
337
338       setup_column (col);
339       
340       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
341       
342 #if 0
343
344       rend = gtk_cell_renderer_text_new ();
345       
346       col = gtk_tree_view_column_new_with_attributes ("Column 5",
347                                                       rend,
348                                                       "text", 3,
349                                                       NULL);
350
351       setup_column (col);
352       
353       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
354       
355       rend = gtk_cell_renderer_text_new ();
356       
357       col = gtk_tree_view_column_new_with_attributes ("Column 6",
358                                                       rend,
359                                                       "text", 4,
360                                                       NULL);
361
362       setup_column (col);
363       
364       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
365       
366       rend = gtk_cell_renderer_text_new ();
367       
368       col = gtk_tree_view_column_new_with_attributes ("Column 7",
369                                                       rend,
370                                                       "text", 5,
371                                                       NULL);
372
373       setup_column (col);
374       
375       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
376       
377       rend = gtk_cell_renderer_text_new ();
378       
379       col = gtk_tree_view_column_new_with_attributes ("Column 8",
380                                                       rend,
381                                                       "text", 6,
382                                                       NULL);
383
384       setup_column (col);
385       
386       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
387       
388       rend = gtk_cell_renderer_text_new ();
389       
390       col = gtk_tree_view_column_new_with_attributes ("Column 9",
391                                                       rend,
392                                                       "text", 7,
393                                                       NULL);
394
395       setup_column (col);
396       
397       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
398       
399       rend = gtk_cell_renderer_text_new ();
400       
401       col = gtk_tree_view_column_new_with_attributes ("Column 10",
402                                                       rend,
403                                                       "text", 8,
404                                                       NULL);
405
406       setup_column (col);
407       
408       gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
409       
410 #endif
411       
412       /* FALL THRU */
413       
414     case COLUMNS_ONE:
415       rend = gtk_cell_renderer_text_new ();
416       
417       col = gtk_tree_view_column_new_with_attributes ("Column 0",
418                                                       rend,
419                                                       "text", 0,
420                                                       NULL);
421
422       setup_column (col);
423       
424       gtk_tree_view_insert_column (GTK_TREE_VIEW (tree_view), col, 0);
425     default:
426       break;
427     }
428 }
429
430 static ColumnsType
431 get_columns_type (void)
432 {
433   return current_column_type;
434 }
435
436 static GdkPixbuf *our_pixbuf;
437   
438 typedef enum
439 {
440   /*   MODEL_TYPES, */
441   MODEL_TREE,
442   MODEL_LIST,
443   MODEL_SORTED_TREE,
444   MODEL_SORTED_LIST,
445   MODEL_EMPTY_LIST,
446   MODEL_EMPTY_TREE,
447   MODEL_NULL,
448   MODEL_LAST
449 } ModelType;
450
451 /* FIXME add a custom model to test */
452 static GtkTreeModel *models[MODEL_LAST];
453 static const char *model_names[MODEL_LAST] = {
454   "GtkTreeStore",
455   "GtkListStore",
456   "GtkTreeModelSort wrapping GtkTreeStore",
457   "GtkTreeModelSort wrapping GtkListStore",
458   "Empty GtkListStore",
459   "Empty GtkTreeStore",
460   "NULL (no model)"
461 };
462
463 static GtkTreeModel*
464 create_list_model (void)
465 {
466   GtkListStore *store;
467   GtkTreeIter iter;
468   gint i;
469   GType *t;
470
471   t = get_model_types ();
472   
473   store = gtk_list_store_new (N_COLUMNS,
474                               t[0], t[1], t[2],
475                               t[3], t[4], t[5],
476                               t[6], t[7], t[8]);
477
478   i = 0;
479   while (i < 200)
480     {
481       char *msg;
482       
483       gtk_list_store_append (store, &iter);
484
485       msg = g_strdup_printf ("%d", i);
486       
487       gtk_list_store_set (store, &iter, 0, msg, 1, "Foo! Foo! Foo!",
488                           2, our_pixbuf,
489                           3, 7.0, 4, (guint) 9000,
490                           5, 'f', 6, 'g',
491                           7, TRUE, 8, 23245454,
492                           -1);
493
494       g_free (msg);
495       
496       ++i;
497     }
498
499   return GTK_TREE_MODEL (store);
500 }
501
502 static void
503 typesystem_recurse (GType        type,
504                     GtkTreeIter *parent_iter,
505                     GtkTreeStore *store)
506 {
507   GType* children;
508   guint n_children = 0;
509   gint i;
510   GtkTreeIter iter;
511   gchar *str;
512   
513   gtk_tree_store_append (store, &iter, parent_iter);
514
515   str = g_strdup_printf ("%ld", (glong)type);
516   gtk_tree_store_set (store, &iter, 0, str, 1, g_type_name (type),
517                       2, our_pixbuf,
518                       3, 7.0, 4, (guint) 9000,
519                       5, 'f', 6, 'g',
520                       7, TRUE, 8, 23245454,
521                       -1);
522   g_free (str);
523   
524   children = g_type_children (type, &n_children);
525
526   i = 0;
527   while (i < n_children)
528     {
529       typesystem_recurse (children[i], &iter, store);
530
531       ++i;
532     }
533   
534   g_free (children);
535 }
536
537 static GtkTreeModel*
538 create_tree_model (void)
539 {
540   GtkTreeStore *store;
541   gint i;
542   GType *t;
543   volatile GType dummy; /* G_GNUC_CONST makes the optimizer remove
544                          * get_type calls if you don't do something
545                          * like this
546                          */
547   
548   /* Make the tree more interesting */
549   dummy = gtk_scrolled_window_get_type ();
550   dummy = gtk_label_get_type ();
551   dummy = gtk_hscrollbar_get_type ();
552   dummy = gtk_vscrollbar_get_type ();
553   dummy = pango_layout_get_type ();
554
555   t = get_model_types ();
556   
557   store = gtk_tree_store_new (N_COLUMNS,
558                               t[0], t[1], t[2],
559                               t[3], t[4], t[5],
560                               t[6], t[7], t[8]);
561
562   i = 0;
563   while (i < G_TYPE_FUNDAMENTAL_MAX)
564     {
565       typesystem_recurse (i, NULL, store);
566       
567       ++i;
568     }
569
570   return GTK_TREE_MODEL (store);
571 }
572
573 static void
574 model_selected (GtkOptionMenu *om, gpointer data)
575 {
576   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
577   gint hist;
578
579   hist = gtk_option_menu_get_history (om);
580
581   if (models[hist] != gtk_tree_view_get_model (tree_view))
582     {
583       gtk_tree_view_set_model (tree_view, models[hist]);
584     }
585 }
586
587 static void
588 columns_selected (GtkOptionMenu *om, gpointer data)
589 {
590   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
591   gint hist;
592
593   hist = gtk_option_menu_get_history (om);
594
595   if (hist != get_columns_type ())
596     {
597       set_columns_type (tree_view, hist);
598     }
599 }
600
601
602 enum
603 {
604   TARGET_GTK_TREE_MODEL_ROW
605 };
606
607 static GtkTargetEntry row_targets[] = {
608   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP,
609     TARGET_GTK_TREE_MODEL_ROW }
610 };
611
612 int
613 main (int    argc,
614       char **argv)
615 {
616   GtkWidget *window;
617   GtkWidget *sw;
618   GtkWidget *tv;
619   GtkWidget *table;
620   GtkWidget *om;
621   GtkWidget *menu;
622   GtkTreeModel *model;
623   gint i;
624   
625   gtk_init (&argc, &argv);
626
627   our_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) book_closed_xpm);  
628   
629 #if 0
630   models[MODEL_TYPES] = GTK_TREE_MODEL (gtk_tree_model_types_new ());
631 #endif
632   models[MODEL_LIST] = create_list_model ();
633   models[MODEL_TREE] = create_tree_model ();
634
635   model = create_list_model ();
636   models[MODEL_SORTED_LIST] = gtk_tree_model_sort_new_with_model (model);
637   g_object_unref (model);
638
639   model = create_tree_model ();
640   models[MODEL_SORTED_TREE] = gtk_tree_model_sort_new_with_model (model);
641   g_object_unref (model);
642
643   models[MODEL_EMPTY_LIST] = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_INT));
644   models[MODEL_EMPTY_TREE] = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
645   
646   models[MODEL_NULL] = NULL;
647
648   run_automated_tests ();
649   
650   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
651   g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
652   gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
653
654   table = gtk_table_new (3, 1, FALSE);
655
656   gtk_container_add (GTK_CONTAINER (window), table);
657
658   tv = gtk_tree_view_new_with_model (models[0]);
659   
660   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tv),
661                                           GDK_BUTTON1_MASK,
662                                           row_targets,
663                                           G_N_ELEMENTS (row_targets),
664                                           GDK_ACTION_MOVE | GDK_ACTION_COPY);
665
666   gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tv),
667                                         row_targets,
668                                         G_N_ELEMENTS (row_targets),
669                                         GDK_ACTION_MOVE | GDK_ACTION_COPY);
670   
671   /* Model menu */
672
673   menu = gtk_menu_new ();
674   
675   i = 0;
676   while (i < MODEL_LAST)
677     {
678       GtkWidget *mi;
679       const char *name;
680
681       name = model_names[i];
682       
683       mi = gtk_menu_item_new_with_label (name);
684
685       gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
686
687 #if 0
688       window = create_prop_editor (G_OBJECT (models[i]));
689
690       gtk_window_set_title (GTK_WINDOW (window),                            
691                             name);
692 #endif
693
694       ++i;
695     }
696   gtk_widget_show_all (menu);
697   
698   om = gtk_option_menu_new ();
699   gtk_option_menu_set_menu (GTK_OPTION_MENU (om), menu);
700   
701   gtk_table_attach (GTK_TABLE (table), om,
702                     0, 1, 0, 1,
703                     0, 0, 
704                     0, 0);
705
706   g_signal_connect (om,
707                     "changed",
708                     G_CALLBACK (model_selected),
709                     tv);
710   
711   /* Columns menu */
712
713   menu = gtk_menu_new ();
714   
715   i = 0;
716   while (i < COLUMNS_LAST)
717     {
718       GtkWidget *mi;
719       const char *name;
720
721       name = column_type_names[i];
722       
723       mi = gtk_menu_item_new_with_label (name);
724
725       gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
726
727       ++i;
728     }
729   gtk_widget_show_all (menu);
730   
731   om = gtk_option_menu_new ();
732   gtk_option_menu_set_menu (GTK_OPTION_MENU (om), menu);
733   
734   gtk_table_attach (GTK_TABLE (table), om,
735                     0, 1, 1, 2,
736                     0, 0, 
737                     0, 0);
738
739   set_columns_type (GTK_TREE_VIEW (tv), COLUMNS_LOTS);
740   gtk_option_menu_set_history (GTK_OPTION_MENU (om), COLUMNS_LOTS);
741   
742   g_signal_connect (om,
743                     "changed",
744                     G_CALLBACK (columns_selected),
745                     tv);
746   
747   sw = gtk_scrolled_window_new (NULL, NULL);
748   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
749                                   GTK_POLICY_AUTOMATIC,
750                                   GTK_POLICY_AUTOMATIC);
751   
752   gtk_table_attach (GTK_TABLE (table), sw,
753                     0, 1, 2, 3,
754                     GTK_EXPAND | GTK_FILL,
755                     GTK_EXPAND | GTK_FILL,
756                     0, 0);
757   
758   gtk_container_add (GTK_CONTAINER (sw), tv);
759   
760   gtk_widget_show_all (window);
761   
762   gtk_main ();
763
764   return 0;
765 }
766
767 /*
768  * GtkTreeModelTypes
769  */
770
771 static void         gtk_tree_model_types_init                 (GtkTreeModelTypes      *model_types);
772 static void         gtk_tree_model_types_tree_model_init      (GtkTreeModelIface   *iface);
773 static gint         gtk_real_model_types_get_n_columns   (GtkTreeModel        *tree_model);
774 static GType        gtk_real_model_types_get_column_type (GtkTreeModel        *tree_model,
775                                                            gint                 index);
776 static GtkTreePath *gtk_real_model_types_get_path        (GtkTreeModel        *tree_model,
777                                                            GtkTreeIter         *iter);
778 static void         gtk_real_model_types_get_value       (GtkTreeModel        *tree_model,
779                                                            GtkTreeIter         *iter,
780                                                            gint                 column,
781                                                            GValue              *value);
782 static gboolean     gtk_real_model_types_iter_next       (GtkTreeModel        *tree_model,
783                                                            GtkTreeIter         *iter);
784 static gboolean     gtk_real_model_types_iter_children   (GtkTreeModel        *tree_model,
785                                                            GtkTreeIter         *iter,
786                                                            GtkTreeIter         *parent);
787 static gboolean     gtk_real_model_types_iter_has_child  (GtkTreeModel        *tree_model,
788                                                            GtkTreeIter         *iter);
789 static gint         gtk_real_model_types_iter_n_children (GtkTreeModel        *tree_model,
790                                                            GtkTreeIter         *iter);
791 static gboolean     gtk_real_model_types_iter_nth_child  (GtkTreeModel        *tree_model,
792                                                            GtkTreeIter         *iter,
793                                                            GtkTreeIter         *parent,
794                                                            gint                 n);
795 static gboolean     gtk_real_model_types_iter_parent     (GtkTreeModel        *tree_model,
796                                                            GtkTreeIter         *iter,
797                                                            GtkTreeIter         *child);
798
799
800 GType
801 gtk_tree_model_types_get_type (void)
802 {
803   static GType model_types_type = 0;
804
805   if (!model_types_type)
806     {
807       static const GTypeInfo model_types_info =
808       {
809         sizeof (GtkTreeModelTypesClass),
810         NULL,           /* base_init */
811         NULL,           /* base_finalize */
812         NULL,           /* class_init */
813         NULL,           /* class_finalize */
814         NULL,           /* class_data */
815         sizeof (GtkTreeModelTypes),
816         0,
817         (GInstanceInitFunc) gtk_tree_model_types_init
818       };
819
820       static const GInterfaceInfo tree_model_info =
821       {
822         (GInterfaceInitFunc) gtk_tree_model_types_tree_model_init,
823         NULL,
824         NULL
825       };
826
827       model_types_type = g_type_register_static (G_TYPE_OBJECT,
828                                                  "GtkTreeModelTypes",
829                                                  &model_types_info, 0);
830       g_type_add_interface_static (model_types_type,
831                                    GTK_TYPE_TREE_MODEL,
832                                    &tree_model_info);
833     }
834
835   return model_types_type;
836 }
837
838 GtkTreeModelTypes *
839 gtk_tree_model_types_new (void)
840 {
841   GtkTreeModelTypes *retval;
842
843   retval = GTK_TREE_MODEL_TYPES (g_object_new (GTK_TYPE_MODEL_TYPES, NULL));
844
845   return retval;
846 }
847
848 static void
849 gtk_tree_model_types_tree_model_init (GtkTreeModelIface *iface)
850 {
851   iface->get_n_columns = gtk_real_model_types_get_n_columns;
852   iface->get_column_type = gtk_real_model_types_get_column_type;
853   iface->get_path = gtk_real_model_types_get_path;
854   iface->get_value = gtk_real_model_types_get_value;
855   iface->iter_next = gtk_real_model_types_iter_next;
856   iface->iter_children = gtk_real_model_types_iter_children;
857   iface->iter_has_child = gtk_real_model_types_iter_has_child;
858   iface->iter_n_children = gtk_real_model_types_iter_n_children;
859   iface->iter_nth_child = gtk_real_model_types_iter_nth_child;
860   iface->iter_parent = gtk_real_model_types_iter_parent;
861 }
862
863 static void
864 gtk_tree_model_types_init (GtkTreeModelTypes *model_types)
865 {
866   model_types->stamp = g_random_int ();
867 }
868
869 static GType column_types[] = {
870   G_TYPE_STRING, /* GType */
871   G_TYPE_STRING  /* type name */
872 };
873   
874 static gint
875 gtk_real_model_types_get_n_columns (GtkTreeModel *tree_model)
876 {
877   return G_N_ELEMENTS (column_types);
878 }
879
880 static GType
881 gtk_real_model_types_get_column_type (GtkTreeModel *tree_model,
882                                       gint          index)
883 {
884   g_return_val_if_fail (index < G_N_ELEMENTS (column_types), G_TYPE_INVALID);
885   
886   return column_types[index];
887 }
888
889 #if 0
890 /* Use default implementation of this */
891 static gboolean
892 gtk_real_model_types_get_iter (GtkTreeModel *tree_model,
893                                GtkTreeIter  *iter,
894                                GtkTreePath  *path)
895 {
896   
897 }
898 #endif
899
900 /* The toplevel nodes of the tree are the reserved types, G_TYPE_NONE through
901  * G_TYPE_RESERVED_FUNDAMENTAL.
902  */
903
904 static GtkTreePath *
905 gtk_real_model_types_get_path (GtkTreeModel *tree_model,
906                                GtkTreeIter  *iter)
907 {
908   GtkTreePath *retval;
909   GType type;
910   GType parent;
911   
912   g_return_val_if_fail (GTK_IS_TREE_MODEL_TYPES (tree_model), NULL);
913   g_return_val_if_fail (iter != NULL, NULL);
914
915   type = GPOINTER_TO_INT (iter->user_data);
916   
917   retval = gtk_tree_path_new ();
918   
919   parent = g_type_parent (type);
920   while (parent != G_TYPE_INVALID)
921     {
922       GType* children = g_type_children (parent, NULL);
923       gint i = 0;
924
925       if (!children || children[0] == G_TYPE_INVALID)
926         {
927           g_warning ("bad iterator?");
928           return NULL;
929         }
930       
931       while (children[i] != type)
932         ++i;
933
934       gtk_tree_path_prepend_index (retval, i);
935
936       g_free (children);
937       
938       type = parent;
939       parent = g_type_parent (parent);
940     }
941
942   /* The fundamental type itself is the index on the toplevel */
943   gtk_tree_path_prepend_index (retval, type);
944
945   return retval;
946 }
947
948 static void
949 gtk_real_model_types_get_value (GtkTreeModel *tree_model,
950                                 GtkTreeIter  *iter,
951                                 gint          column,
952                                 GValue       *value)
953 {
954   GType type;
955
956   type = GPOINTER_TO_INT (iter->user_data);
957
958   switch (column)
959     {
960     case 0:
961       {
962         gchar *str;
963         
964         g_value_init (value, G_TYPE_STRING);
965
966         str = g_strdup_printf ("%ld", type);
967         g_value_set_string (value, str);
968         g_free (str);
969       }
970       break;
971
972     case 1:
973       g_value_init (value, G_TYPE_STRING);
974       g_value_set_string (value, g_type_name (type));
975       break;
976
977     default:
978       g_warning ("Bad column %d requested", column);
979     }
980 }
981
982 static gboolean
983 gtk_real_model_types_iter_next (GtkTreeModel  *tree_model,
984                                 GtkTreeIter   *iter)
985 {
986   
987   GType parent;
988   GType type;
989
990   type = GPOINTER_TO_INT (iter->user_data);
991
992   parent = g_type_parent (type);
993   
994   if (parent == G_TYPE_INVALID)
995     {
996       /* find next _valid_ fundamental type */
997       do
998         type++;
999       while (!g_type_name (type) && type <= G_TYPE_FUNDAMENTAL_MAX);
1000       if (type <= G_TYPE_FUNDAMENTAL_MAX)
1001         {
1002           /* found one */
1003           iter->user_data = GINT_TO_POINTER (type);
1004           return TRUE;
1005         }
1006       else
1007         return FALSE;
1008     }
1009   else
1010     {
1011       GType* children = g_type_children (parent, NULL);
1012       gint i = 0;
1013
1014       g_assert (children != NULL);
1015       
1016       while (children[i] != type)
1017         ++i;
1018   
1019       ++i;
1020
1021       if (children[i] != G_TYPE_INVALID)
1022         {
1023           g_free (children);
1024           iter->user_data = GINT_TO_POINTER (children[i]);
1025           return TRUE;
1026         }
1027       else
1028         {
1029           g_free (children);
1030           return FALSE;
1031         }
1032     }
1033 }
1034
1035 static gboolean
1036 gtk_real_model_types_iter_children (GtkTreeModel *tree_model,
1037                                     GtkTreeIter  *iter,
1038                                     GtkTreeIter  *parent)
1039 {
1040   GType type;
1041   GType* children;
1042   
1043   type = GPOINTER_TO_INT (parent->user_data);
1044
1045   children = g_type_children (type, NULL);
1046
1047   if (!children || children[0] == G_TYPE_INVALID)
1048     {
1049       g_free (children);
1050       return FALSE;
1051     }
1052   else
1053     {
1054       iter->user_data = GINT_TO_POINTER (children[0]);
1055       g_free (children);
1056       return TRUE;
1057     }
1058 }
1059
1060 static gboolean
1061 gtk_real_model_types_iter_has_child (GtkTreeModel *tree_model,
1062                                      GtkTreeIter  *iter)
1063 {
1064   GType type;
1065   GType* children;
1066   
1067   type = GPOINTER_TO_INT (iter->user_data);
1068   
1069   children = g_type_children (type, NULL);
1070
1071   if (!children || children[0] == G_TYPE_INVALID)
1072     {
1073       g_free (children);
1074       return FALSE;
1075     }
1076   else
1077     {
1078       g_free (children);
1079       return TRUE;
1080     }
1081 }
1082
1083 static gint
1084 gtk_real_model_types_iter_n_children (GtkTreeModel *tree_model,
1085                                       GtkTreeIter  *iter)
1086 {
1087   if (iter == NULL)
1088     {
1089       return G_TYPE_FUNDAMENTAL_MAX;
1090     }
1091   else
1092     {
1093       GType type;
1094       GType* children;
1095       guint n_children = 0;
1096
1097       type = GPOINTER_TO_INT (iter->user_data);
1098       
1099       children = g_type_children (type, &n_children);
1100       
1101       g_free (children);
1102       
1103       return n_children;
1104     }
1105 }
1106
1107 static gboolean
1108 gtk_real_model_types_iter_nth_child (GtkTreeModel *tree_model,
1109                                      GtkTreeIter  *iter,
1110                                      GtkTreeIter  *parent,
1111                                      gint          n)
1112 {  
1113   if (parent == NULL)
1114     {
1115       /* fundamental type */
1116       if (n < G_TYPE_FUNDAMENTAL_MAX)
1117         {
1118           iter->user_data = GINT_TO_POINTER (n);
1119           return TRUE;
1120         }
1121       else
1122         return FALSE;
1123     }
1124   else
1125     {
1126       GType type = GPOINTER_TO_INT (parent->user_data);      
1127       guint n_children = 0;
1128       GType* children = g_type_children (type, &n_children);
1129
1130       if (n_children == 0)
1131         {
1132           g_free (children);
1133           return FALSE;
1134         }
1135       else if (n >= n_children)
1136         {
1137           g_free (children);
1138           return FALSE;
1139         }
1140       else
1141         {
1142           iter->user_data = GINT_TO_POINTER (children[n]);
1143           g_free (children);
1144
1145           return TRUE;
1146         }
1147     }
1148 }
1149
1150 static gboolean
1151 gtk_real_model_types_iter_parent (GtkTreeModel *tree_model,
1152                                   GtkTreeIter  *iter,
1153                                   GtkTreeIter  *child)
1154 {
1155   GType type;
1156   GType parent;
1157   
1158   type = GPOINTER_TO_INT (child->user_data);
1159   
1160   parent = g_type_parent (type);
1161   
1162   if (parent == G_TYPE_INVALID)
1163     {
1164       if (type > G_TYPE_FUNDAMENTAL_MAX)
1165         g_warning ("no parent for %ld %s\n", type, g_type_name (type));
1166       return FALSE;
1167     }
1168   else
1169     {
1170       iter->user_data = GINT_TO_POINTER (parent);
1171       
1172       return TRUE;
1173     }
1174 }
1175
1176 /*
1177  * Automated testing
1178  */
1179
1180 static void
1181 treestore_torture_recurse (GtkTreeStore *store,
1182                            GtkTreeIter  *root,
1183                            gint          depth)
1184 {
1185   GtkTreeModel *model;
1186   gint i;
1187   GtkTreeIter iter;  
1188   
1189   model = GTK_TREE_MODEL (store);    
1190
1191   if (depth > 2)
1192     return;
1193
1194   ++depth;
1195
1196   gtk_tree_store_append (store, &iter, root);
1197   
1198   gtk_tree_model_iter_children (model, &iter, root);
1199   
1200   i = 0;
1201   while (i < 100)
1202     {
1203       gtk_tree_store_append (store, &iter, root);
1204       ++i;
1205     }
1206
1207   while (gtk_tree_model_iter_children (model, &iter, root))
1208     gtk_tree_store_remove (store, &iter);
1209
1210   gtk_tree_store_append (store, &iter, root);
1211
1212   /* inserts before last node in tree */
1213   i = 0;
1214   while (i < 100)
1215     {
1216       gtk_tree_store_insert_before (store, &iter, root, &iter);
1217       ++i;
1218     }
1219
1220   /* inserts after the node before the last node */
1221   i = 0;
1222   while (i < 100)
1223     {
1224       gtk_tree_store_insert_after (store, &iter, root, &iter);
1225       ++i;
1226     }
1227
1228   /* inserts after the last node */
1229   gtk_tree_store_append (store, &iter, root);
1230     
1231   i = 0;
1232   while (i < 100)
1233     {
1234       gtk_tree_store_insert_after (store, &iter, root, &iter);
1235       ++i;
1236     }
1237
1238   /* remove everything again */
1239   while (gtk_tree_model_iter_children (model, &iter, root))
1240     gtk_tree_store_remove (store, &iter);
1241
1242
1243     /* Prepends */
1244   gtk_tree_store_prepend (store, &iter, root);
1245     
1246   i = 0;
1247   while (i < 100)
1248     {
1249       gtk_tree_store_prepend (store, &iter, root);
1250       ++i;
1251     }
1252
1253   /* remove everything again */
1254   while (gtk_tree_model_iter_children (model, &iter, root))
1255     gtk_tree_store_remove (store, &iter);
1256
1257   gtk_tree_store_append (store, &iter, root);
1258   gtk_tree_store_append (store, &iter, root);
1259   gtk_tree_store_append (store, &iter, root);
1260   gtk_tree_store_append (store, &iter, root);
1261
1262   while (gtk_tree_model_iter_children (model, &iter, root))
1263     {
1264       treestore_torture_recurse (store, &iter, depth);
1265       gtk_tree_store_remove (store, &iter);
1266     }
1267 }
1268
1269 static void
1270 run_automated_tests (void)
1271 {
1272   g_print ("Running automated tests...\n");
1273   
1274   /* FIXME TreePath basic verification */
1275
1276   /* FIXME generic consistency checks on the models */
1277
1278   {
1279     /* Make sure list store mutations don't crash anything */
1280     GtkListStore *store;
1281     GtkTreeModel *model;
1282     gint i;
1283     GtkTreeIter iter;
1284     
1285     store = gtk_list_store_new (1, G_TYPE_INT);
1286
1287     model = GTK_TREE_MODEL (store);
1288     
1289     i = 0;
1290     while (i < 100)
1291       {
1292         gtk_list_store_append (store, &iter);
1293         ++i;
1294       }
1295
1296     while (gtk_tree_model_get_iter_first (model, &iter))
1297       gtk_list_store_remove (store, &iter);
1298
1299     gtk_list_store_append (store, &iter);
1300
1301     /* inserts before last node in list */
1302     i = 0;
1303     while (i < 100)
1304       {
1305         gtk_list_store_insert_before (store, &iter, &iter);
1306         ++i;
1307       }
1308
1309     /* inserts after the node before the last node */
1310     i = 0;
1311     while (i < 100)
1312       {
1313         gtk_list_store_insert_after (store, &iter, &iter);
1314         ++i;
1315       }
1316
1317     /* inserts after the last node */
1318     gtk_list_store_append (store, &iter);
1319     
1320     i = 0;
1321     while (i < 100)
1322       {
1323         gtk_list_store_insert_after (store, &iter, &iter);
1324         ++i;
1325       }
1326
1327     /* remove everything again */
1328     while (gtk_tree_model_get_iter_first (model, &iter))
1329       gtk_list_store_remove (store, &iter);
1330
1331
1332     /* Prepends */
1333     gtk_list_store_prepend (store, &iter);
1334     
1335     i = 0;
1336     while (i < 100)
1337       {
1338         gtk_list_store_prepend (store, &iter);
1339         ++i;
1340       }
1341
1342     /* remove everything again */
1343     while (gtk_tree_model_get_iter_first (model, &iter))
1344       gtk_list_store_remove (store, &iter);
1345     
1346     g_object_unref (store);
1347   }
1348
1349   {
1350     /* Make sure tree store mutations don't crash anything */
1351     GtkTreeStore *store;
1352     GtkTreeIter root;
1353
1354     store = gtk_tree_store_new (1, G_TYPE_INT);
1355     gtk_tree_store_append (GTK_TREE_STORE (store), &root, NULL);
1356     /* Remove test until it is rewritten to work */
1357     /*    treestore_torture_recurse (store, &root, 0);*/
1358     
1359     g_object_unref (store);
1360   }
1361
1362   g_print ("Passed.\n");
1363 }