Warnings: missing initializer for value_tables and function type cast (GObject)
[pspp] / src / ui / gui / psppire-var-view.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2009, 2010, 2011  Free Software Foundation
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 <gtk/gtk.h>
20 #include "psppire-var-view.h"
21 #include "psppire-var-ptr.h"
22 #include "psppire-select-dest.h"
23
24 #include <libpspp/cast.h>
25 #include <libpspp/str.h>
26 #include <data/variable.h>
27
28 #include <gettext.h>
29 #define _(msgid) gettext (msgid)
30 #define N_(msgid) msgid
31
32 static void psppire_var_view_base_finalize (PsppireVarViewClass *, gpointer);
33 static void psppire_var_view_base_init     (PsppireVarViewClass *class);
34 static void psppire_var_view_class_init    (PsppireVarViewClass *class);
35 static void psppire_var_view_init          (PsppireVarView      *var_view);
36
37 /* Returns TRUE iff VV contains the item V.
38    V must be an initialised value containing a
39    PSPPIRE_VAR_PTR_TYPE.
40 */
41 static gboolean
42 var_view_contains_var (PsppireSelectDestWidget *sdm, const GValue *v)
43 {
44   gboolean ok;
45   GtkTreeIter iter;
46   PsppireVarView *vv = PSPPIRE_VAR_VIEW (sdm);
47   g_return_val_if_fail (G_VALUE_HOLDS (v, PSPPIRE_VAR_PTR_TYPE), FALSE);
48
49   for (ok = psppire_var_view_get_iter_first (vv, &iter);
50        ok;
51        ok = psppire_var_view_get_iter_next (vv, &iter))
52     {
53       const struct variable *var = psppire_var_view_get_variable (vv, 0, &iter);
54       if (var == g_value_get_boxed (v))
55         return TRUE;
56     }
57
58   return FALSE;
59 }
60
61 static void
62 model_init (PsppireSelectDestWidgetIface *iface)
63 {
64   iface->contains_var = var_view_contains_var;
65 }
66
67 GType
68 psppire_var_view_get_type (void)
69 {
70   static GType psppire_var_view_type = 0;
71
72   if (!psppire_var_view_type)
73     {
74       static const GTypeInfo psppire_var_view_info =
75       {
76         sizeof (PsppireVarViewClass),
77         (GBaseInitFunc) (void (*)(void)) psppire_var_view_base_init,
78         (GBaseFinalizeFunc) (void (*)(void)) psppire_var_view_base_finalize,
79         (GClassInitFunc) (void (*)(void)) psppire_var_view_class_init,
80         (GClassFinalizeFunc) NULL,
81         NULL,
82         sizeof (PsppireVarView),
83         0,
84         (GInstanceInitFunc) (void (*)(void)) psppire_var_view_init,
85         NULL /* value_table */
86       };
87
88       static const GInterfaceInfo var_view_model_info = {
89         (GInterfaceInitFunc) (void (*)(void)) model_init, /* Fill this in */
90         NULL,
91         NULL
92       };
93
94       psppire_var_view_type =
95         g_type_register_static (GTK_TYPE_TREE_VIEW, "PsppireVarView",
96                                 &psppire_var_view_info, 0);
97
98       g_type_add_interface_static (psppire_var_view_type,
99                                    PSPPIRE_TYPE_SELECT_DEST_WIDGET,
100                                    &var_view_model_info);
101     }
102
103   return psppire_var_view_type;
104 }
105
106 void
107 psppire_var_view_clear (PsppireVarView *vv)
108 {
109   GtkListStore *l = gtk_list_store_newv  (vv->n_cols, vv->cols);
110
111   gtk_tree_view_set_model (GTK_TREE_VIEW (vv), GTK_TREE_MODEL (l));
112 }
113
114
115 static void
116 psppire_var_view_finalize (GObject *object)
117 {
118   PsppireVarView *var_view = PSPPIRE_VAR_VIEW (object);
119   g_free (var_view->nums);
120   g_free (var_view->cols);
121 }
122
123
124
125 /* Properties */
126 enum
127 {
128   PROP_0,
129   PROP_N_COLS
130 };
131
132 /* A (*GtkTreeCellDataFunc) function.
133    This function expects TREEMODEL to hold PSPPIRE_VAR_PTR_TYPE.
134    It renders the name of the variable into CELL.
135 */
136 static void
137 display_cell_var_name (GtkTreeViewColumn *tree_column,
138                        GtkCellRenderer *cell,
139                        GtkTreeModel *treemodel,
140                        GtkTreeIter *iter,
141                        gpointer data)
142 {
143   struct variable *var;
144   GValue value = {0};
145   gint *col = data;
146
147   GtkTreePath *path = gtk_tree_model_get_path (treemodel, iter);
148
149   gtk_tree_model_get_value (treemodel, iter, *col, &value);
150
151   gtk_tree_path_free (path);
152
153   var = g_value_get_boxed (&value);
154
155   g_value_unset (&value);
156
157   g_object_set (cell, "text", var ? var_get_name (var) : "", NULL);
158 }
159
160
161 static void
162 psppire_var_view_get_property (GObject         *object,
163                                guint            prop_id,
164                                GValue          *value,
165                                GParamSpec      *pspec)
166 {
167   PsppireVarView *var_view = PSPPIRE_VAR_VIEW (object);
168
169   switch (prop_id)
170     {
171     case PROP_N_COLS:
172       g_value_set_int (value,  var_view->n_cols);
173       break;
174     default:
175       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176       break;
177     };
178 }
179
180 static void
181 set_renderers (PsppireVarView *var_view)
182 {
183   gint c;
184   var_view->nums = g_malloc (sizeof *var_view->nums * var_view->n_cols);
185
186   for (c = 0 ; c < var_view->n_cols; ++c)
187     {
188       GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
189       GtkTreeViewColumn *col = gtk_tree_view_column_new ();
190
191       gchar *label = g_strdup_printf (_("Var%d"), c + 1);
192
193       gtk_tree_view_column_set_min_width (col, 100);
194       gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
195       gtk_tree_view_column_set_resizable (col, TRUE);
196       gtk_tree_view_column_set_title (col, label);
197
198       g_free (label);
199
200       var_view->nums[c] = c;
201
202       gtk_tree_view_column_pack_start (col, renderer, TRUE);
203       gtk_tree_view_column_set_cell_data_func (col, renderer,
204                                                display_cell_var_name,
205                                                &var_view->nums[c], 0);
206
207       gtk_tree_view_append_column (GTK_TREE_VIEW (var_view), col);
208     }
209 }
210
211
212 GtkTreeModel *
213 psppire_var_view_get_current_model (PsppireVarView *vv)
214 {
215   return gtk_tree_view_get_model (GTK_TREE_VIEW (vv));
216 }
217
218 static void
219 psppire_var_view_set_property (GObject         *object,
220                                guint            prop_id,
221                                const GValue    *value,
222                                GParamSpec      *pspec)
223 {
224   PsppireVarView *var_view = PSPPIRE_VAR_VIEW (object);
225
226   switch (prop_id)
227     {
228     case PROP_N_COLS:
229       {
230         gint c;
231         var_view->n_cols = g_value_get_int (value);
232
233         var_view->cols = g_realloc (var_view->cols, sizeof (GType) *  var_view->n_cols);
234
235         for (c = 0 ; c < var_view->n_cols; ++c)
236           var_view->cols[c] = PSPPIRE_VAR_PTR_TYPE;
237
238         set_renderers (var_view);
239
240         psppire_var_view_clear (var_view);
241       }
242       break;
243     default:
244       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245       break;
246     };
247 }
248
249 static void
250 psppire_var_view_class_init (PsppireVarViewClass *class)
251 {
252   GObjectClass *object_class = G_OBJECT_CLASS (class);
253
254   GParamSpec *n_cols_spec =
255     g_param_spec_int ("n-cols",
256                       "Number of columns",
257                       "The Number of Columns in the Variable View",
258                       1, 20,
259                       1,
260                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE | G_PARAM_WRITABLE);
261
262
263   object_class->set_property = psppire_var_view_set_property;
264   object_class->get_property = psppire_var_view_get_property;
265
266   g_object_class_install_property (object_class,
267                                    PROP_N_COLS,
268                                    n_cols_spec);
269 }
270
271
272 static void
273 psppire_var_view_base_init (PsppireVarViewClass *class)
274 {
275
276   GObjectClass *object_class = G_OBJECT_CLASS (class);
277
278   object_class->finalize = psppire_var_view_finalize;
279 }
280
281
282
283 static void
284 psppire_var_view_base_finalize (PsppireVarViewClass *class,
285                                  gpointer class_data)
286 {
287 }
288
289
290
291 static void
292 psppire_var_view_init (PsppireVarView *vv)
293 {
294   GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (vv));
295   vv->cols = 0;
296
297   gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
298 }
299
300
301 GtkWidget*
302 psppire_var_view_new (void)
303 {
304   return GTK_WIDGET (g_object_new (psppire_var_view_get_type (), NULL));
305 }
306
307
308 gboolean
309 psppire_var_view_get_iter_first (PsppireVarView *vv, GtkTreeIter *iter)
310 {
311   GtkTreeIter dummy;
312   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (vv));
313   return gtk_tree_model_get_iter_first (model, iter ? iter : &dummy);
314 }
315
316 gboolean
317 psppire_var_view_get_iter_next (PsppireVarView *vv, GtkTreeIter *iter)
318 {
319   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (vv));
320   return gtk_tree_model_iter_next (model, iter);
321 }
322
323 const struct variable *
324 psppire_var_view_get_var_from_model (GtkTreeModel *model, gint column, GtkTreeIter *iter)
325 {
326   const struct variable *var = NULL;
327   GValue value = {0};
328   gtk_tree_model_get_value (model, iter, column, &value);
329
330   if (G_VALUE_TYPE (&value) == PSPPIRE_VAR_PTR_TYPE)
331     var = g_value_get_boxed (&value);
332   else
333     g_critical ("Unsupported type `%s', in variable name treeview.",
334                 G_VALUE_TYPE_NAME (&value));
335
336   g_value_unset (&value);
337
338   return var;
339 }
340
341 const struct variable *
342 psppire_var_view_get_variable (PsppireVarView *vv, gint column, GtkTreeIter *iter)
343 {
344   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (vv));
345   return psppire_var_view_get_var_from_model (model, column, iter);
346 }
347
348
349
350 /*
351   Append the names of selected variables to STRING.
352   Returns the number of variables appended.
353 */
354 gint
355 psppire_var_view_append_names (PsppireVarView *vv, gint column, GString *string)
356 {
357   gint n_vars = 0;
358   GtkTreeIter iter;
359
360   if (psppire_var_view_get_iter_first (vv, &iter))
361     {
362       do
363         {
364           const struct variable *var = psppire_var_view_get_variable (vv, column, &iter);
365           g_string_append (string, " ");
366           g_string_append (string, var_get_name (var));
367
368           n_vars++;
369         }
370       while (psppire_var_view_get_iter_next (vv, &iter));
371     }
372
373   return n_vars;
374 }
375
376 /* Return a linked list of struct variables which are
377    contained in VV.
378    The caller is responsible for freeing the returned list.
379    The variables however are owned by their dictionary
380    and should not be freed.
381   */
382 GSList *
383 psppire_var_view_list_names (PsppireVarView *vv, gint column)
384 {
385   GtkTreeIter iter;
386   GSList *list = NULL;
387
388   if (psppire_var_view_get_iter_first (vv, &iter))
389     {
390       do
391         {
392           const struct variable *var = psppire_var_view_get_variable (vv, column, &iter);
393           list = g_slist_prepend (list, CONST_CAST (struct variable *, var));
394         }
395       while (psppire_var_view_get_iter_next (vv, &iter));
396     }
397
398   return list;
399 }
400
401
402 /*
403   Append the names of selected variables to STR
404   Returns the number of variables appended.
405 */
406 gint
407 psppire_var_view_append_names_str (PsppireVarView *vv, gint column, struct string *str)
408 {
409   gint n_vars = 0;
410   GtkTreeIter iter;
411
412   if (psppire_var_view_get_iter_first (vv, &iter))
413     {
414       do
415         {
416           const struct variable *var = psppire_var_view_get_variable (vv, column, &iter);
417           ds_put_cstr (str, " ");
418           ds_put_cstr (str, var_get_name (var));
419
420           n_vars++;
421         }
422       while (psppire_var_view_get_iter_next (vv, &iter));
423     }
424
425   return n_vars;
426 }
427
428
429