1/* Tree View/List Store
2 *
3 * The GtkListStore is used to store data in list form, to be used
4 * later on by a GtkTreeView to display it. This demo builds a
5 * simple GtkListStore and displays it.
6 */
7
8#include <gtk/gtk.h>
9
10static GtkWidget *window = NULL;
11static GtkTreeModel *model = NULL;
12static guint timeout = 0;
13
14typedef struct
15{
16 const gboolean fixed;
17 const guint number;
18 const char *severity;
19 const char *description;
20} Bug;
21
22enum
23{
24 COLUMN_FIXED,
25 COLUMN_NUMBER,
26 COLUMN_SEVERITY,
27 COLUMN_DESCRIPTION,
28 COLUMN_PULSE,
29 COLUMN_ICON,
30 COLUMN_ACTIVE,
31 COLUMN_SENSITIVE,
32 NUM_COLUMNS
33};
34
35static Bug bugs[] =
36{
37 { FALSE, 60482, "Normal", "scrollable notebooks and hidden tabs" },
38 { FALSE, 60620, "Critical", "gdk_surface_clear_area (gdksurface-win32.c) is not thread-safe" },
39 { FALSE, 50214, "Major", "Xft support does not clean up correctly" },
40 { TRUE, 52877, "Major", "GtkFileSelection needs a refresh method. " },
41 { FALSE, 56070, "Normal", "Can't click button after setting in sensitive" },
42 { TRUE, 56355, "Normal", "GtkLabel - Not all changes propagate correctly" },
43 { FALSE, 50055, "Normal", "Rework width/height computations for TreeView" },
44 { FALSE, 58278, "Normal", "gtk_dialog_set_response_sensitive () doesn't work" },
45 { FALSE, 55767, "Normal", "Getters for all setters" },
46 { FALSE, 56925, "Normal", "Gtkcalender size" },
47 { FALSE, 56221, "Normal", "Selectable label needs right-click copy menu" },
48 { TRUE, 50939, "Normal", "Add shift clicking to GtkTextView" },
49 { FALSE, 6112, "Enhancement","netscape-like collapsible toolbars" },
50 { FALSE, 1, "Normal", "First bug :=)" },
51};
52
53static gboolean
54spinner_timeout (gpointer data)
55{
56 GtkTreeIter iter;
57 guint pulse;
58
59 if (model == NULL)
60 return G_SOURCE_REMOVE;
61
62 gtk_tree_model_get_iter_first (tree_model: model, iter: &iter);
63 gtk_tree_model_get (tree_model: model, iter: &iter,
64 COLUMN_PULSE, &pulse,
65 -1);
66 if (pulse == G_MAXUINT)
67 pulse = 0;
68 else
69 pulse++;
70
71 gtk_list_store_set (GTK_LIST_STORE (model),
72 iter: &iter,
73 COLUMN_PULSE, pulse,
74 COLUMN_ACTIVE, TRUE,
75 -1);
76
77 return G_SOURCE_CONTINUE;
78}
79
80static GtkTreeModel *
81create_model (void)
82{
83 int i = 0;
84 GtkListStore *store;
85 GtkTreeIter iter;
86
87 /* create list store */
88 store = gtk_list_store_new (n_columns: NUM_COLUMNS,
89 G_TYPE_BOOLEAN,
90 G_TYPE_UINT,
91 G_TYPE_STRING,
92 G_TYPE_STRING,
93 G_TYPE_UINT,
94 G_TYPE_STRING,
95 G_TYPE_BOOLEAN,
96 G_TYPE_BOOLEAN);
97
98 /* add data to the list store */
99 for (i = 0; i < G_N_ELEMENTS (bugs); i++)
100 {
101 const char *icon_name;
102 gboolean sensitive;
103
104 if (i == 1 || i == 3)
105 icon_name = "battery-caution-charging-symbolic";
106 else
107 icon_name = NULL;
108 if (i == 3)
109 sensitive = FALSE;
110 else
111 sensitive = TRUE;
112 gtk_list_store_append (list_store: store, iter: &iter);
113 gtk_list_store_set (list_store: store, iter: &iter,
114 COLUMN_FIXED, bugs[i].fixed,
115 COLUMN_NUMBER, bugs[i].number,
116 COLUMN_SEVERITY, bugs[i].severity,
117 COLUMN_DESCRIPTION, bugs[i].description,
118 COLUMN_PULSE, 0,
119 COLUMN_ICON, icon_name,
120 COLUMN_ACTIVE, FALSE,
121 COLUMN_SENSITIVE, sensitive,
122 -1);
123 }
124
125 return GTK_TREE_MODEL (store);
126}
127
128static void
129fixed_toggled (GtkCellRendererToggle *cell,
130 char *path_str,
131 gpointer data)
132{
133 GtkTreeModel *tree_model = (GtkTreeModel *)data;
134 GtkTreeIter iter;
135 GtkTreePath *path = gtk_tree_path_new_from_string (path: path_str);
136 gboolean fixed;
137
138 /* get toggled iter */
139 gtk_tree_model_get_iter (tree_model, iter: &iter, path);
140 gtk_tree_model_get (tree_model, iter: &iter, COLUMN_FIXED, &fixed, -1);
141
142 /* do something with the value */
143 fixed ^= 1;
144
145 /* set new value */
146 gtk_list_store_set (GTK_LIST_STORE (tree_model), iter: &iter, COLUMN_FIXED, fixed, -1);
147
148 /* clean up */
149 gtk_tree_path_free (path);
150}
151
152static void
153add_columns (GtkTreeView *treeview)
154{
155 GtkCellRenderer *renderer;
156 GtkTreeViewColumn *column;
157
158 /* column for fixed toggles */
159 renderer = gtk_cell_renderer_toggle_new ();
160 g_signal_connect (renderer, "toggled",
161 G_CALLBACK (fixed_toggled), model);
162
163 column = gtk_tree_view_column_new_with_attributes (title: "Fixed?",
164 cell: renderer,
165 "active", COLUMN_FIXED,
166 NULL);
167
168 /* set this column to a fixed sizing (of 50 pixels) */
169 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
170 type: GTK_TREE_VIEW_COLUMN_FIXED);
171 gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), fixed_width: 50);
172 gtk_tree_view_append_column (tree_view: treeview, column);
173
174 /* column for bug numbers */
175 renderer = gtk_cell_renderer_text_new ();
176 column = gtk_tree_view_column_new_with_attributes (title: "Bug number",
177 cell: renderer,
178 "text",
179 COLUMN_NUMBER,
180 NULL);
181 gtk_tree_view_column_set_sort_column_id (tree_column: column, sort_column_id: COLUMN_NUMBER);
182 gtk_tree_view_append_column (tree_view: treeview, column);
183
184 /* column for severities */
185 renderer = gtk_cell_renderer_text_new ();
186 column = gtk_tree_view_column_new_with_attributes (title: "Severity",
187 cell: renderer,
188 "text",
189 COLUMN_SEVERITY,
190 NULL);
191 gtk_tree_view_column_set_sort_column_id (tree_column: column, sort_column_id: COLUMN_SEVERITY);
192 gtk_tree_view_append_column (tree_view: treeview, column);
193
194 /* column for description */
195 renderer = gtk_cell_renderer_text_new ();
196 column = gtk_tree_view_column_new_with_attributes (title: "Description",
197 cell: renderer,
198 "text",
199 COLUMN_DESCRIPTION,
200 NULL);
201 gtk_tree_view_column_set_sort_column_id (tree_column: column, sort_column_id: COLUMN_DESCRIPTION);
202 gtk_tree_view_append_column (tree_view: treeview, column);
203
204 /* column for spinner */
205 renderer = gtk_cell_renderer_spinner_new ();
206 column = gtk_tree_view_column_new_with_attributes (title: "Spinning",
207 cell: renderer,
208 "pulse",
209 COLUMN_PULSE,
210 "active",
211 COLUMN_ACTIVE,
212 NULL);
213 gtk_tree_view_column_set_sort_column_id (tree_column: column, sort_column_id: COLUMN_PULSE);
214 gtk_tree_view_append_column (tree_view: treeview, column);
215
216 /* column for symbolic icon */
217 renderer = gtk_cell_renderer_pixbuf_new ();
218 column = gtk_tree_view_column_new_with_attributes (title: "Symbolic icon",
219 cell: renderer,
220 "icon-name",
221 COLUMN_ICON,
222 "sensitive",
223 COLUMN_SENSITIVE,
224 NULL);
225 gtk_tree_view_column_set_sort_column_id (tree_column: column, sort_column_id: COLUMN_ICON);
226 gtk_tree_view_append_column (tree_view: treeview, column);
227}
228
229static gboolean
230window_closed (GtkWidget *widget,
231 GdkEvent *event,
232 gpointer user_data)
233{
234 model = NULL;
235 window = NULL;
236 if (timeout != 0)
237 {
238 g_source_remove (tag: timeout);
239 timeout = 0;
240 }
241 return FALSE;
242}
243
244GtkWidget *
245do_list_store (GtkWidget *do_widget)
246{
247 if (!window)
248 {
249 GtkWidget *vbox;
250 GtkWidget *label;
251 GtkWidget *sw;
252 GtkWidget *treeview;
253
254 /* create window, etc */
255 window = gtk_window_new ();
256 gtk_window_set_display (GTK_WINDOW (window),
257 display: gtk_widget_get_display (widget: do_widget));
258 gtk_window_set_title (GTK_WINDOW (window), title: "List Store");
259 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
260
261 vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 8);
262 gtk_widget_set_margin_start (widget: vbox, margin: 8);
263 gtk_widget_set_margin_end (widget: vbox, margin: 8);
264 gtk_widget_set_margin_top (widget: vbox, margin: 8);
265 gtk_widget_set_margin_bottom (widget: vbox, margin: 8);
266 gtk_window_set_child (GTK_WINDOW (window), child: vbox);
267
268 label = gtk_label_new (str: "This is the bug list (note: not based on real data, it would be nice to have a nice ODBC interface to bugzilla or so, though).");
269 gtk_box_append (GTK_BOX (vbox), child: label);
270
271 sw = gtk_scrolled_window_new ();
272 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
273 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
274 hscrollbar_policy: GTK_POLICY_NEVER,
275 vscrollbar_policy: GTK_POLICY_AUTOMATIC);
276 gtk_box_append (GTK_BOX (vbox), child: sw);
277
278 /* create tree model */
279 model = create_model ();
280
281 /* create tree view */
282 treeview = gtk_tree_view_new_with_model (model);
283 gtk_widget_set_vexpand (widget: treeview, TRUE);
284 gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview),
285 column: COLUMN_DESCRIPTION);
286
287 g_object_unref (object: model);
288
289 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: treeview);
290
291 /* add columns to the tree view */
292 add_columns (GTK_TREE_VIEW (treeview));
293
294 /* finish & show */
295 gtk_window_set_default_size (GTK_WINDOW (window), width: 280, height: 250);
296 g_signal_connect (window, "destroy", G_CALLBACK (window_closed), NULL);
297 }
298
299 if (!gtk_widget_get_visible (widget: window))
300 {
301 gtk_widget_show (widget: window);
302 if (timeout == 0) {
303 /* FIXME this should use the animation-duration instead */
304 timeout = g_timeout_add (interval: 80, function: spinner_timeout, NULL);
305 }
306 }
307 else
308 {
309 gtk_window_destroy (GTK_WINDOW (window));
310 window = NULL;
311 if (timeout != 0)
312 {
313 g_source_remove (tag: timeout);
314 timeout = 0;
315 }
316 }
317
318 return window;
319}
320

source code of gtk/demos/gtk-demo/list_store.c