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