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