1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2014  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 #include "dict-display.h"
22 
23 #include "psppire-var-ptr.h"
24 
25 #include "helper.h"
26 
27 /*
28    If m is not a base TreeModel type (ie, is a filter or sorter) then
29    convert OP to a TreePath for the base and return it.
30    The return value must be freed by the caller.
31 */
32 static GtkTreePath *
get_base_tree_path(GtkTreeModel * m,GtkTreePath * op)33 get_base_tree_path (GtkTreeModel *m, GtkTreePath *op)
34 {
35   GtkTreePath *p = gtk_tree_path_copy (op);
36   while (! PSPPIRE_IS_DICT (m))
37     {
38       GtkTreePath *oldp = p;
39 
40       if (GTK_IS_TREE_MODEL_FILTER (m))
41 	{
42 	  p = gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (m), oldp);
43 	  m = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (m));
44 	}
45       else if (GTK_IS_TREE_MODEL_SORT (m))
46 	{
47 	  p = gtk_tree_model_sort_convert_path_to_child_path (GTK_TREE_MODEL_SORT (m), oldp);
48 	  m = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (m));
49 	}
50       else
51 	{
52 	  g_error ("Unexpected model type: %s", G_OBJECT_TYPE_NAME (m));
53 	}
54 
55       gtk_tree_path_free (oldp);
56     }
57 
58   return p;
59 }
60 
61 
62 /* Returns FALSE if the variables represented by the union of the rows
63    currently selected by SOURCE widget, and contents of the DEST
64    widget, are of different types.
65 
66    In other words, this function when passed as the argument to
67    psppire_selector_set_allow, ensures that the selector selects only
68    string  variables, or only numeric variables, not a mixture.
69 */
70 gboolean
homogeneous_types(GtkWidget * source,GtkWidget * dest)71 homogeneous_types (GtkWidget *source, GtkWidget *dest)
72 {
73   gboolean ok;
74   GtkTreeIter iter;
75   gboolean retval = TRUE;
76 
77   GtkTreeModel *top_model = gtk_tree_view_get_model (GTK_TREE_VIEW (source));
78   GtkTreeModel *model;
79 
80   PsppireDict *dict;
81   GtkTreeSelection *selection;
82   enum val_type type;
83   GList *list, *l;
84   bool have_type;
85 
86 
87   get_base_model (top_model, NULL, &model, NULL);
88 
89   dict = PSPPIRE_DICT (model);
90 
91   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source));
92 
93   list = gtk_tree_selection_get_selected_rows (selection, &model);
94 
95   /* Iterate through the selection of the source treeview */
96   have_type = false;
97   for (l = list; l ; l = l->next)
98     {
99       GtkTreePath *p = get_base_tree_path (top_model, l->data);
100       gint *idx = gtk_tree_path_get_indices (p);
101       const struct variable *v = psppire_dict_get_variable (dict, idx[0]);
102 
103       gtk_tree_path_free (p);
104 
105       if (have_type && var_get_type (v) != type)
106         {
107           retval = FALSE;
108           break;
109         }
110 
111       type = var_get_type (v);
112       have_type = true;
113     }
114 
115   g_list_foreach (list, GFUNC_COMPAT_CAST (gtk_tree_path_free), NULL);
116   g_list_free (list);
117 
118   if (retval == FALSE)
119     return FALSE;
120 
121   /* now deal with the dest widget */
122   model = gtk_tree_view_get_model (GTK_TREE_VIEW (dest));
123 
124   for (ok = gtk_tree_model_get_iter_first (model, &iter);
125        ok;
126        ok = gtk_tree_model_iter_next (model, &iter))
127     {
128       const struct variable *v;
129       gtk_tree_model_get (model, &iter, 0, &v, -1);
130 
131       if (have_type && var_get_type (v) != type)
132         {
133           retval = FALSE;
134           break;
135         }
136 
137       type = var_get_type (v);
138       have_type = true;
139     }
140 
141   return retval;
142 }
143 
144 
145 
146 /* Returns true iff the variable selected by SOURCE is numeric */
147 gboolean
numeric_only(GtkWidget * source,GtkWidget * dest)148 numeric_only (GtkWidget *source, GtkWidget *dest)
149 {
150   gboolean retval = TRUE;
151 
152   GtkTreeModel *top_model = gtk_tree_view_get_model (GTK_TREE_VIEW (source));
153   GtkTreeModel *model = NULL;
154 
155   PsppireDict *dict;
156   GtkTreeSelection *selection;
157   GList *list, *l;
158 
159   get_base_model (top_model, NULL, &model, NULL);
160 
161   dict = PSPPIRE_DICT (model);
162 
163   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (source));
164 
165   list = gtk_tree_selection_get_selected_rows (selection, &top_model);
166 
167   /* Iterate through the selection of the source treeview */
168   for (l = list; l ; l = l->next)
169     {
170       GtkTreePath *p = get_base_tree_path (top_model, l->data);
171       gint *idx = gtk_tree_path_get_indices (p);
172       const struct variable *v = psppire_dict_get_variable (dict, idx[0]);
173       gtk_tree_path_free (p);
174 
175       if (var_is_alpha (v))
176 	{
177 	  retval = FALSE;
178 	  break;
179 	}
180     }
181 
182   g_list_foreach (list, GFUNC_COMPAT_CAST (gtk_tree_path_free), NULL);
183   g_list_free (list);
184 
185   return retval;
186 }
187 
188 /*
189   A pair of functions intended to be used as callbacks for the "toggled" signal
190   of a GtkToggleButton widget.  They make the sensitivity of W follow the status
191   of the togglebutton.
192 */
193 void
set_sensitivity_from_toggle(GtkToggleButton * togglebutton,GtkWidget * w)194 set_sensitivity_from_toggle (GtkToggleButton *togglebutton,  GtkWidget *w)
195 {
196   gboolean active = gtk_toggle_button_get_active (togglebutton);
197 
198   gtk_widget_set_sensitive (w, active);
199   if (active)
200     gtk_widget_grab_focus (w);
201 }
202 
203 /* */
204 void
set_sensitivity_from_toggle_invert(GtkToggleButton * togglebutton,GtkWidget * w)205 set_sensitivity_from_toggle_invert (GtkToggleButton *togglebutton,
206 				    GtkWidget *w)
207 {
208   gboolean active = gtk_toggle_button_get_active (togglebutton);
209 
210   gtk_widget_set_sensitive (w, !active);
211 }
212 
213 
214 
215