Added display sort feature to PsppireDictView
[pspp] / src / ui / gui / dialog-common.c
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 *
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
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) 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
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) 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
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
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