1#include <gtk/gtk.h>
2
3enum
4{
5 PROP_LABEL = 1,
6 PROP_ID,
7 LAST_PROPERTY
8};
9
10static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
11
12typedef struct
13{
14 GObject parent;
15
16 char *label;
17 int id;
18} MyObject;
19
20typedef struct
21{
22 GObjectClass parent_class;
23} MyObjectClass;
24
25static GType my_object_get_type (void);
26G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT)
27
28static void
29my_object_init (MyObject *obj)
30{
31}
32
33static void
34my_object_get_property (GObject *object,
35 guint property_id,
36 GValue *value,
37 GParamSpec *pspec)
38{
39 MyObject *obj = (MyObject *)object;
40
41 switch (property_id)
42 {
43 case PROP_LABEL:
44 g_value_set_string (value, v_string: obj->label);
45 break;
46 case PROP_ID:
47 g_value_set_int (value, v_int: obj->id);
48 break;
49 default:
50 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
51 break;
52 }
53}
54
55static void
56my_object_set_property (GObject *object,
57 guint property_id,
58 const GValue *value,
59 GParamSpec *pspec)
60{
61 MyObject *obj = (MyObject *)object;
62
63 switch (property_id)
64 {
65 case PROP_LABEL:
66 g_free (mem: obj->label);
67 obj->label = g_value_dup_string (value);
68 break;
69 case PROP_ID:
70 obj->id = g_value_get_int (value);
71 break;
72 default:
73 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
74 break;
75 }
76}
77
78static void
79my_object_finalize (GObject *obj)
80{
81 MyObject *object = (MyObject *)obj;
82
83 g_free (mem: object->label);
84
85 G_OBJECT_CLASS (my_object_parent_class)->finalize (obj);
86}
87
88static void
89my_object_class_init (MyObjectClass *class)
90{
91 GObjectClass *object_class = G_OBJECT_CLASS (class);
92
93 object_class->get_property = my_object_get_property;
94 object_class->set_property = my_object_set_property;
95 object_class->finalize = my_object_finalize;
96
97 properties[PROP_LABEL] = g_param_spec_string (name: "label", nick: "label", blurb: "label",
98 NULL, flags: G_PARAM_READWRITE);
99 properties[PROP_ID] = g_param_spec_int (name: "id", nick: "id", blurb: "id",
100 minimum: 0, G_MAXINT, default_value: 0, flags: G_PARAM_READWRITE);
101
102 g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROPERTY, pspecs: properties);
103}
104
105static GtkWidget *
106create_widget (gpointer item,
107 gpointer user_data)
108{
109 MyObject *obj = (MyObject *)item;
110 GtkWidget *label;
111
112 label = gtk_label_new (str: "");
113 g_object_bind_property (source: obj, source_property: "label", target: label, target_property: "label", flags: G_BINDING_SYNC_CREATE);
114
115 return label;
116}
117
118static int
119compare_items (gconstpointer a, gconstpointer b, gpointer data)
120{
121 int id_a, id_b;
122
123 g_object_get (object: (gpointer)a, first_property_name: "id", &id_a, NULL);
124 g_object_get (object: (gpointer)b, first_property_name: "id", &id_b, NULL);
125
126 return id_a - id_b;
127}
128
129static void
130add_some (GtkButton *button, GListStore *store)
131{
132 int n, i;
133 guint n_items;
134 GObject *obj;
135 char *label;
136
137 for (n = 0; n < 50; n++)
138 {
139 n_items = g_list_model_get_n_items (list: G_LIST_MODEL (ptr: store));
140 i = g_random_int_range (begin: 0, MAX (2 * n_items, 1));
141 label = g_strdup_printf (format: "Added %d", i);
142 obj = g_object_new (object_type: my_object_get_type (),
143 first_property_name: "id", i,
144 "label", label,
145 NULL);
146 g_list_store_insert_sorted (store, item: obj, compare_func: compare_items, NULL);
147 g_object_unref (object: obj);
148 g_free (mem: label);
149 }
150}
151
152static void
153remove_some (GtkButton *button, GListStore *store)
154{
155 int n, i;
156 guint n_items;
157
158 for (n = 0; n < 50; n++)
159 {
160 n_items = g_list_model_get_n_items (list: G_LIST_MODEL (ptr: store));
161 if (n_items == 0)
162 return;
163 i = g_random_int_range (begin: 0, end: n_items);
164 g_list_store_remove (store, position: i);
165 }
166}
167
168int
169main (int argc, char *argv[])
170{
171 GtkWidget *window, *grid, *sw, *box, *button;
172 GListStore *store;
173 int i;
174
175 gtk_init ();
176
177 store = g_list_store_new (item_type: my_object_get_type ());
178 for (i = 0; i < 100; i++)
179 {
180 MyObject *obj;
181 char *label;
182
183 label = g_strdup_printf (format: "item %d", i);
184 obj = g_object_new (object_type: my_object_get_type (),
185 first_property_name: "id", i,
186 "label", label,
187 NULL);
188 g_list_store_append (store, item: obj);
189 g_free (mem: label);
190 g_object_unref (object: obj);
191 }
192
193 window = gtk_window_new ();
194 grid = gtk_grid_new ();
195 gtk_window_set_child (GTK_WINDOW (window), child: grid);
196 sw = gtk_scrolled_window_new ();
197 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
198 hscrollbar_policy: GTK_POLICY_AUTOMATIC,
199 vscrollbar_policy: GTK_POLICY_AUTOMATIC);
200 gtk_widget_set_hexpand (widget: sw, TRUE);
201 gtk_widget_set_vexpand (widget: sw, TRUE);
202 gtk_grid_attach (GTK_GRID (grid), child: sw, column: 0, row: 0, width: 1, height: 1);
203
204 box = gtk_list_box_new ();
205 gtk_list_box_bind_model (GTK_LIST_BOX (box), model: G_LIST_MODEL (ptr: store), create_widget_func: create_widget, NULL, NULL);
206 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: box);
207
208 sw = gtk_scrolled_window_new ();
209 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
210 hscrollbar_policy: GTK_POLICY_AUTOMATIC,
211 vscrollbar_policy: GTK_POLICY_AUTOMATIC);
212 gtk_widget_set_hexpand (widget: sw, TRUE);
213 gtk_widget_set_vexpand (widget: sw, TRUE);
214 gtk_grid_attach (GTK_GRID (grid), child: sw, column: 1, row: 0, width: 1, height: 1);
215
216 box = gtk_flow_box_new ();
217 gtk_flow_box_bind_model (GTK_FLOW_BOX (box), model: G_LIST_MODEL (ptr: store), create_widget_func: create_widget, NULL, NULL);
218 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: box);
219
220 button = gtk_button_new_with_label (label: "Add some");
221 g_signal_connect (button, "clicked", G_CALLBACK (add_some), store);
222 gtk_grid_attach (GTK_GRID (grid), child: button, column: 0, row: 1, width: 1, height: 1);
223
224 button = gtk_button_new_with_label (label: "Remove some");
225 g_signal_connect (button, "clicked", G_CALLBACK (remove_some), store);
226 gtk_grid_attach (GTK_GRID (grid), child: button, column: 0, row: 2, width: 1, height: 1);
227
228 gtk_widget_show (widget: window);
229
230 while (TRUE)
231 g_main_context_iteration (NULL, TRUE);
232
233 return 0;
234}
235

source code of gtk/tests/listmodel.c