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