gui: New type PsppireEmptyListStore.
[pspp] / src / ui / gui / psppire-empty-list-store.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "psppire-empty-list-store.h"
20
21 static void psppire_empty_list_store_class_init (PsppireEmptyListStoreClass *);
22 static void psppire_empty_list_store_init (PsppireEmptyListStore *);
23
24 /* GtkTreeModel interface. */
25 static void gtk_tree_model_interface_init (GtkTreeModelIface *iface);
26 static GtkTreeModelFlags empty_list_store_get_flags (GtkTreeModel *tree_model);
27 static gint empty_list_store_get_n_columns (GtkTreeModel *tree_model);
28 static GType empty_list_store_get_column_type (GtkTreeModel *tree_model,
29                                                gint          index_);
30 static gboolean empty_list_store_get_iter (GtkTreeModel *tree_model,
31                                            GtkTreeIter  *iter,
32                                            GtkTreePath  *path);
33 static GtkTreePath * empty_list_store_get_path (GtkTreeModel *tree_model,
34                                                 GtkTreeIter  *iter);
35 static void empty_list_store_get_value (GtkTreeModel *tree_model,
36                                         GtkTreeIter  *iter,
37                                         gint          column,
38                                         GValue       *value);
39 static gboolean empty_list_store_iter_next (GtkTreeModel *tree_model,
40                                             GtkTreeIter  *iter);
41 static gboolean empty_list_store_iter_children (GtkTreeModel *tree_model,
42                                                 GtkTreeIter  *iter,
43                                                 GtkTreeIter  *parent);
44 static gboolean empty_list_store_iter_has_child (GtkTreeModel *tree_model,
45                                                  GtkTreeIter  *iter);
46 static gint empty_list_store_iter_n_children (GtkTreeModel *tree_model,
47                                               GtkTreeIter  *iter);
48 static gboolean empty_list_store_iter_nth_child (GtkTreeModel *tree_model,
49                                                  GtkTreeIter  *iter,
50                                                  GtkTreeIter  *parent,
51                                                  gint          n);
52 static gboolean empty_list_store_iter_parent (GtkTreeModel *tree_model,
53                                               GtkTreeIter  *iter,
54                                               GtkTreeIter  *child);
55
56 GType
57 psppire_empty_list_store_get_type (void)
58 {
59   static GType type = 0;
60   if (!type)
61     {
62       static const GTypeInfo psppire_empty_list_store_info =
63         {
64           sizeof(PsppireEmptyListStoreClass),
65           NULL,    /* base init */
66           NULL,    /* base finalize */
67           (GClassInitFunc) psppire_empty_list_store_class_init,
68           NULL,    /* class finalize */
69           NULL,    /* class data */
70           sizeof(PsppireEmptyListStore),
71           0,    /* n_preallocs, ignored since 2.10 */
72           (GInstanceInitFunc) psppire_empty_list_store_init,
73           NULL
74         };
75       static const GInterfaceInfo gtk_tree_model_info =
76         {
77           (GInterfaceInitFunc) gtk_tree_model_interface_init,
78           (GInterfaceFinalizeFunc) NULL,
79           NULL
80         };
81       type = g_type_register_static (G_TYPE_OBJECT,
82                                  "PsppireEmptyListStore",
83                                  &psppire_empty_list_store_info, 0);
84       g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL,
85                                    &gtk_tree_model_info);
86     }
87   return type;
88 }
89
90 enum
91   {
92     PROP_0,
93     PROP_N_ROWS
94   };
95
96 static void
97 psppire_empty_list_store_set_property (GObject      *object,
98                                        guint         prop_id,
99                                        const GValue *value,
100                                        GParamSpec   *pspec)
101 {
102   PsppireEmptyListStore *obj = PSPPIRE_EMPTY_LIST_STORE (object);
103
104   switch (prop_id)
105     {
106     case PROP_N_ROWS:
107       obj->n_rows = g_value_get_int (value);
108       break;
109
110     default:
111       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112       break;
113     }
114 }
115
116 static void
117 psppire_empty_list_store_get_property (GObject      *object,
118                                        guint         prop_id,
119                                        GValue       *value,
120                                        GParamSpec   *pspec)
121 {
122   PsppireEmptyListStore *obj = PSPPIRE_EMPTY_LIST_STORE (object);
123
124   switch (prop_id)
125     {
126     case PROP_N_ROWS:
127       g_value_set_int (value, obj->n_rows);
128       break;
129
130     default:
131       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
132       break;
133     }
134 }
135
136 static void
137 psppire_empty_list_store_class_init (PsppireEmptyListStoreClass *class)
138 {
139   GObjectClass *gobject_class;
140   gobject_class = G_OBJECT_CLASS (class);
141
142   gobject_class->set_property = psppire_empty_list_store_set_property;
143   gobject_class->get_property = psppire_empty_list_store_get_property;
144
145   g_object_class_install_property (gobject_class,
146                                    PROP_N_ROWS,
147                                    g_param_spec_int ("n-rows",
148                                                      ("Number of rows"),
149                                                      ("Number of rows in GtkTreeModel"),
150                                                      0,
151                                                      G_MAXINT,
152                                                      0,
153                                                      G_PARAM_READWRITE));
154 }
155
156 static void
157 psppire_empty_list_store_init (PsppireEmptyListStore *obj)
158 {
159   obj->n_rows = 0;
160 }
161
162 PsppireEmptyListStore *
163 psppire_empty_list_store_new (gint n_rows)
164 {
165   return PSPPIRE_EMPTY_LIST_STORE (g_object_new (PSPPIRE_TYPE_EMPTY_LIST_STORE,
166                                                  "n-rows", n_rows,
167                                                  NULL));
168 }
169
170 gint
171 psppire_empty_list_store_get_n_rows (const PsppireEmptyListStore *obj)
172 {
173   return obj->n_rows;
174 }
175
176 void
177 psppire_empty_list_store_set_n_rows (PsppireEmptyListStore *obj,
178                                      gint n_rows)
179 {
180   obj->n_rows = n_rows;
181 }
182
183 void
184 psppire_empty_list_store_row_inserted (PsppireEmptyListStore *obj,
185                                        gint row)
186 {
187   GtkTreeModel *tree_model = GTK_TREE_MODEL (obj);
188   GtkTreeIter iter;
189   GtkTreePath *path;
190
191   path = gtk_tree_path_new_from_indices (row, -1);
192   gtk_tree_model_get_iter (tree_model, &iter, path);
193   gtk_tree_model_row_inserted (tree_model, path, &iter);
194   gtk_tree_path_free (path);
195 }
196
197 void
198 psppire_empty_list_store_row_deleted (PsppireEmptyListStore *obj,
199                                       gint row)
200 {
201   GtkTreeModel *tree_model = GTK_TREE_MODEL (obj);
202   GtkTreePath *path;
203
204   path = gtk_tree_path_new_from_indices (row, -1);
205   gtk_tree_model_row_deleted (tree_model, path);
206   gtk_tree_path_free (path);
207 }
208 \f
209 /* GtkTreeModel interface. */
210
211 /* Random number used in 'stamp' member of GtkTreeIter. */
212 #define TREE_MODEL_STAMP 0x10c44c13
213
214 static gboolean
215 empty_list_store_init_iter (GtkTreeModel *model, gint idx, GtkTreeIter *iter)
216 {
217   const PsppireEmptyListStore *store = PSPPIRE_EMPTY_LIST_STORE (model);
218
219   if (idx < 0 || idx >= store->n_rows)
220     {
221       iter->stamp = 0;
222       iter->user_data = GINT_TO_POINTER (-1);
223       return FALSE;
224     }
225   else
226     {
227       iter->stamp = TREE_MODEL_STAMP;
228       iter->user_data = GINT_TO_POINTER (idx);
229       return TRUE;
230     }
231 }
232
233 static void
234 gtk_tree_model_interface_init (GtkTreeModelIface *iface)
235 {
236   g_return_if_fail (iface != NULL);
237
238   iface->get_flags = empty_list_store_get_flags;
239   iface->get_n_columns = empty_list_store_get_n_columns;
240   iface->get_column_type = empty_list_store_get_column_type;
241   iface->get_iter = empty_list_store_get_iter;
242   iface->get_path = empty_list_store_get_path;
243   iface->get_value = empty_list_store_get_value;
244   iface->iter_next = empty_list_store_iter_next;
245   iface->iter_children = empty_list_store_iter_children;
246   iface->iter_has_child = empty_list_store_iter_has_child;
247   iface->iter_n_children = empty_list_store_iter_n_children;
248   iface->iter_nth_child = empty_list_store_iter_nth_child;
249   iface->iter_parent = empty_list_store_iter_parent;
250 }
251
252 static GtkTreeModelFlags
253 empty_list_store_get_flags (GtkTreeModel *tree_model G_GNUC_UNUSED)
254 {
255   return GTK_TREE_MODEL_LIST_ONLY;
256 }
257
258 static gint
259 empty_list_store_get_n_columns (GtkTreeModel *tree_model G_GNUC_UNUSED)
260 {
261   return 0;
262 }
263
264 static GType
265 empty_list_store_get_column_type (GtkTreeModel *tree_model,
266                                   gint          index_)
267 {
268   g_return_val_if_reached (G_TYPE_NONE);
269 }
270
271 static gboolean
272 empty_list_store_get_iter (GtkTreeModel *tree_model,
273                            GtkTreeIter  *iter,
274                            GtkTreePath  *path)
275 {
276   gint *indices, depth;
277
278   g_return_val_if_fail (path, FALSE);
279
280   indices = gtk_tree_path_get_indices (path);
281   depth = gtk_tree_path_get_depth (path);
282
283   g_return_val_if_fail (depth == 1, FALSE);
284
285   return empty_list_store_init_iter (tree_model, indices[0], iter);
286 }
287
288 static GtkTreePath *
289 empty_list_store_get_path (GtkTreeModel *tree_model,
290                            GtkTreeIter  *iter)
291 {
292   GtkTreePath *path;
293
294   g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE);
295
296   path = gtk_tree_path_new ();
297   gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data));
298
299   return path;
300 }
301
302 static void
303 empty_list_store_get_value (GtkTreeModel *tree_model,
304                             GtkTreeIter  *iter,
305                             gint          column,
306                             GValue       *value)
307 {
308   g_return_if_reached ();
309 }
310
311 static gboolean
312 empty_list_store_iter_next (GtkTreeModel *tree_model,
313                             GtkTreeIter  *iter)
314 {
315   gint idx;
316
317   g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE);
318
319   idx = GPOINTER_TO_INT (iter->user_data);
320   return empty_list_store_init_iter (tree_model, idx + (idx >= 0), iter);
321 }
322
323 static gboolean
324 empty_list_store_iter_children (GtkTreeModel *tree_model,
325                                 GtkTreeIter  *iter,
326                                 GtkTreeIter  *parent)
327 {
328   return FALSE;
329 }
330
331 static gboolean
332 empty_list_store_iter_has_child (GtkTreeModel *tree_model,
333                                  GtkTreeIter  *iter)
334 {
335   return FALSE;
336 }
337
338 static gint
339 empty_list_store_iter_n_children (GtkTreeModel *tree_model,
340                                   GtkTreeIter  *iter)
341 {
342   return iter == NULL ? PSPPIRE_EMPTY_LIST_STORE (tree_model)->n_rows : 0;
343 }
344
345 static gboolean
346 empty_list_store_iter_nth_child (GtkTreeModel *tree_model,
347                                  GtkTreeIter  *iter,
348                                  GtkTreeIter  *parent,
349                                  gint          n)
350 {
351   g_return_val_if_fail (parent == NULL, FALSE);
352
353   return empty_list_store_init_iter (tree_model, n, iter);
354 }
355
356 static gboolean
357 empty_list_store_iter_parent (GtkTreeModel *tree_model,
358                               GtkTreeIter  *iter,
359                               GtkTreeIter  *child)
360 {
361   return FALSE;
362 }
363
364 gint
365 empty_list_store_iter_to_row (const GtkTreeIter *iter)
366 {
367   g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, 0);
368   return GPOINTER_TO_INT (iter->user_data);
369 }