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