]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/tree_store.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / demos / gtk-demo / tree_store.c
1 /* Tree View/Tree Store
2  *
3  * The GtkTreeStore is used to store data in tree form, to be
4  * used later on by a GtkTreeView to display it. This demo builds
5  * a simple GtkTreeStore and displays it. If you're new to the
6  * GtkTreeView widgets and associates, look into the GtkListStore
7  * example first.
8  *
9  */
10
11 #include <config.h>
12 #include <gtk/gtk.h>
13
14 static GtkWidget *window = NULL;
15
16 /* TreeItem structure */
17 typedef struct _TreeItem TreeItem;
18 struct _TreeItem
19 {
20   const gchar    *label;
21   gboolean        alex;
22   gboolean        havoc;
23   gboolean        tim;
24   gboolean        owen;
25   gboolean        dave;
26   gboolean        world_holiday; /* shared by the European hackers */
27   TreeItem       *children;
28 };
29
30 /* columns */
31 enum
32 {
33   HOLIDAY_NAME_COLUMN = 0,
34   ALEX_COLUMN,
35   HAVOC_COLUMN,
36   TIM_COLUMN,
37   OWEN_COLUMN,
38   DAVE_COLUMN,
39
40   VISIBLE_COLUMN,
41   WORLD_COLUMN,
42   NUM_COLUMNS
43 };
44
45 /* tree data */
46 static TreeItem january[] =
47 {
48   {"New Years Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
49   {"Presidential Inauguration", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
50   {"Martin Luther King Jr. day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
51   { NULL }
52 };
53
54 static TreeItem february[] =
55 {
56   { "Presidents' Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
57   { "Groundhog Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
58   { "Valentine's Day", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, NULL },
59   { NULL }
60 };
61
62 static TreeItem march[] =
63 {
64   { "National Tree Planting Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
65   { "St Patrick's Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
66   { NULL }
67 };
68 static TreeItem april[] =
69 {
70   { "April Fools' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
71   { "Army Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
72   { "Earth Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
73   { "Administrative Professionals' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
74   { NULL }
75 };
76
77 static TreeItem may[] =
78 {
79   { "Nurses' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
80   { "National Day of Prayer", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
81   { "Mothers' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
82   { "Armed Forces Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
83   { "Memorial Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
84   { NULL }
85 };
86
87 static TreeItem june[] =
88 {
89   { "June Fathers' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
90   { "Juneteenth (Liberation of Slaves)", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
91   { "Flag Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
92   { NULL }
93 };
94
95 static TreeItem july[] =
96 {
97   { "Parents' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
98   { "Independence Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
99   { NULL }
100 };
101
102 static TreeItem august[] =
103 {
104   { "Air Force Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
105   { "Coast Guard Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
106   { "Friendship Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
107   { NULL }
108 };
109
110 static TreeItem september[] =
111 {
112   { "Grandparents' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
113   { "Citizenship Day or Constitution Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
114   { "Labor Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
115   { NULL }
116 };
117
118 static TreeItem october[] =
119 {
120   { "National Children's Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
121   { "Bosses' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
122   { "Sweetest Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
123   { "Mother-in-Law's Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
124   { "Navy Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
125   { "Columbus Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
126   { "Halloween", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
127   { NULL }
128 };
129
130 static TreeItem november[] =
131 {
132   { "Marine Corps Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
133   { "Veterans' Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
134   { "Thanksgiving", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
135   { NULL }
136 };
137
138 static TreeItem december[] =
139 {
140   { "Pearl Harbor Remembrance Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
141   { "Christmas", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
142   { "Kwanzaa", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
143   { NULL }
144 };
145
146
147 static TreeItem toplevel[] =
148 {
149   {"January", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, january},
150   {"February", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, february},
151   {"March", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, march},
152   {"April", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, april},
153   {"May", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, may},
154   {"June", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, june},
155   {"July", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, july},
156   {"August", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, august},
157   {"September", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, september},
158   {"October", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, october},
159   {"November", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, november},
160   {"December", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, december},
161   {NULL}
162 };
163
164
165 static GtkTreeModel *
166 create_model (void)
167 {
168   GtkTreeStore *model;
169   GtkTreeIter iter;
170   TreeItem *month = toplevel;
171
172   /* create tree store */
173   model = gtk_tree_store_new (NUM_COLUMNS,
174                               G_TYPE_STRING,
175                               G_TYPE_BOOLEAN,
176                               G_TYPE_BOOLEAN,
177                               G_TYPE_BOOLEAN,
178                               G_TYPE_BOOLEAN,
179                               G_TYPE_BOOLEAN,
180                               G_TYPE_BOOLEAN,
181                               G_TYPE_BOOLEAN);
182
183   /* add data to the tree store */
184   while (month->label)
185     {
186       TreeItem *holiday = month->children;
187
188       gtk_tree_store_append (model, &iter, NULL);
189       gtk_tree_store_set (model, &iter,
190                           HOLIDAY_NAME_COLUMN, month->label,
191                           ALEX_COLUMN, FALSE,
192                           HAVOC_COLUMN, FALSE,
193                           TIM_COLUMN, FALSE,
194                           OWEN_COLUMN, FALSE,
195                           DAVE_COLUMN, FALSE,
196                           VISIBLE_COLUMN, FALSE,
197                           WORLD_COLUMN, FALSE,
198                           -1);
199
200       /* add children */
201       while (holiday->label)
202         {
203           GtkTreeIter child_iter;
204
205           gtk_tree_store_append (model, &child_iter, &iter);
206           gtk_tree_store_set (model, &child_iter,
207                               HOLIDAY_NAME_COLUMN, holiday->label,
208                               ALEX_COLUMN, holiday->alex,
209                               HAVOC_COLUMN, holiday->havoc,
210                               TIM_COLUMN, holiday->tim,
211                               OWEN_COLUMN, holiday->owen,
212                               DAVE_COLUMN, holiday->dave,
213                               VISIBLE_COLUMN, TRUE,
214                               WORLD_COLUMN, holiday->world_holiday,
215                               -1);
216
217           holiday++;
218         }
219
220       month++;
221     }
222
223   return GTK_TREE_MODEL (model);
224 }
225
226 static void
227 item_toggled (GtkCellRendererToggle *cell,
228               gchar                 *path_str,
229               gpointer               data)
230 {
231   GtkTreeModel *model = (GtkTreeModel *)data;
232   GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
233   GtkTreeIter iter;
234   gboolean toggle_item;
235
236   gint *column;
237
238   column = g_object_get_data (G_OBJECT (cell), "column");
239
240   /* get toggled iter */
241   gtk_tree_model_get_iter (model, &iter, path);
242   gtk_tree_model_get (model, &iter, column, &toggle_item, -1);
243
244   /* do something with the value */
245   toggle_item ^= 1;
246
247   /* set new value */
248   gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column,
249                       toggle_item, -1);
250
251   /* clean up */
252   gtk_tree_path_free (path);
253 }
254
255 static void
256 add_columns (GtkTreeView *treeview)
257 {
258   gint col_offset;
259   GtkCellRenderer *renderer;
260   GtkTreeViewColumn *column;
261   GtkTreeModel *model = gtk_tree_view_get_model (treeview);
262
263   /* column for holiday names */
264   renderer = gtk_cell_renderer_text_new ();
265   g_object_set (renderer, "xalign", 0.0, NULL);
266
267   col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
268                                                             -1, "Holiday",
269                                                             renderer, "text",
270                                                             HOLIDAY_NAME_COLUMN,
271                                                             NULL);
272   column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
273   gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
274
275   /* alex column */
276   renderer = gtk_cell_renderer_toggle_new ();
277   g_object_set (renderer, "xalign", 0.0, NULL);
278   g_object_set_data (G_OBJECT (renderer), "column", (gint *)ALEX_COLUMN);
279
280   g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
281
282   col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
283                                                             -1, "Alex",
284                                                             renderer,
285                                                             "active",
286                                                             ALEX_COLUMN,
287                                                             "visible",
288                                                             VISIBLE_COLUMN,
289                                                             "activatable",
290                                                             WORLD_COLUMN, NULL);
291
292   column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
293   gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
294                                    GTK_TREE_VIEW_COLUMN_FIXED);
295   gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
296   gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
297
298   /* havoc column */
299   renderer = gtk_cell_renderer_toggle_new ();
300   g_object_set (renderer, "xalign", 0.0, NULL);
301   g_object_set_data (G_OBJECT (renderer), "column", (gint *)HAVOC_COLUMN);
302
303   g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
304
305   col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
306                                                             -1, "Havoc",
307                                                             renderer,
308                                                             "active",
309                                                             HAVOC_COLUMN,
310                                                             "visible",
311                                                             VISIBLE_COLUMN,
312                                                             NULL);
313
314   column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
315   gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
316                                    GTK_TREE_VIEW_COLUMN_FIXED);
317   gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
318   gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
319
320   /* tim column */
321   renderer = gtk_cell_renderer_toggle_new ();
322   g_object_set (renderer, "xalign", 0.0, NULL);
323   g_object_set_data (G_OBJECT (renderer), "column", (gint *)TIM_COLUMN);
324
325   g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
326
327   col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
328                                                             -1, "Tim",
329                                                             renderer,
330                                                             "active",
331                                                             TIM_COLUMN,
332                                                             "visible",
333                                                             VISIBLE_COLUMN,
334                                                             "activatable",
335                                                             WORLD_COLUMN, NULL);
336
337   column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
338   gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
339                                    GTK_TREE_VIEW_COLUMN_FIXED);
340   gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
341   gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
342
343   /* owen column */
344   renderer = gtk_cell_renderer_toggle_new ();
345   g_object_set (renderer, "xalign", 0.0, NULL);
346   g_object_set_data (G_OBJECT (renderer), "column", (gint *)OWEN_COLUMN);
347
348   g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
349
350   col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
351                                                             -1, "Owen",
352                                                             renderer,
353                                                             "active",
354                                                             OWEN_COLUMN,
355                                                             "visible",
356                                                             VISIBLE_COLUMN,
357                                                             NULL);
358
359   column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
360   gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
361                                    GTK_TREE_VIEW_COLUMN_FIXED);
362   gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
363   gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
364
365   /* dave column */
366   renderer = gtk_cell_renderer_toggle_new ();
367   g_object_set (renderer, "xalign", 0.0, NULL);
368   g_object_set_data (G_OBJECT (renderer), "column", (gint *)DAVE_COLUMN);
369
370   g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
371
372   col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
373                                                             -1, "Dave",
374                                                             renderer,
375                                                             "active",
376                                                             DAVE_COLUMN,
377                                                             "visible",
378                                                             VISIBLE_COLUMN,
379                                                             NULL);
380
381   column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
382   gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
383                                    GTK_TREE_VIEW_COLUMN_FIXED);
384   gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
385   gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
386 }
387
388 GtkWidget *
389 do_tree_store (GtkWidget *do_widget)
390 {
391   if (!window)
392     {
393       GtkWidget *vbox;
394       GtkWidget *sw;
395       GtkWidget *treeview;
396       GtkTreeModel *model;
397
398       /* create window, etc */
399       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
400       gtk_window_set_screen (GTK_WINDOW (window),
401                              gtk_widget_get_screen (do_widget));
402       gtk_window_set_title (GTK_WINDOW (window), "Card planning sheet");
403       g_signal_connect (window, "destroy",
404                         G_CALLBACK (gtk_widget_destroyed), &window);
405
406       vbox = gtk_vbox_new (FALSE, 8);
407       gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
408       gtk_container_add (GTK_CONTAINER (window), vbox);
409
410       gtk_box_pack_start (GTK_BOX (vbox),
411                           gtk_label_new ("Jonathan's Holiday Card Planning Sheet"),
412                           FALSE, FALSE, 0);
413
414       sw = gtk_scrolled_window_new (NULL, NULL);
415       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
416                                            GTK_SHADOW_ETCHED_IN);
417       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
418                                       GTK_POLICY_AUTOMATIC,
419                                       GTK_POLICY_AUTOMATIC);
420       gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
421
422       /* create model */
423       model = create_model ();
424
425       /* create tree view */
426       treeview = gtk_tree_view_new_with_model (model);
427       g_object_unref (model);
428       gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
429       gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
430                                    GTK_SELECTION_MULTIPLE);
431
432       add_columns (GTK_TREE_VIEW (treeview));
433
434       gtk_container_add (GTK_CONTAINER (sw), treeview);
435
436       /* expand all rows after the treeview widget has been realized */
437       g_signal_connect (treeview, "realize",
438                         G_CALLBACK (gtk_tree_view_expand_all), NULL);
439       gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
440     }
441
442   if (!GTK_WIDGET_VISIBLE (window))
443     gtk_widget_show_all (window);
444   else
445     {
446       gtk_widget_destroy (window);
447       window = NULL;
448     }
449
450   return window;
451 }