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*
get_model_types(void)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
col_clicked_cb(GtkTreeViewColumn * col,gpointer data)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
setup_column(GtkTreeViewColumn * col)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
toggled_callback(GtkCellRendererToggle * celltoggle,gchar * path_string,GtkTreeView * tree_view)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
edited_callback(GtkCellRendererText * renderer,const gchar * path_string,const gchar * new_text,GtkTreeView * tree_view)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
set_columns_type(GtkTreeView * tree_view,ColumnsType type)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
get_columns_type(void)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*
create_list_model(void)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
typesystem_recurse(GType type,GtkTreeIter * parent_iter,GtkTreeStore * store)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*
create_tree_model(void)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
model_selected(GtkComboBox * combo_box,gpointer data)661 model_selected (GtkComboBox *combo_box, gpointer data)
662 {
663 GtkTreeView *tree_view = GTK_TREE_VIEW (data);
664 gint hist;
665
666 hist = gtk_combo_box_get_active (combo_box);
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
columns_selected(GtkComboBox * combo_box,gpointer data)675 columns_selected (GtkComboBox *combo_box, gpointer data)
676 {
677 GtkTreeView *tree_view = GTK_TREE_VIEW (data);
678 gint hist;
679
680 hist = gtk_combo_box_get_active (combo_box);
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
main(int argc,char ** argv)700 main (int argc,
701 char **argv)
702 {
703 GtkWidget *window;
704 GtkWidget *sw;
705 GtkWidget *tv;
706 GtkWidget *table;
707 GtkWidget *combo_box;
708 GtkTreeModel *model;
709 gint i;
710
711 gtk_init (&argc, &argv);
712
713 our_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) book_closed_xpm);
714
715 #if 0
716 models[MODEL_TYPES] = GTK_TREE_MODEL (gtk_tree_model_types_new ());
717 #endif
718 models[MODEL_LIST] = create_list_model ();
719 models[MODEL_TREE] = create_tree_model ();
720
721 model = create_list_model ();
722 models[MODEL_SORTED_LIST] = gtk_tree_model_sort_new_with_model (model);
723 g_object_unref (model);
724
725 model = create_tree_model ();
726 models[MODEL_SORTED_TREE] = gtk_tree_model_sort_new_with_model (model);
727 g_object_unref (model);
728
729 models[MODEL_EMPTY_LIST] = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_INT));
730 models[MODEL_EMPTY_TREE] = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
731
732 models[MODEL_NULL] = NULL;
733
734 run_automated_tests ();
735
736 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
737 g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
738 gtk_window_set_default_size (GTK_WINDOW (window), 430, 400);
739
740 table = gtk_table_new (3, 1, FALSE);
741
742 gtk_container_add (GTK_CONTAINER (window), table);
743
744 tv = gtk_tree_view_new_with_model (models[0]);
745
746 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tv),
747 GDK_BUTTON1_MASK,
748 row_targets,
749 G_N_ELEMENTS (row_targets),
750 GDK_ACTION_MOVE | GDK_ACTION_COPY);
751
752 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tv),
753 row_targets,
754 G_N_ELEMENTS (row_targets),
755 GDK_ACTION_MOVE | GDK_ACTION_COPY);
756
757 /* Model menu */
758 combo_box = gtk_combo_box_text_new ();
759 for (i = 0; i < MODEL_LAST; i++)
760 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), model_names[i]);
761
762 gtk_table_attach (GTK_TABLE (table), combo_box,
763 0, 1, 0, 1,
764 0, 0,
765 0, 0);
766
767 g_signal_connect (combo_box,
768 "changed",
769 G_CALLBACK (model_selected),
770 tv);
771
772 /* Columns menu */
773 combo_box = gtk_combo_box_text_new ();
774 for (i = 0; i < COLUMNS_LAST; i++)
775 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), column_type_names[i]);
776
777 gtk_table_attach (GTK_TABLE (table), combo_box,
778 0, 1, 1, 2,
779 0, 0,
780 0, 0);
781
782 set_columns_type (GTK_TREE_VIEW (tv), COLUMNS_LOTS);
783 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), COLUMNS_LOTS);
784
785 g_signal_connect (combo_box,
786 "changed",
787 G_CALLBACK (columns_selected),
788 tv);
789
790 sw = gtk_scrolled_window_new (NULL, NULL);
791 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
792 GTK_POLICY_AUTOMATIC,
793 GTK_POLICY_AUTOMATIC);
794
795 gtk_table_attach (GTK_TABLE (table), sw,
796 0, 1, 2, 3,
797 GTK_EXPAND | GTK_FILL,
798 GTK_EXPAND | GTK_FILL,
799 0, 0);
800
801 gtk_container_add (GTK_CONTAINER (sw), tv);
802
803 gtk_widget_show_all (window);
804
805 gtk_main ();
806
807 return 0;
808 }
809
810 /*
811 * GtkTreeModelTypes
812 */
813
814 static void gtk_tree_model_types_init (GtkTreeModelTypes *model_types);
815 static void gtk_tree_model_types_tree_model_init (GtkTreeModelIface *iface);
816 static gint gtk_real_model_types_get_n_columns (GtkTreeModel *tree_model);
817 static GType gtk_real_model_types_get_column_type (GtkTreeModel *tree_model,
818 gint index);
819 static GtkTreePath *gtk_real_model_types_get_path (GtkTreeModel *tree_model,
820 GtkTreeIter *iter);
821 static void gtk_real_model_types_get_value (GtkTreeModel *tree_model,
822 GtkTreeIter *iter,
823 gint column,
824 GValue *value);
825 static gboolean gtk_real_model_types_iter_next (GtkTreeModel *tree_model,
826 GtkTreeIter *iter);
827 static gboolean gtk_real_model_types_iter_children (GtkTreeModel *tree_model,
828 GtkTreeIter *iter,
829 GtkTreeIter *parent);
830 static gboolean gtk_real_model_types_iter_has_child (GtkTreeModel *tree_model,
831 GtkTreeIter *iter);
832 static gint gtk_real_model_types_iter_n_children (GtkTreeModel *tree_model,
833 GtkTreeIter *iter);
834 static gboolean gtk_real_model_types_iter_nth_child (GtkTreeModel *tree_model,
835 GtkTreeIter *iter,
836 GtkTreeIter *parent,
837 gint n);
838 static gboolean gtk_real_model_types_iter_parent (GtkTreeModel *tree_model,
839 GtkTreeIter *iter,
840 GtkTreeIter *child);
841
842
843 GType
gtk_tree_model_types_get_type(void)844 gtk_tree_model_types_get_type (void)
845 {
846 static GType model_types_type = 0;
847
848 if (!model_types_type)
849 {
850 const GTypeInfo model_types_info =
851 {
852 sizeof (GtkTreeModelTypesClass),
853 NULL, /* base_init */
854 NULL, /* base_finalize */
855 NULL, /* class_init */
856 NULL, /* class_finalize */
857 NULL, /* class_data */
858 sizeof (GtkTreeModelTypes),
859 0,
860 (GInstanceInitFunc) gtk_tree_model_types_init
861 };
862
863 const GInterfaceInfo tree_model_info =
864 {
865 (GInterfaceInitFunc) gtk_tree_model_types_tree_model_init,
866 NULL,
867 NULL
868 };
869
870 model_types_type = g_type_register_static (G_TYPE_OBJECT,
871 "GtkTreeModelTypes",
872 &model_types_info, 0);
873 g_type_add_interface_static (model_types_type,
874 GTK_TYPE_TREE_MODEL,
875 &tree_model_info);
876 }
877
878 return model_types_type;
879 }
880
881 GtkTreeModelTypes *
gtk_tree_model_types_new(void)882 gtk_tree_model_types_new (void)
883 {
884 GtkTreeModelTypes *retval;
885
886 retval = g_object_new (GTK_TYPE_MODEL_TYPES, NULL);
887
888 return retval;
889 }
890
891 static void
gtk_tree_model_types_tree_model_init(GtkTreeModelIface * iface)892 gtk_tree_model_types_tree_model_init (GtkTreeModelIface *iface)
893 {
894 iface->get_n_columns = gtk_real_model_types_get_n_columns;
895 iface->get_column_type = gtk_real_model_types_get_column_type;
896 iface->get_path = gtk_real_model_types_get_path;
897 iface->get_value = gtk_real_model_types_get_value;
898 iface->iter_next = gtk_real_model_types_iter_next;
899 iface->iter_children = gtk_real_model_types_iter_children;
900 iface->iter_has_child = gtk_real_model_types_iter_has_child;
901 iface->iter_n_children = gtk_real_model_types_iter_n_children;
902 iface->iter_nth_child = gtk_real_model_types_iter_nth_child;
903 iface->iter_parent = gtk_real_model_types_iter_parent;
904 }
905
906 static void
gtk_tree_model_types_init(GtkTreeModelTypes * model_types)907 gtk_tree_model_types_init (GtkTreeModelTypes *model_types)
908 {
909 model_types->stamp = g_random_int ();
910 }
911
912 static GType column_types[] = {
913 G_TYPE_STRING, /* GType */
914 G_TYPE_STRING /* type name */
915 };
916
917 static gint
gtk_real_model_types_get_n_columns(GtkTreeModel * tree_model)918 gtk_real_model_types_get_n_columns (GtkTreeModel *tree_model)
919 {
920 return G_N_ELEMENTS (column_types);
921 }
922
923 static GType
gtk_real_model_types_get_column_type(GtkTreeModel * tree_model,gint index)924 gtk_real_model_types_get_column_type (GtkTreeModel *tree_model,
925 gint index)
926 {
927 g_return_val_if_fail (index < G_N_ELEMENTS (column_types), G_TYPE_INVALID);
928
929 return column_types[index];
930 }
931
932 #if 0
933 /* Use default implementation of this */
934 static gboolean
935 gtk_real_model_types_get_iter (GtkTreeModel *tree_model,
936 GtkTreeIter *iter,
937 GtkTreePath *path)
938 {
939
940 }
941 #endif
942
943 /* The toplevel nodes of the tree are the reserved types, G_TYPE_NONE through
944 * G_TYPE_RESERVED_FUNDAMENTAL.
945 */
946
947 static GtkTreePath *
gtk_real_model_types_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)948 gtk_real_model_types_get_path (GtkTreeModel *tree_model,
949 GtkTreeIter *iter)
950 {
951 GtkTreePath *retval;
952 GType type;
953 GType parent;
954
955 g_return_val_if_fail (GTK_IS_TREE_MODEL_TYPES (tree_model), NULL);
956 g_return_val_if_fail (iter != NULL, NULL);
957
958 type = GPOINTER_TO_INT (iter->user_data);
959
960 retval = gtk_tree_path_new ();
961
962 parent = g_type_parent (type);
963 while (parent != G_TYPE_INVALID)
964 {
965 GType* children = g_type_children (parent, NULL);
966 gint i = 0;
967
968 if (!children || children[0] == G_TYPE_INVALID)
969 {
970 g_warning ("bad iterator?");
971 return NULL;
972 }
973
974 while (children[i] != type)
975 ++i;
976
977 gtk_tree_path_prepend_index (retval, i);
978
979 g_free (children);
980
981 type = parent;
982 parent = g_type_parent (parent);
983 }
984
985 /* The fundamental type itself is the index on the toplevel */
986 gtk_tree_path_prepend_index (retval, type);
987
988 return retval;
989 }
990
991 static void
gtk_real_model_types_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,gint column,GValue * value)992 gtk_real_model_types_get_value (GtkTreeModel *tree_model,
993 GtkTreeIter *iter,
994 gint column,
995 GValue *value)
996 {
997 GType type;
998
999 type = GPOINTER_TO_INT (iter->user_data);
1000
1001 switch (column)
1002 {
1003 case 0:
1004 {
1005 gchar *str;
1006
1007 g_value_init (value, G_TYPE_STRING);
1008
1009 str = g_strdup_printf ("%ld", (long int) type);
1010 g_value_set_string (value, str);
1011 g_free (str);
1012 }
1013 break;
1014
1015 case 1:
1016 g_value_init (value, G_TYPE_STRING);
1017 g_value_set_string (value, g_type_name (type));
1018 break;
1019
1020 default:
1021 g_warning ("Bad column %d requested", column);
1022 }
1023 }
1024
1025 static gboolean
gtk_real_model_types_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)1026 gtk_real_model_types_iter_next (GtkTreeModel *tree_model,
1027 GtkTreeIter *iter)
1028 {
1029
1030 GType parent;
1031 GType type;
1032
1033 type = GPOINTER_TO_INT (iter->user_data);
1034
1035 parent = g_type_parent (type);
1036
1037 if (parent == G_TYPE_INVALID)
1038 {
1039 /* find next _valid_ fundamental type */
1040 do
1041 type++;
1042 while (!g_type_name (type) && type <= G_TYPE_FUNDAMENTAL_MAX);
1043 if (type <= G_TYPE_FUNDAMENTAL_MAX)
1044 {
1045 /* found one */
1046 iter->user_data = GINT_TO_POINTER (type);
1047 return TRUE;
1048 }
1049 else
1050 return FALSE;
1051 }
1052 else
1053 {
1054 GType* children = g_type_children (parent, NULL);
1055 gint i = 0;
1056
1057 g_assert (children != NULL);
1058
1059 while (children[i] != type)
1060 ++i;
1061
1062 ++i;
1063
1064 if (children[i] != G_TYPE_INVALID)
1065 {
1066 g_free (children);
1067 iter->user_data = GINT_TO_POINTER (children[i]);
1068 return TRUE;
1069 }
1070 else
1071 {
1072 g_free (children);
1073 return FALSE;
1074 }
1075 }
1076 }
1077
1078 static gboolean
gtk_real_model_types_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)1079 gtk_real_model_types_iter_children (GtkTreeModel *tree_model,
1080 GtkTreeIter *iter,
1081 GtkTreeIter *parent)
1082 {
1083 GType type;
1084 GType* children;
1085
1086 type = GPOINTER_TO_INT (parent->user_data);
1087
1088 children = g_type_children (type, NULL);
1089
1090 if (!children || children[0] == G_TYPE_INVALID)
1091 {
1092 g_free (children);
1093 return FALSE;
1094 }
1095 else
1096 {
1097 iter->user_data = GINT_TO_POINTER (children[0]);
1098 g_free (children);
1099 return TRUE;
1100 }
1101 }
1102
1103 static gboolean
gtk_real_model_types_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)1104 gtk_real_model_types_iter_has_child (GtkTreeModel *tree_model,
1105 GtkTreeIter *iter)
1106 {
1107 GType type;
1108 GType* children;
1109
1110 type = GPOINTER_TO_INT (iter->user_data);
1111
1112 children = g_type_children (type, NULL);
1113
1114 if (!children || children[0] == G_TYPE_INVALID)
1115 {
1116 g_free (children);
1117 return FALSE;
1118 }
1119 else
1120 {
1121 g_free (children);
1122 return TRUE;
1123 }
1124 }
1125
1126 static gint
gtk_real_model_types_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)1127 gtk_real_model_types_iter_n_children (GtkTreeModel *tree_model,
1128 GtkTreeIter *iter)
1129 {
1130 if (iter == NULL)
1131 {
1132 return G_TYPE_FUNDAMENTAL_MAX;
1133 }
1134 else
1135 {
1136 GType type;
1137 GType* children;
1138 guint n_children = 0;
1139
1140 type = GPOINTER_TO_INT (iter->user_data);
1141
1142 children = g_type_children (type, &n_children);
1143
1144 g_free (children);
1145
1146 return n_children;
1147 }
1148 }
1149
1150 static gboolean
gtk_real_model_types_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,gint n)1151 gtk_real_model_types_iter_nth_child (GtkTreeModel *tree_model,
1152 GtkTreeIter *iter,
1153 GtkTreeIter *parent,
1154 gint n)
1155 {
1156 if (parent == NULL)
1157 {
1158 /* fundamental type */
1159 if (n < G_TYPE_FUNDAMENTAL_MAX)
1160 {
1161 iter->user_data = GINT_TO_POINTER (n);
1162 return TRUE;
1163 }
1164 else
1165 return FALSE;
1166 }
1167 else
1168 {
1169 GType type = GPOINTER_TO_INT (parent->user_data);
1170 guint n_children = 0;
1171 GType* children = g_type_children (type, &n_children);
1172
1173 if (n_children == 0)
1174 {
1175 g_free (children);
1176 return FALSE;
1177 }
1178 else if (n >= n_children)
1179 {
1180 g_free (children);
1181 return FALSE;
1182 }
1183 else
1184 {
1185 iter->user_data = GINT_TO_POINTER (children[n]);
1186 g_free (children);
1187
1188 return TRUE;
1189 }
1190 }
1191 }
1192
1193 static gboolean
gtk_real_model_types_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)1194 gtk_real_model_types_iter_parent (GtkTreeModel *tree_model,
1195 GtkTreeIter *iter,
1196 GtkTreeIter *child)
1197 {
1198 GType type;
1199 GType parent;
1200
1201 type = GPOINTER_TO_INT (child->user_data);
1202
1203 parent = g_type_parent (type);
1204
1205 if (parent == G_TYPE_INVALID)
1206 {
1207 if (type > G_TYPE_FUNDAMENTAL_MAX)
1208 g_warning ("no parent for %ld %s\n",
1209 (long int) type,
1210 g_type_name (type));
1211 return FALSE;
1212 }
1213 else
1214 {
1215 iter->user_data = GINT_TO_POINTER (parent);
1216
1217 return TRUE;
1218 }
1219 }
1220
1221 /*
1222 * Automated testing
1223 */
1224
1225 #if 0
1226
1227 static void
1228 treestore_torture_recurse (GtkTreeStore *store,
1229 GtkTreeIter *root,
1230 gint depth)
1231 {
1232 GtkTreeModel *model;
1233 gint i;
1234 GtkTreeIter iter;
1235
1236 model = GTK_TREE_MODEL (store);
1237
1238 if (depth > 2)
1239 return;
1240
1241 ++depth;
1242
1243 gtk_tree_store_append (store, &iter, root);
1244
1245 gtk_tree_model_iter_children (model, &iter, root);
1246
1247 i = 0;
1248 while (i < 100)
1249 {
1250 gtk_tree_store_append (store, &iter, root);
1251 ++i;
1252 }
1253
1254 while (gtk_tree_model_iter_children (model, &iter, root))
1255 gtk_tree_store_remove (store, &iter);
1256
1257 gtk_tree_store_append (store, &iter, root);
1258
1259 /* inserts before last node in tree */
1260 i = 0;
1261 while (i < 100)
1262 {
1263 gtk_tree_store_insert_before (store, &iter, root, &iter);
1264 ++i;
1265 }
1266
1267 /* inserts after the node before the last node */
1268 i = 0;
1269 while (i < 100)
1270 {
1271 gtk_tree_store_insert_after (store, &iter, root, &iter);
1272 ++i;
1273 }
1274
1275 /* inserts after the last node */
1276 gtk_tree_store_append (store, &iter, root);
1277
1278 i = 0;
1279 while (i < 100)
1280 {
1281 gtk_tree_store_insert_after (store, &iter, root, &iter);
1282 ++i;
1283 }
1284
1285 /* remove everything again */
1286 while (gtk_tree_model_iter_children (model, &iter, root))
1287 gtk_tree_store_remove (store, &iter);
1288
1289
1290 /* Prepends */
1291 gtk_tree_store_prepend (store, &iter, root);
1292
1293 i = 0;
1294 while (i < 100)
1295 {
1296 gtk_tree_store_prepend (store, &iter, root);
1297 ++i;
1298 }
1299
1300 /* remove everything again */
1301 while (gtk_tree_model_iter_children (model, &iter, root))
1302 gtk_tree_store_remove (store, &iter);
1303
1304 gtk_tree_store_append (store, &iter, root);
1305 gtk_tree_store_append (store, &iter, root);
1306 gtk_tree_store_append (store, &iter, root);
1307 gtk_tree_store_append (store, &iter, root);
1308
1309 while (gtk_tree_model_iter_children (model, &iter, root))
1310 {
1311 treestore_torture_recurse (store, &iter, depth);
1312 gtk_tree_store_remove (store, &iter);
1313 }
1314 }
1315
1316 #endif
1317
1318 static void
run_automated_tests(void)1319 run_automated_tests (void)
1320 {
1321 g_print ("Running automated tests...\n");
1322
1323 /* FIXME TreePath basic verification */
1324
1325 /* FIXME generic consistency checks on the models */
1326
1327 {
1328 /* Make sure list store mutations don't crash anything */
1329 GtkListStore *store;
1330 GtkTreeModel *model;
1331 gint i;
1332 GtkTreeIter iter;
1333
1334 store = gtk_list_store_new (1, G_TYPE_INT);
1335
1336 model = GTK_TREE_MODEL (store);
1337
1338 i = 0;
1339 while (i < 100)
1340 {
1341 gtk_list_store_append (store, &iter);
1342 ++i;
1343 }
1344
1345 while (gtk_tree_model_get_iter_first (model, &iter))
1346 gtk_list_store_remove (store, &iter);
1347
1348 gtk_list_store_append (store, &iter);
1349
1350 /* inserts before last node in list */
1351 i = 0;
1352 while (i < 100)
1353 {
1354 gtk_list_store_insert_before (store, &iter, &iter);
1355 ++i;
1356 }
1357
1358 /* inserts after the node before the last node */
1359 i = 0;
1360 while (i < 100)
1361 {
1362 gtk_list_store_insert_after (store, &iter, &iter);
1363 ++i;
1364 }
1365
1366 /* inserts after the last node */
1367 gtk_list_store_append (store, &iter);
1368
1369 i = 0;
1370 while (i < 100)
1371 {
1372 gtk_list_store_insert_after (store, &iter, &iter);
1373 ++i;
1374 }
1375
1376 /* remove everything again */
1377 while (gtk_tree_model_get_iter_first (model, &iter))
1378 gtk_list_store_remove (store, &iter);
1379
1380
1381 /* Prepends */
1382 gtk_list_store_prepend (store, &iter);
1383
1384 i = 0;
1385 while (i < 100)
1386 {
1387 gtk_list_store_prepend (store, &iter);
1388 ++i;
1389 }
1390
1391 /* remove everything again */
1392 while (gtk_tree_model_get_iter_first (model, &iter))
1393 gtk_list_store_remove (store, &iter);
1394
1395 g_object_unref (store);
1396 }
1397
1398 {
1399 /* Make sure tree store mutations don't crash anything */
1400 GtkTreeStore *store;
1401 GtkTreeIter root;
1402
1403 store = gtk_tree_store_new (1, G_TYPE_INT);
1404 gtk_tree_store_append (GTK_TREE_STORE (store), &root, NULL);
1405 /* Remove test until it is rewritten to work */
1406 /* treestore_torture_recurse (store, &root, 0);*/
1407
1408 g_object_unref (store);
1409 }
1410
1411 g_print ("Passed.\n");
1412 }
1413