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