CORRELATIONS: Fixed bug displaying non-sqaure correlation matrices
[pspp] / src / ui / gui / count-dialog.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2011, 2012  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
18 #include <config.h>
19
20 #include "count-dialog.h"
21
22 #include <gtk/gtk.h>
23 #include "builder-wrapper.h"
24 #include "psppire-dialog.h"
25 #include "psppire-selector.h"
26 #include "psppire-val-chooser.h"
27 #include "psppire-var-view.h"
28 #include "psppire-acr.h"
29 #include "dialog-common.h"
30
31
32 #include <ui/syntax-gen.h>
33 #include "executor.h"
34 #include "helper.h"
35
36 struct cnt_dialog
37 {
38   PsppireDict *dict;
39
40   GtkWidget *dialog;
41
42   GtkListStore *value_list;
43   GtkWidget *chooser;
44
45   GtkWidget *target;
46   GtkWidget *label;
47   GtkWidget *variable_treeview;
48 };
49
50 /* Callback which gets called when a new row is selected
51    in the acr's variable treeview.
52    We use if to set the togglebuttons and entries to correspond to the
53    selected row.
54 */
55 static void
56 on_acr_selection_change (GtkTreeSelection *selection, gpointer data)
57 {
58   GtkTreeIter iter;
59   struct old_value *ov = NULL;
60   GtkTreeModel *model = NULL;
61   struct cnt_dialog *cnt = data;
62   GValue ov_value = {0};
63
64   if ( ! gtk_tree_selection_get_selected (selection, &model, &iter) )
65     return;
66
67   gtk_tree_model_get_value (GTK_TREE_MODEL (model), &iter,
68                             0, &ov_value);
69
70   ov = g_value_get_boxed (&ov_value);
71   psppire_val_chooser_set_status (PSPPIRE_VAL_CHOOSER (cnt->chooser), ov);
72 }
73
74
75
76 static char * generate_syntax (const struct cnt_dialog *cnt);
77
78 static void values_dialog (struct cnt_dialog *cd);
79
80 static void
81 refresh (PsppireDialog *dialog, struct cnt_dialog *cnt)
82 {
83   GtkTreeModel *vars =
84     gtk_tree_view_get_model (GTK_TREE_VIEW (cnt->variable_treeview));
85
86   gtk_list_store_clear (GTK_LIST_STORE (vars));
87
88   gtk_entry_set_text (GTK_ENTRY (cnt->target), "");
89   gtk_entry_set_text (GTK_ENTRY (cnt->label), "");
90   gtk_list_store_clear (GTK_LIST_STORE (cnt->value_list));
91 }
92
93 static gboolean
94 dialog_state_valid (gpointer data)
95 {
96   GtkTreeIter iter;
97   struct cnt_dialog *cnt = data;
98
99   if (! cnt->value_list)
100     return FALSE;
101
102   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cnt->value_list), &iter) )
103     return FALSE;
104
105   if (!gtk_tree_model_get_iter_first (gtk_tree_view_get_model (GTK_TREE_VIEW (cnt->variable_treeview)), &iter))
106     return FALSE;
107
108   if (0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (cnt->target))))
109     return FALSE;
110
111   return TRUE;
112 }
113
114 void count_dialog (PsppireDataWindow *de)
115 {
116   gint response;
117   PsppireVarStore *vs = NULL;
118   struct cnt_dialog cnt;
119
120   GtkBuilder *builder = builder_new ("count.ui");
121
122   GtkWidget *selector = get_widget_assert (builder, "count-selector1");
123
124   GtkWidget *dict_view = get_widget_assert (builder, "dict-view");
125   GtkWidget *button = get_widget_assert (builder, "button1");
126
127   cnt.target = get_widget_assert (builder, "entry1");
128   cnt.label = get_widget_assert (builder, "entry2");
129   cnt.variable_treeview = get_widget_assert (builder, "treeview2");
130
131   g_signal_connect_swapped (button, "clicked", G_CALLBACK (values_dialog), &cnt);
132
133   cnt.value_list = gtk_list_store_new (1,old_value_get_type ());
134
135   cnt.dialog =  get_widget_assert (builder, "count-dialog");
136
137   g_signal_connect (cnt.dialog, "refresh", G_CALLBACK (refresh),  &cnt);
138
139
140   g_object_get (de->data_editor, "var-store", &vs, NULL);
141
142   g_object_get (vs, "dictionary", &cnt.dict, NULL);
143
144   gtk_window_set_transient_for (GTK_WINDOW (cnt.dialog), GTK_WINDOW (de));
145
146   g_object_set (dict_view, "model", cnt.dict, NULL);
147
148   psppire_selector_set_allow (PSPPIRE_SELECTOR (selector),  numeric_only);
149
150   psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (cnt.dialog),
151                                       dialog_state_valid, &cnt);
152
153   response = psppire_dialog_run (PSPPIRE_DIALOG (cnt.dialog));
154
155   switch (response)
156     {
157     case GTK_RESPONSE_OK:
158       g_free (execute_syntax_string (de, generate_syntax (&cnt)));
159       break;
160     case PSPPIRE_RESPONSE_PASTE:
161       g_free (paste_syntax_to_window (generate_syntax (&cnt)));
162       break;
163     default:
164       break;
165     }
166
167
168   g_object_unref (cnt.value_list);
169   g_object_unref (builder);
170 }
171
172 /* A function to set a value in a column in the ACR */
173 static gboolean
174 set_value (gint col, GValue  *val, gpointer data)
175 {
176   struct cnt_dialog *cnt = data;
177   PsppireValChooser *vc = PSPPIRE_VAL_CHOOSER (cnt->chooser);
178   struct old_value ov;
179         
180   g_assert (col == 0);
181
182   psppire_val_chooser_get_status (vc, &ov);
183
184   g_value_init (val, old_value_get_type ());
185   g_value_set_boxed (val, &ov);
186
187   return TRUE;
188 }
189
190
191 static void
192 values_dialog (struct cnt_dialog *cd)
193 {
194   gint response;
195   GtkListStore *local_store = clone_list_store (cd->value_list);
196   GtkBuilder *builder = builder_new ("count.ui");
197
198   GtkWidget *dialog = get_widget_assert (builder, "values-dialog");
199
200   GtkWidget *acr = get_widget_assert (builder, "acr");
201   cd->chooser = get_widget_assert (builder, "value-chooser");
202
203   psppire_acr_set_enabled (PSPPIRE_ACR (acr), TRUE);
204
205   psppire_acr_set_model (PSPPIRE_ACR (acr), local_store);
206   psppire_acr_set_get_value_func (PSPPIRE_ACR (acr), set_value, cd);
207
208   {
209     GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (PSPPIRE_ACR(acr)->tv));
210     g_signal_connect (sel, "changed",
211                     G_CALLBACK (on_acr_selection_change), cd);
212   }
213
214   response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
215
216   if ( response == PSPPIRE_RESPONSE_CONTINUE )
217     {
218       g_object_unref (cd->value_list);
219       cd->value_list = local_store;
220     }
221   else
222     {
223       g_object_unref (local_store);
224     }
225
226   psppire_dialog_notify_change (PSPPIRE_DIALOG (cd->dialog));
227
228   g_object_unref (builder);
229 }
230
231
232
233 static char *
234 generate_syntax (const struct cnt_dialog *cnt)
235 {
236   gchar *text = NULL;
237   const gchar *s = NULL;
238   gboolean ok;
239   GtkTreeIter iter;
240   GString *str = g_string_sized_new (100);
241
242   g_string_append (str, "\nCOUNT ");
243
244   g_string_append (str, gtk_entry_get_text (GTK_ENTRY (cnt->target)));
245
246   g_string_append (str, " =");
247
248   psppire_var_view_append_names (PSPPIRE_VAR_VIEW (cnt->variable_treeview), 0, str);
249
250   g_string_append (str, "(");
251   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (cnt->value_list),
252                                            &iter);
253        ok;
254        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (cnt->value_list), &iter))
255     {
256       GValue a_value = {0};
257       struct old_value *ov;
258
259       gtk_tree_model_get_value (GTK_TREE_MODEL (cnt->value_list), &iter,
260                                 0, &a_value);
261
262       ov = g_value_get_boxed (&a_value);
263
264       g_string_append (str, " ");
265       old_value_append_syntax (str, ov);
266     }
267   g_string_append (str, ").");
268
269
270   s = gtk_entry_get_text (GTK_ENTRY (cnt->label));
271   if (0 != strcmp (s, ""))
272   {
273     struct string ds;
274     ds_init_empty (&ds);
275     g_string_append (str, "\nVARIABLE LABELS ");
276
277     g_string_append (str, gtk_entry_get_text (GTK_ENTRY (cnt->target)));
278
279     g_string_append (str, " ");
280
281     syntax_gen_string (&ds, ss_cstr (s));
282
283     g_string_append (str, ds_cstr (&ds));
284
285     g_string_append (str, ".");
286     ds_destroy (&ds);
287   }
288
289   g_string_append (str, "\nEXECUTE.\n");
290
291   text = str->str;
292
293   g_string_free (str, FALSE);
294
295   return text;
296 }