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

source code of gtk/tests/testtreeview.c