1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2012, 2013 Free Software Foundation
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.
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.
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/>. */
20 #include "psppire-dialog-action-compute.h"
22 #include <language/expressions/public.h>
24 #include "psppire-var-view.h"
25 #include "dict-display.h"
26 #include "psppire-dialog.h"
27 #include "psppire-keypad.h"
28 #include "psppire-selector.h"
29 #include "builder-wrapper.h"
31 static void psppire_dialog_action_compute_init (PsppireDialogActionCompute *act);
32 static void psppire_dialog_action_compute_class_init (PsppireDialogActionComputeClass *class);
34 G_DEFINE_TYPE (PsppireDialogActionCompute, psppire_dialog_action_compute, PSPPIRE_TYPE_DIALOG_ACTION);
38 generate_syntax (const PsppireDialogAction *act)
40 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (act);
44 const gchar *target_name ;
47 GtkTextIter start, end;
49 GtkTextBuffer *buffer =
50 gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview));
52 gtk_text_buffer_get_start_iter (buffer, &start);
53 gtk_text_buffer_get_end_iter (buffer, &end);
55 target_name = gtk_entry_get_text (GTK_ENTRY (cd->target));
57 expression = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
59 string = g_string_sized_new (64);
62 NULL == psppire_dict_lookup_var (act->dict, target_name))
64 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->str_btn)))
66 const char *w = gtk_entry_get_text (GTK_ENTRY (cd->width_entry));
67 g_string_append_printf (string,
68 "STRING %s (a%s).\n", target_name, w);
71 g_string_append_printf (string, "NUMERIC %s.\n", target_name);
74 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->user_label)))
75 label = gtk_entry_get_text (GTK_ENTRY (cd->entry));
79 if (strlen (label) > 0)
80 g_string_append_printf (string, "VARIABLE LABEL %s '%s'.\n",
84 g_string_append_printf (string, "COMPUTE %s = %s.\n",
89 g_string_append (string, "EXECUTE.\n");
93 g_string_free (string, FALSE);
100 dialog_state_valid (gpointer data)
107 on_target_change (GObject *obj, gpointer rd_)
109 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (rd_);
111 const gchar *var_name = gtk_entry_get_text (GTK_ENTRY (cd->target));
112 gboolean valid = var_name && strcmp ("", var_name);
114 gtk_widget_set_sensitive (cd->type_and_label, valid);
118 refresh (PsppireDialogAction *rd_)
120 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (rd_);
121 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (rd_);
122 GtkTextIter start, end;
123 GtkTreeSelection *selection;
124 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview));
126 cd->use_type = FALSE;
128 /* Clear the target variable entry box */
129 gtk_entry_set_text (GTK_ENTRY (cd->target), "");
130 g_signal_emit_by_name (cd->target, "changed");
132 /* Clear the syntax area textbuffer */
133 gtk_text_buffer_get_start_iter (buffer, &start);
134 gtk_text_buffer_get_end_iter (buffer, &end);
135 gtk_text_buffer_delete (buffer, &start, &end);
137 /* Unselect all items in the treeview */
138 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pda->source));
139 gtk_tree_selection_unselect_all (selection);
141 /* And the other one */
142 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->functions));
143 gtk_tree_selection_unselect_all (selection);
156 function_list_populate (GtkTreeView *tv)
158 GtkListStore *liststore;
162 const gint n_funcs = expr_get_function_cnt ();
164 liststore = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
166 for (i = 0 ; i < n_funcs ; ++i)
168 const struct operation *op = expr_get_function (i);
170 gtk_list_store_append (liststore, &iter);
172 gtk_list_store_set (liststore, &iter,
173 COMPUTE_COL_NAME, expr_operation_get_name (op),
174 COMPUTE_COL_USAGE, expr_operation_get_prototype (op),
175 COMPUTE_COL_ARITY, expr_operation_get_arg_cnt (op),
181 /* Set the cell rendering */
184 GtkTreeViewColumn *col;
185 GtkCellRenderer *renderer;
188 col = gtk_tree_view_column_new ();
190 gtk_tree_view_append_column (tv, col);
192 renderer = gtk_cell_renderer_text_new ();
194 gtk_tree_view_column_pack_start (col, renderer, TRUE);
196 gtk_tree_view_column_add_attribute (col, renderer, "text", COMPUTE_COL_USAGE);
199 gtk_tree_view_set_model (tv, GTK_TREE_MODEL (liststore));
200 g_object_unref (liststore);
206 reset_type_label_dialog (PsppireDialogActionCompute *cd)
208 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (cd);
210 const gchar *target_name;
211 struct variable *target_var;
214 target_name = gtk_entry_get_text (GTK_ENTRY (cd->target));
217 if ((target_var = psppire_dict_lookup_var (pda->dict, target_name)))
219 /* Existing Variable */
220 const gchar *label = var_get_label (target_var);
222 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->user_label), TRUE);
226 gtk_entry_set_text (GTK_ENTRY (cd->entry), label);
229 gtk_widget_set_sensitive (cd->width_entry, FALSE);
231 if (var_is_numeric (target_var))
232 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->numeric_target),
235 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->str_btn),
238 gtk_widget_set_sensitive (cd->numeric_target, FALSE);
239 gtk_widget_set_sensitive (cd->str_btn, FALSE);
243 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->expression), TRUE);
245 gtk_widget_set_sensitive (cd->width_entry, TRUE);
246 gtk_widget_set_sensitive (cd->numeric_target, TRUE);
247 gtk_widget_set_sensitive (cd->str_btn, TRUE);
249 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->numeric_target),
256 erase_selection (GtkTextBuffer *buffer)
258 GtkTextIter start, end;
260 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
262 gtk_text_buffer_delete (buffer, &start, &end);
267 on_keypad_button (PsppireKeypad *kp, const gchar *syntax, gpointer data)
269 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data);
271 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview));
273 erase_selection (buffer);
275 gtk_text_buffer_insert_at_cursor (buffer, syntax, strlen (syntax));
277 if (0 == strcmp (syntax, "()"))
280 GtkTextMark *cursor = gtk_text_buffer_get_insert (buffer);
281 gtk_text_buffer_get_iter_at_mark (buffer, &iter, cursor);
282 gtk_text_iter_backward_cursor_position (&iter);
283 gtk_text_buffer_move_mark (buffer, cursor, &iter);
289 erase (PsppireKeypad *kp, gpointer data)
291 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data);
293 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview));
295 erase_selection (buffer);
300 run_type_label_dialog (GtkButton *b, gpointer data)
302 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data);
303 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (data);
306 gtk_window_set_transient_for (GTK_WINDOW (cd->subdialog), GTK_WINDOW (pda->dialog));
308 reset_type_label_dialog (cd);
309 response = psppire_dialog_run (PSPPIRE_DIALOG (cd->subdialog));
310 if (response == PSPPIRE_RESPONSE_CONTINUE)
315 on_type_toggled (GtkToggleButton *button, gpointer data)
317 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data);
318 if (gtk_toggle_button_get_active (button))
320 gtk_widget_set_sensitive (cd->width_entry, TRUE);
321 gtk_widget_grab_focus (cd->width_entry);
325 gtk_widget_set_sensitive (cd->width_entry, FALSE);
331 on_expression_toggle (GtkToggleButton *button, gpointer data)
333 PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data);
334 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (data);
336 if (gtk_toggle_button_get_active (button))
338 gtk_entry_set_text (GTK_ENTRY (cd->entry), "");
339 gtk_widget_set_sensitive (cd->entry, FALSE);
343 const gchar *target_name = gtk_entry_get_text (GTK_ENTRY (cd->target));
344 const struct variable *target_var = psppire_dict_lookup_var (pda->dict, target_name);
347 const char *label = var_get_label (target_var);
350 gtk_entry_set_text (GTK_ENTRY (cd->entry), label);
353 gtk_entry_set_text (GTK_ENTRY (cd->entry), "");
355 gtk_widget_set_sensitive (cd->entry, TRUE);
356 gtk_widget_grab_focus (cd->entry);
361 /* Inserts the name of the selected variable into the destination widget.
362 The destination widget must be a GtkTextView
365 insert_source_row_into_text_view (GtkTreeIter iter,
374 struct variable *var;
375 GtkTreeIter dict_iter;
376 GtkTextBuffer *buffer;
378 g_return_if_fail (GTK_IS_TEXT_VIEW (dest));
380 get_base_model (model, &iter, &m, &dict_iter);
381 dict = PSPPIRE_DICT (m);
383 path = gtk_tree_model_get_path (GTK_TREE_MODEL (dict), &dict_iter);
385 idx = gtk_tree_path_get_indices (path);
387 var = psppire_dict_get_variable (dict, *idx);
389 gtk_tree_path_free (path);
391 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dest));
393 erase_selection (buffer);
395 gtk_text_buffer_insert_at_cursor (buffer, var_get_name (var), -1);
399 insert_function_into_syntax_area (GtkTreeIter iter,
400 GtkWidget *text_view,
405 GValue name_value = {0};
406 GValue arity_value = {0};
410 GtkTextBuffer *buffer ;
412 g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
414 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
416 gtk_tree_model_get_value (model, &iter, COMPUTE_COL_NAME, &name_value);
417 gtk_tree_model_get_value (model, &iter, COMPUTE_COL_ARITY, &arity_value);
419 arity = g_value_get_int (&arity_value);
421 string = g_string_new (g_value_get_string (&name_value));
423 g_string_append (string, "(");
424 for (i = 0 ; i < arity -1 ; ++i)
426 g_string_append (string, "?,");
428 g_string_append (string, "?)");
430 erase_selection (buffer);
432 gtk_text_buffer_insert_at_cursor (buffer, string->str, string->len);
434 g_value_unset (&name_value);
435 g_value_unset (&arity_value);
436 g_string_free (string, TRUE);
438 /* Now position the cursor over the first '?' */
441 GtkTextIter selectbound;
442 GtkTextMark *cursor = gtk_text_buffer_get_insert (buffer);
443 gtk_text_buffer_get_iter_at_mark (buffer, &insert, cursor);
444 for (i = 0 ; i < arity ; ++i)
446 gtk_text_iter_backward_cursor_position (&insert);
447 gtk_text_iter_backward_cursor_position (&insert);
449 selectbound = insert;
450 gtk_text_iter_forward_cursor_position (&selectbound);
452 gtk_text_buffer_select_range (buffer, &insert, &selectbound);
458 psppire_dialog_action_compute_activate (PsppireDialogAction *a, GVariant *param)
460 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
461 PsppireDialogActionCompute *act = PSPPIRE_DIALOG_ACTION_COMPUTE (a);
463 GtkBuilder *xml = builder_new ("compute.ui");
465 pda->dialog = get_widget_assert (xml, "compute-variable-dialog");
466 pda->source = get_widget_assert (xml, "compute-treeview1");
468 act->textview = get_widget_assert (xml, "compute-textview1");
470 get_widget_assert (xml, "type-and-label-label-entry");
473 get_widget_assert (xml, "type-and-label-width");
475 act->functions = get_widget_assert (xml, "compute-treeview2");
476 act->keypad = get_widget_assert (xml, "psppire-keypad1");
477 act->target = get_widget_assert (xml, "compute-entry1");
478 act->var_selector = get_widget_assert (xml, "compute-selector1");
479 act->func_selector = get_widget_assert (xml, "compute-selector2");
480 act->type_and_label = get_widget_assert (xml, "compute-button1");
482 act->subdialog = get_widget_assert (xml, "type-and-label-dialog");
484 act->numeric_target = get_widget_assert (xml, "radio-button-numeric");
485 act->expression = get_widget_assert (xml, "radio-button-expression-label");
486 act->user_label = get_widget_assert (xml, "radio-button-user-label");
487 act->str_btn = get_widget_assert (xml, "radio-button-string");
489 g_signal_connect (act->expression, "toggled",
490 G_CALLBACK (on_expression_toggle), pda);
492 g_signal_connect (act->str_btn, "toggled",
493 G_CALLBACK (on_type_toggled), pda);
496 g_object_set (pda->source,
497 "selection-mode", GTK_SELECTION_SINGLE,
500 psppire_selector_set_select_func (PSPPIRE_SELECTOR (act->var_selector),
501 insert_source_row_into_text_view, NULL);
504 function_list_populate (GTK_TREE_VIEW (act->functions));
506 psppire_selector_set_select_func (PSPPIRE_SELECTOR (act->func_selector),
507 insert_function_into_syntax_area, NULL);
509 g_signal_connect (act->target, "changed", G_CALLBACK (on_target_change), act);
511 g_signal_connect (act->keypad, "insert-syntax",
512 G_CALLBACK (on_keypad_button), act);
514 g_signal_connect (act->keypad, "erase",
515 G_CALLBACK (erase), act);
517 g_signal_connect (act->type_and_label, "clicked",
518 G_CALLBACK (run_type_label_dialog), pda);
520 psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid);
521 psppire_dialog_action_set_refresh (pda, refresh);
527 psppire_dialog_action_compute_class_init (PsppireDialogActionComputeClass *class)
529 PSPPIRE_DIALOG_ACTION_CLASS (class)->initial_activate = psppire_dialog_action_compute_activate;
531 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
536 psppire_dialog_action_compute_init (PsppireDialogActionCompute *act)