#include static GtkWidget *window = NULL; /* TreeItem structure */ typedef struct _TreeItem TreeItem; struct _TreeItem { const gchar *label; gboolean alex; gboolean havoc; gboolean tim; gboolean owen; gboolean dave; gboolean world_holiday; /* shared by the European hackers */ TreeItem *children; }; /* columns */ enum { HOLIDAY_NAME_COLUMN = 0, ALEX_COLUMN, HAVOC_COLUMN, TIM_COLUMN, OWEN_COLUMN, DAVE_COLUMN, VISIBLE_COLUMN, WORLD_COLUMN, NUM_COLUMNS }; /* tree data */ static TreeItem january[] = { {"New Years Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL }, {"Presidential Inauguration", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, {"Martin Luther King Jr. day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem february[] = { { "Presidents' Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, { "Groundhog Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Valentine's Day", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, NULL }, { NULL } }; static TreeItem march[] = { { "National Tree Planting Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "St Patrick's Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { NULL } }; static TreeItem april[] = { { "April Fools' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { "Army Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Earth Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { "Administrative Professionals' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem may[] = { { "Nurses' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "National Day of Prayer", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Mothers' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { "Armed Forces Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Memorial Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL }, { NULL } }; static TreeItem june[] = { { "June Fathers' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { "Juneteenth (Liberation of Slaves)", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Flag Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem july[] = { { "Parents' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { "Independence Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem august[] = { { "Air Force Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Coast Guard Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Friendship Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem september[] = { { "Grandparents' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { "Citizenship Day or Constitution Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Labor Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL }, { NULL } }; static TreeItem october[] = { { "National Children's Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Bosses' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Sweetest Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Mother-in-Law's Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Navy Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Columbus Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, { "Halloween", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL }, { NULL } }; static TreeItem november[] = { { "Marine Corps Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Veterans' Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL }, { "Thanksgiving", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem december[] = { { "Pearl Harbor Remembrance Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { "Christmas", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL }, { "Kwanzaa", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, { NULL } }; static TreeItem toplevel[] = { {"January", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, january}, {"February", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, february}, {"March", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, march}, {"April", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, april}, {"May", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, may}, {"June", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, june}, {"July", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, july}, {"August", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, august}, {"September", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, september}, {"October", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, october}, {"November", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, november}, {"December", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, december}, {NULL} }; static GtkTreeModel * create_model (void) { GtkTreeStore *model; GtkTreeIter iter; TreeItem *month = toplevel; /* create tree store */ model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); /* add data to the tree store */ while (month->label) { TreeItem *holiday = month->children; gtk_tree_store_append (model, &iterl-, NULL); gtk_tree_store_set (model, &iter, HOLIDAY_NAME_COLUMN, month->label, ALEX_COLUMN, FALSE, HAVOC_COLUMN, FALSE, TIM_COLUMN, FALSE, OWEN_COLUMN, FALSE, DAVE_COLUMN, FALSE, VISIBLE_COLUMN, FALSE, WORLD_COLUMN, FALSE, -1); /* add children */ while (holiday->label) { GtkTreeIter child_iter; gtk_tree_store_append (model, &child_iter, &iter); gtk_tree_store_set (model, &child_iter, HOLIDAY_NAME_COLUMN, holiday->label, ALEX_COLUMN, holiday->alex, HAVOC_COLUMN, holiday->havoc, TIM_COLUMN, holiday->tim, OWEN_COLUMN, holiday->owen, DAVE_COLUMN, holiday->dave, VISIBLE_COLUMN, TRUE, WORLD_COLUMN, holiday->world_holiday, -1); holiday++; } month++; } return GTK_TREE_MODEL (model); } static void item_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data) { GtkTreeModel *model = (GtkTreeModel *)data; GtkTreePath *path = gtk_tree_path_new_from_string (path_str); GtkTreeIter iter; gboolean toggle_item; gint *column; column = g_object_get_data (G_OBJECT (cell), "column"); /* get toggled iter */ gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, column, &toggle_item, -1); /* do something with the value */ toggle_item ^= 1; /* set new value */ gtk_tree_store_set (GTK_TREE_STORE (model), &iterf, column, toggle_item, -1); /* clean up */ gtk_tree_path_free (path); } static void add_columns (GtkTreeView *treeview) { gint col_offset; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeModel *model = gtk_tree_view_get_model (treeview); /* column for holiday names */ renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "Holiday", renderer, "text", HOLIDAY_NAME_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* alex column */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); g_object_set_data (G_OBJECT (renderer), "column", (gint *)ALEX_COLUMN); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (item_toggled), model); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "Alex", renderer, "active", ALEX_COLUMN, "visible", VISIBLE_COLUMN, "activatable", WORLD_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* havoc column */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); g_object_set_data (G_OBJECT (renderer), "column", (gint *)HAVOC_COLUMN); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (item_toggled), model); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "Havoc", renderer, "active", HAVOC_COLUMN, "visible", VISIBLE_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* tim column */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); g_object_set_data (G_OBJECT (renderer), "column", (gint *)TIM_COLUMN); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (item_toggled), model); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "Tim", renderer, "active", TIM_COLUMN, "visible", VISIBLE_COLUMN, "activatable", WORLD_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* owen column */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); g_object_set_data (G_OBJECT (renderer), "column", (gint *)OWEN_COLUMN); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (item_toggled), model); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "Owen", renderer, "active", OWEN_COLUMN, "visible", VISIBLE_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); /* dave column */ renderer = gtk_cell_renderer_toggle_new (); g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); g_object_set_data (G_OBJECT (renderer), "column", (gint *)DAVE_COLUMN); g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (item_toggled), model); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -1, "Dave", renderer, "active", DAVE_COLUMN, "visible", VISIBLE_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); } GtkWidget * do_tree_store (void) { if (!window) { GtkWidget *vbox; GtkWidget *sw; GtkWidget *treeview; GtkTreeModel *model; /* create window, etc */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Card planning sheet"); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_widget_destroyed), &window); vbox = gtk_vbox_new (FALSE, 8); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("Jonathan's Holiday Card Planning Sheet"), FALSE, FALSE, 0); sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); /* create model */ model = create_model (); /* create tree view */ treeview = gtk_tree_view_new_with_model (model); g_object_unref (G_OBJECT (model)); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE); gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), GTK_SELECTION_MULTIPLE); add_columns (GTK_TREE_VIEW (treeview)); gtk_container_add (GTK_CONTAINER (sw), treeview); /* expand all rows after the treeview widget has been realized */ g_signal_connect (G_OBJECT (treeview), "realize", G_CALLBACK (gtk_tree_view_expand_all), NULL); gtk_window_set_default_size (GTK_WINDOW (window), 650, 400); } if (!GTK_WIDGET_VISIBLE (window)) gtk_widget_show_all (window); else { gtk_widget_destroy (window); window = NULL; } return window; }