Fixed bug inserting cases in data sheet.
[pspp] / src / ui / gui / dialog-common.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007  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 <libpspp/i18n.h>
20 #include "dialog-common.h"
21
22 #include "psppire-var-ptr.h"
23
24 #include "helper.h"
25
26
27 /* Append the names of selected variables to STRING.
28    TREEVIEW is the treeview containing the variables.
29    COLUMN is the column in the treeview containing the variables.
30    DICT is the dictionary for those variables.
31 */
32 gint
33 append_variable_names (GString *string,
34                        PsppireDict *dict, GtkTreeView *treeview, gint column)
35 {
36   gint n_vars = 0;
37   GtkTreeIter iter;
38
39   GtkTreeModel *list_store =
40     gtk_tree_view_get_model (treeview);
41
42   if ( gtk_tree_model_get_iter_first (list_store, &iter) )
43     {
44       do
45         {
46           GValue value = {0};
47           struct variable *var = NULL;
48           GtkTreePath *path = gtk_tree_model_get_path (list_store, &iter);
49
50           gtk_tree_model_get_value (list_store, &iter, column, &value);
51
52           /* FIXME:  G_TYPE_INT should be deprecated.
53              As well as being simpler, it'd be unecessary to pass dict */
54           if ( G_VALUE_TYPE (&value) == G_TYPE_INT )
55           var = psppire_dict_get_variable (dict, g_value_get_int (&value));
56
57           else if ( G_VALUE_TYPE (&value) == PSPPIRE_VAR_PTR_TYPE)
58             var = g_value_get_boxed (&value);
59
60           else
61             g_critical ("Unsupported type \"%s\", in variable name treeview.",
62                         G_VALUE_TYPE_NAME (&value));
63
64           g_value_unset (&value);
65
66           g_string_append (string, " ");
67           g_string_append (string, var_get_name (var));
68
69           gtk_tree_path_free (path);
70           n_vars++;
71         }
72       while (gtk_tree_model_iter_next (list_store, &iter));
73     }
74
75   return n_vars;
76 }
77
78
79
80 struct variable *
81 get_selected_variable (GtkTreeModel *treemodel,
82                        GtkTreeIter *iter,
83                        PsppireDict *dict)
84 {
85   struct variable *var;
86   GValue value = {0};
87
88   GtkTreePath *path = gtk_tree_model_get_path (treemodel, iter);
89
90   gtk_tree_model_get_value (treemodel, iter, 0, &value);
91
92   gtk_tree_path_free (path);
93
94   var =  psppire_dict_get_variable (dict, g_value_get_int (&value));
95
96   g_value_unset (&value);
97
98   return var;
99 }
100
101
102
103
104 /* A (*GtkTreeCellDataFunc) function.
105    This function expects TREEMODEL to hold G_TYPE_INT.  The ints it holds
106    are the indices of the variables in the dictionary, which DATA points to.
107    It renders the name of the variable into CELL.
108 */
109 void
110 cell_var_name (GtkTreeViewColumn *tree_column,
111                GtkCellRenderer *cell,
112                GtkTreeModel *tree_model,
113                GtkTreeIter *iter,
114                gpointer data)
115 {
116   PsppireDict *dict = data;
117   struct variable *var;
118   gchar *name;
119
120   var = get_selected_variable (tree_model, iter, dict);
121
122   name = recode_string (UTF8, psppire_dict_encoding (dict),
123                         var_get_name (var), -1);
124   g_object_set (cell, "text", name, NULL);
125   g_free (name);
126 }
127
128
129
130 /* Set a model for DEST, which is an GtkListStore of g_int's
131    whose values are the indices into DICT */
132 void
133 set_dest_model (GtkTreeView *dest, PsppireDict *dict)
134 {
135   GtkTreeViewColumn *col;
136   GtkListStore *dest_list = gtk_list_store_new (1, G_TYPE_INT);
137   GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
138
139   gtk_tree_view_set_model (GTK_TREE_VIEW (dest), GTK_TREE_MODEL (dest_list));
140
141   col = gtk_tree_view_column_new_with_attributes ("Var",
142                                                   renderer,
143                                                   "text",
144                                                   0,
145                                                   NULL);
146
147   gtk_tree_view_column_set_cell_data_func (col, renderer,
148                                            cell_var_name,
149                                            dict, 0);
150
151   /* FIXME: make this a value in terms of character widths */
152   g_object_set (col, "min-width",  100, NULL);
153
154   gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
155
156   gtk_tree_view_append_column (GTK_TREE_VIEW (dest), col);
157 }
158
159
160
161 /* Returns FALSE if the variables represented by the union of the rows
162    currently selected by SOURCE widget, and contents of the DEST
163    widget, are of different types.
164
165    In other words, this function when passed as the argument to
166    psppire_selector_set_allow, ensures that the selector selects only
167    string  variables, or only numeric variables, not a mixture.
168 */
169 gboolean
170 homogeneous_types (GtkWidget *source, GtkWidget *dest)
171 {
172   gboolean ok;
173   GtkTreeIter iter;
174   gboolean retval = TRUE;
175
176   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (source));
177
178   PsppireDict *dict;
179   GtkTreeSelection *selection;
180   enum val_type type = -1;
181   GList *list, *l;
182
183   while (GTK_IS_TREE_MODEL_FILTER (model))
184     {
185       model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
186     }
187
188   dict = PSPPIRE_DICT (model);
189
190   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source));
191
192   list = gtk_tree_selection_get_selected_rows (selection, &model);
193
194   /* Iterate through the selection of the source treeview */
195   for (l = list; l ; l = l->next)
196     {
197       GtkTreePath *path = l->data;
198
199       GtkTreePath *fpath =
200         gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), path);
201
202       gint *idx = gtk_tree_path_get_indices (fpath);
203
204       const struct variable *v = psppire_dict_get_variable (dict, idx[0]);
205
206       gtk_tree_path_free (fpath);
207
208       if ( type != -1 )
209         {
210           if ( var_get_type (v) != type )
211             {
212               retval = FALSE;
213               break;
214             }
215         }
216
217       type = var_get_type (v);
218     }
219
220   g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
221   g_list_free (list);
222
223   if ( retval == FALSE )
224     return FALSE;
225
226   /* now deal with the dest widget */
227   model = gtk_tree_view_get_model (GTK_TREE_VIEW (dest));
228
229   for (ok = gtk_tree_model_get_iter_first (model, &iter);
230        ok;
231        ok = gtk_tree_model_iter_next (model, &iter))
232     {
233       gint idx;
234       const struct variable *v;
235       gtk_tree_model_get (model, &iter, 0, &idx, -1);
236
237       v = psppire_dict_get_variable (dict, idx);
238
239       if ( type != -1 )
240         {
241           if ( var_get_type (v) != type )
242             {
243               retval = FALSE;
244               break;
245             }
246         }
247
248       type = var_get_type (v);
249     }
250
251
252   return retval;
253 }
254
255
256
257 /* Returns true iff the variable selected by SOURCE is numeric */
258 gboolean
259 numeric_only (GtkWidget *source, GtkWidget *dest)
260 {
261   gboolean retval = TRUE;
262
263   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (source));
264
265   PsppireDict *dict;
266   GtkTreeSelection *selection;
267   GList *list, *l;
268
269   while (GTK_IS_TREE_MODEL_FILTER (model))
270     {
271       model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
272     }
273
274   dict = PSPPIRE_DICT (model);
275
276   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source));
277
278   list = gtk_tree_selection_get_selected_rows (selection, &model);
279
280   /* Iterate through the selection of the source treeview */
281   for (l = list; l ; l = l->next)
282     {
283       GtkTreePath *path = l->data;
284       GtkTreePath *fpath = gtk_tree_model_filter_convert_path_to_child_path
285         (GTK_TREE_MODEL_FILTER (model), path);
286
287       gint *idx = gtk_tree_path_get_indices (fpath);
288
289       const struct variable *v = psppire_dict_get_variable (dict, idx[0]);
290
291       gtk_tree_path_free (fpath);
292
293       if ( var_is_alpha (v))
294         {
295           retval = FALSE;
296           break;
297         }
298     }
299
300   g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
301   g_list_free (list);
302
303   return retval;
304 }
305