Allow ranges with left to right and bottom to top sense to be selected.
[pspp-builds.git] / 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   const struct variable *var = get_selected_variable (tree_model, iter, dict);
118
119   g_object_set (cell, "text", var_get_name (var), NULL);
120 }
121
122
123
124 /* Set a model for DEST, which is an GtkListStore of g_int's
125    whose values are the indices into DICT */
126 void
127 set_dest_model (GtkTreeView *dest, PsppireDict *dict)
128 {
129   GtkTreeViewColumn *col;
130   GtkListStore *dest_list = gtk_list_store_new (1, G_TYPE_INT);
131   GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
132
133   gtk_tree_view_set_model (GTK_TREE_VIEW (dest), GTK_TREE_MODEL (dest_list));
134
135   col = gtk_tree_view_column_new_with_attributes ("Var",
136                                                   renderer,
137                                                   "text",
138                                                   0,
139                                                   NULL);
140
141   gtk_tree_view_column_set_cell_data_func (col, renderer,
142                                            cell_var_name,
143                                            dict, 0);
144
145   /* FIXME: make this a value in terms of character widths */
146   g_object_set (col, "min-width",  100, NULL);
147
148   gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
149
150   gtk_tree_view_append_column (GTK_TREE_VIEW (dest), col);
151 }
152
153
154
155 /* Returns FALSE if the variables represented by the union of the rows
156    currently selected by SOURCE widget, and contents of the DEST
157    widget, are of different types.
158
159    In other words, this function when passed as the argument to
160    psppire_selector_set_allow, ensures that the selector selects only
161    string  variables, or only numeric variables, not a mixture.
162 */
163 gboolean
164 homogeneous_types (GtkWidget *source, GtkWidget *dest)
165 {
166   gboolean ok;
167   GtkTreeIter iter;
168   gboolean retval = TRUE;
169
170   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (source));
171
172   PsppireDict *dict;
173   GtkTreeSelection *selection;
174   enum val_type type = -1;
175   GList *list, *l;
176
177   while (GTK_IS_TREE_MODEL_FILTER (model))
178     {
179       model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
180     }
181
182   dict = PSPPIRE_DICT (model);
183
184   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source));
185
186   list = gtk_tree_selection_get_selected_rows (selection, &model);
187
188   /* Iterate through the selection of the source treeview */
189   for (l = list; l ; l = l->next)
190     {
191       GtkTreePath *path = l->data;
192
193       GtkTreePath *fpath =
194         gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model), path);
195
196       gint *idx = gtk_tree_path_get_indices (fpath);
197
198       const struct variable *v = psppire_dict_get_variable (dict, idx[0]);
199
200       gtk_tree_path_free (fpath);
201
202       if ( type != -1 )
203         {
204           if ( var_get_type (v) != type )
205             {
206               retval = FALSE;
207               break;
208             }
209         }
210
211       type = var_get_type (v);
212     }
213
214   g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
215   g_list_free (list);
216
217   if ( retval == FALSE )
218     return FALSE;
219
220   /* now deal with the dest widget */
221   model = gtk_tree_view_get_model (GTK_TREE_VIEW (dest));
222
223   for (ok = gtk_tree_model_get_iter_first (model, &iter);
224        ok;
225        ok = gtk_tree_model_iter_next (model, &iter))
226     {
227       gint idx;
228       const struct variable *v;
229       gtk_tree_model_get (model, &iter, 0, &idx, -1);
230
231       v = psppire_dict_get_variable (dict, idx);
232
233       if ( type != -1 )
234         {
235           if ( var_get_type (v) != type )
236             {
237               retval = FALSE;
238               break;
239             }
240         }
241
242       type = var_get_type (v);
243     }
244
245
246   return retval;
247 }
248
249
250
251 /* Returns true iff the variable selected by SOURCE is numeric */
252 gboolean
253 numeric_only (GtkWidget *source, GtkWidget *dest)
254 {
255   gboolean retval = TRUE;
256
257   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (source));
258
259   PsppireDict *dict;
260   GtkTreeSelection *selection;
261   GList *list, *l;
262
263   while (GTK_IS_TREE_MODEL_FILTER (model))
264     {
265       model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
266     }
267
268   dict = PSPPIRE_DICT (model);
269
270   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source));
271
272   list = gtk_tree_selection_get_selected_rows (selection, &model);
273
274   /* Iterate through the selection of the source treeview */
275   for (l = list; l ; l = l->next)
276     {
277       GtkTreePath *path = l->data;
278       GtkTreePath *fpath = gtk_tree_model_filter_convert_path_to_child_path
279         (GTK_TREE_MODEL_FILTER (model), path);
280
281       gint *idx = gtk_tree_path_get_indices (fpath);
282
283       const struct variable *v = psppire_dict_get_variable (dict, idx[0]);
284
285       gtk_tree_path_free (fpath);
286
287       if ( var_is_alpha (v))
288         {
289           retval = FALSE;
290           break;
291         }
292     }
293
294   g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
295   g_list_free (list);
296
297   return retval;
298 }
299