From 20818d7ae4bc4d4256d78683c9eb8d26416acd30 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Thu, 10 Oct 2013 09:31:03 +0200 Subject: [PATCH] Compute Dialog: Convert to PsppireDialogAction --- src/ui/gui/automake.mk | 4 +- src/ui/gui/compute-dialog.c | 641 --------------------- src/ui/gui/compute-dialog.h | 24 - src/ui/gui/data-editor.ui | 3 +- src/ui/gui/psppire-data-window.c | 2 - src/ui/gui/psppire-dialog-action-compute.c | 556 ++++++++++++++++++ src/ui/gui/psppire-dialog-action-compute.h | 95 +++ src/ui/gui/widgets.c | 2 + 8 files changed, 657 insertions(+), 670 deletions(-) delete mode 100644 src/ui/gui/compute-dialog.c delete mode 100644 src/ui/gui/compute-dialog.h create mode 100644 src/ui/gui/psppire-dialog-action-compute.c create mode 100644 src/ui/gui/psppire-dialog-action-compute.h diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index bd1ae5280a..addbbe2cad 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -139,8 +139,6 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/builder-wrapper.h \ src/ui/gui/comments-dialog.c \ src/ui/gui/comments-dialog.h \ - src/ui/gui/compute-dialog.c \ - src/ui/gui/compute-dialog.h \ src/ui/gui/count-dialog.c \ src/ui/gui/count-dialog.h \ src/ui/gui/dialog-common.c \ @@ -191,6 +189,8 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/psppire-dialog-action-binomial.h \ src/ui/gui/psppire-dialog-action-chisquare.c \ src/ui/gui/psppire-dialog-action-chisquare.h \ + src/ui/gui/psppire-dialog-action-compute.c \ + src/ui/gui/psppire-dialog-action-compute.h \ src/ui/gui/psppire-dialog-action-correlation.c \ src/ui/gui/psppire-dialog-action-correlation.h \ src/ui/gui/psppire-dialog-action-crosstabs.c \ diff --git a/src/ui/gui/compute-dialog.c b/src/ui/gui/compute-dialog.c deleted file mode 100644 index 46f9fbe078..0000000000 --- a/src/ui/gui/compute-dialog.c +++ /dev/null @@ -1,641 +0,0 @@ -/* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2007, 2010, 2011, 2012 Free Software Foundation - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include -#include -#include "compute-dialog.h" -#include "builder-wrapper.h" -#include "psppire-dialog.h" -#include "psppire-keypad.h" -#include "psppire-data-window.h" -#include "psppire-selector.h" -#include "dialog-common.h" -#include - - -#include -#include "executor.h" -#include "helper.h" - - -static void function_list_populate (GtkTreeView *tv); - -static void insert_function_into_syntax_area (GtkTreeIter iter, - GtkWidget *text_view, - GtkTreeModel *model, - gpointer data - ); - -static void insert_source_row_into_text_view (GtkTreeIter iter, - GtkWidget *dest, - GtkTreeModel *model, - gpointer data - ); - - - -struct compute_dialog -{ - GtkBuilder *xml; /* The xml that generated the widgets */ - PsppireDict *dict; - gboolean use_type; -}; - - -static void -on_target_change (GObject *obj, struct compute_dialog *cd) -{ - GtkWidget *target = get_widget_assert (cd->xml, "compute-entry1"); - GtkWidget *type_and_label = get_widget_assert (cd->xml, "compute-button1"); - - const gchar *var_name = gtk_entry_get_text (GTK_ENTRY (target)); - gboolean valid = var_name && strcmp ("", var_name); - - gtk_widget_set_sensitive (type_and_label, valid); -} - -static void -refresh (GObject *obj, const struct compute_dialog *cd) -{ - GtkTextIter start, end; - GtkWidget *target = get_widget_assert (cd->xml, "compute-entry1"); - GtkWidget *syntax_area = get_widget_assert (cd->xml, "compute-textview1"); - GtkWidget *varlist = get_widget_assert (cd->xml, "compute-treeview1"); - GtkWidget *funclist = get_widget_assert (cd->xml, "compute-treeview2"); - - GtkTextBuffer *buffer = - gtk_text_view_get_buffer (GTK_TEXT_VIEW (syntax_area)); - - GtkTreeSelection *selection; - - /* Clear the target variable entry box */ - gtk_entry_set_text (GTK_ENTRY (target), ""); - g_signal_emit_by_name (target, "changed"); - - /* Clear the syntax area textbuffer */ - gtk_text_buffer_get_start_iter (buffer, &start); - gtk_text_buffer_get_end_iter (buffer, &end); - gtk_text_buffer_delete (buffer, &start, &end); - - /* Unselect all items in the treeview */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (varlist)); - gtk_tree_selection_unselect_all (selection); - - /* And the other one */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (funclist)); - gtk_tree_selection_unselect_all (selection); -} - - -static void -erase_selection (GtkTextBuffer *buffer) -{ - GtkTextIter start, end; - - gtk_text_buffer_get_selection_bounds (buffer, &start, &end); - - gtk_text_buffer_delete (buffer, &start, &end); -} - - - -static void -on_keypad_button (PsppireKeypad *kp, const gchar *syntax, gpointer data) -{ - GtkBuilder *xml = data; - - GtkWidget *rhs = get_widget_assert (xml, "compute-textview1"); - - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rhs)); - - erase_selection (buffer); - - gtk_text_buffer_insert_at_cursor (buffer, syntax, strlen (syntax)); - - if (0 == strcmp (syntax, "()")) - { - GtkTextIter iter; - GtkTextMark *cursor = gtk_text_buffer_get_insert (buffer); - gtk_text_buffer_get_iter_at_mark (buffer, &iter, cursor); - gtk_text_iter_backward_cursor_position (&iter); - gtk_text_buffer_move_mark (buffer, cursor, &iter); - } - -} - -static void -erase (PsppireKeypad *kp, gpointer data) -{ - GtkBuilder *xml = data; - - GtkWidget *rhs = get_widget_assert (xml, "compute-textview1"); - - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rhs)); - - erase_selection (buffer); -} - -static char * -generate_syntax (const struct compute_dialog *cd) -{ - gchar *text; - GString *string ; - const gchar *target_name ; - gchar *expression; - const gchar *label; - GtkTextIter start, end; - GtkWidget *target = get_widget_assert (cd->xml, "compute-entry1"); - GtkWidget *syntax_area = get_widget_assert (cd->xml, "compute-textview1"); - GtkWidget *string_toggle = get_widget_assert (cd->xml, "radio-button-string"); - GtkWidget *user_label_toggle = - get_widget_assert (cd->xml, "radio-button-user-label"); - GtkWidget *width_entry = get_widget_assert (cd->xml, "type-and-label-width"); - GtkWidget *label_entry = get_widget_assert (cd->xml, - "type-and-label-label-entry"); - - - GtkTextBuffer *buffer = - gtk_text_view_get_buffer (GTK_TEXT_VIEW (syntax_area)); - - gtk_text_buffer_get_start_iter (buffer, &start); - gtk_text_buffer_get_end_iter (buffer, &end); - - target_name = gtk_entry_get_text (GTK_ENTRY (target)); - - expression = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); - - string = g_string_sized_new (64); - - if ( cd-> use_type && - NULL == psppire_dict_lookup_var (cd->dict, target_name )) - { - if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (string_toggle))) - { - const char *w = gtk_entry_get_text (GTK_ENTRY(width_entry)); - g_string_append_printf (string, - "STRING %s (a%s).\n", target_name, w); - } - else - g_string_append_printf (string, "NUMERIC %s.\n", target_name); - } - - if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (user_label_toggle))) - label = gtk_entry_get_text (GTK_ENTRY (label_entry)); - else - label = expression; - - if ( strlen (label) > 0 ) - g_string_append_printf (string, "VARIABLE LABEL %s '%s'.\n", - target_name, - label); - - g_string_append_printf (string, "COMPUTE %s = %s.\n", - target_name, - expression - ); - - g_string_append (string, "EXECUTE.\n"); - - - g_free (expression); - - text = string->str; - - g_string_free (string, FALSE); - - return text; -} - -static void -reset_type_label_dialog (struct compute_dialog *cd) -{ - const gchar *target_name; - struct variable *target_var; - - GtkWidget *width_entry = - get_widget_assert (cd->xml, "type-and-label-width"); - - GtkWidget *label_entry = - get_widget_assert (cd->xml, "type-and-label-label-entry"); - - GtkWidget *numeric_target = - get_widget_assert (cd->xml, "radio-button-numeric"); - - GtkWidget *string_target = - get_widget_assert (cd->xml, "radio-button-string"); - - - target_name = gtk_entry_get_text - (GTK_ENTRY (get_widget_assert (cd->xml, "compute-entry1"))); - - - if ( (target_var = psppire_dict_lookup_var (cd->dict, target_name)) ) - { - /* Existing Variable */ - const gchar *label ; - GtkWidget *user_label = - get_widget_assert (cd->xml, "radio-button-user-label"); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (user_label), TRUE); - - label = var_get_label (target_var); - - if ( label ) - { - gtk_entry_set_text (GTK_ENTRY (label_entry), label); - } - - gtk_widget_set_sensitive (width_entry, FALSE); - - if ( var_is_numeric (target_var)) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (numeric_target), - TRUE); - else - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (string_target), - TRUE); - - gtk_widget_set_sensitive (numeric_target, FALSE); - gtk_widget_set_sensitive (string_target, FALSE); - } - else - { - GtkWidget *expression = - get_widget_assert (cd->xml, "radio-button-expression-label"); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (expression), TRUE); - - gtk_widget_set_sensitive (width_entry, TRUE); - gtk_widget_set_sensitive (numeric_target, TRUE); - gtk_widget_set_sensitive (string_target, TRUE); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (numeric_target), - TRUE); - } - -} - -static void -run_type_label_dialog (GtkButton *b, gpointer data) -{ - struct compute_dialog *cd = data; - gint response; - - GtkWidget *subdialog = get_widget_assert (cd->xml, "type-and-label-dialog"); - GtkWidget *dialog = get_widget_assert (cd->xml, "compute-variable-dialog"); - - gtk_window_set_transient_for (GTK_WINDOW (subdialog), GTK_WINDOW (dialog)); - - reset_type_label_dialog (cd); - response = psppire_dialog_run (PSPPIRE_DIALOG (subdialog)); - if ( response == PSPPIRE_RESPONSE_CONTINUE) - cd->use_type = TRUE; -} - -static void -on_type_toggled (GtkToggleButton *button, gpointer data) -{ - struct compute_dialog *cd = data; - - GtkWidget *entry = - get_widget_assert (cd->xml, "type-and-label-width"); - - if ( gtk_toggle_button_get_active (button)) - { - gtk_widget_set_sensitive (entry, TRUE); - gtk_widget_grab_focus (entry); - } - else - { - gtk_widget_set_sensitive (entry, FALSE); - } -} - -static void -on_expression_toggle (GtkToggleButton *button, gpointer data) -{ - struct compute_dialog *cd = data; - - GtkWidget *entry = - get_widget_assert (cd->xml, "type-and-label-label-entry"); - - if ( gtk_toggle_button_get_active (button)) - { - gtk_entry_set_text (GTK_ENTRY (entry), ""); - gtk_widget_set_sensitive (entry, FALSE); - } - else - { - struct variable *target_var; - const gchar *target_name = gtk_entry_get_text - (GTK_ENTRY (get_widget_assert (cd->xml, "compute-entry1"))); - - target_var = psppire_dict_lookup_var (cd->dict, target_name); - if ( target_var ) - { - const char *label = var_get_label (target_var); - - if ( label ) - gtk_entry_set_text (GTK_ENTRY (entry), label); - } - else - gtk_entry_set_text (GTK_ENTRY (entry), ""); - - gtk_widget_set_sensitive (entry, TRUE); - gtk_widget_grab_focus (entry); - } -} - - -/* Return TRUE if the dialog box's widgets' state are such that clicking OK - might not result in erroneous syntax being generated */ -static gboolean -contents_plausible (gpointer data) -{ - struct compute_dialog *cd = data; - - GtkWidget *target = get_widget_assert (cd->xml, "compute-entry1"); - GtkWidget *syntax_area = get_widget_assert (cd->xml, "compute-textview1"); - GtkTextBuffer *buffer = - gtk_text_view_get_buffer (GTK_TEXT_VIEW (syntax_area)); - - if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (target)))) - return FALSE; - - if ( gtk_text_buffer_get_char_count (buffer) == 0 ) - return FALSE; - - return TRUE; -} - -/* Pops up the Compute dialog box */ -void -compute_dialog (PsppireDataWindow *de) -{ - gint response; - - struct compute_dialog scd; - - GtkBuilder *xml = builder_new ("compute.ui"); - - GtkWidget *dialog = get_widget_assert (xml, "compute-variable-dialog"); - - GtkWidget *dict_view = get_widget_assert (xml, "compute-treeview1"); - GtkWidget *functions = get_widget_assert (xml, "compute-treeview2"); - GtkWidget *keypad = get_widget_assert (xml, "psppire-keypad1"); - GtkWidget *target = get_widget_assert (xml, "compute-entry1"); - GtkWidget *var_selector = get_widget_assert (xml, "compute-selector1"); - GtkWidget *func_selector = get_widget_assert (xml, "compute-selector2"); - GtkWidget *type_and_label = get_widget_assert (xml, "compute-button1"); - - GtkWidget *expression = - get_widget_assert (xml, "radio-button-expression-label"); - - GtkWidget *str_btn = - get_widget_assert (xml, "radio-button-string"); - - - g_object_get (de->data_editor, "dictionary", &scd.dict, NULL); - scd.use_type = FALSE; - - g_signal_connect (expression, "toggled", - G_CALLBACK(on_expression_toggle), &scd); - - g_signal_connect (str_btn, "toggled", - G_CALLBACK(on_type_toggled), &scd); - - gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de)); - - - g_object_set (dict_view, "model", scd.dict, - "selection-mode", GTK_SELECTION_SINGLE, - NULL); - - psppire_selector_set_select_func (PSPPIRE_SELECTOR (var_selector), - insert_source_row_into_text_view, NULL); - - function_list_populate (GTK_TREE_VIEW (functions)); - - psppire_selector_set_select_func (PSPPIRE_SELECTOR (func_selector), - insert_function_into_syntax_area, NULL); - - scd.xml = xml; - - psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog), - contents_plausible, &scd); - - g_signal_connect (target, "changed", G_CALLBACK (on_target_change), &scd); - - g_signal_connect (dialog, "refresh", G_CALLBACK (refresh), &scd); - - g_signal_connect (keypad, "insert-syntax", - G_CALLBACK (on_keypad_button), xml); - - g_signal_connect (keypad, "erase", - G_CALLBACK (erase), xml); - - - g_signal_connect (type_and_label, "clicked", - G_CALLBACK (run_type_label_dialog), &scd); - - - - response = psppire_dialog_run (PSPPIRE_DIALOG (dialog)); - - - switch (response) - { - case GTK_RESPONSE_OK: - g_free (execute_syntax_string (de, generate_syntax (&scd))); - break; - case PSPPIRE_RESPONSE_PASTE: - g_free (paste_syntax_to_window (generate_syntax (&scd))); - break; - default: - break; - } - - g_object_unref (xml); -} - - -enum { - COMPUTE_COL_NAME, - COMPUTE_COL_USAGE, - COMPUTE_COL_ARITY -}; - - -static void -function_list_populate (GtkTreeView *tv) -{ - GtkListStore *liststore; - GtkTreeIter iter; - gint i; - - const gint n_funcs = expr_get_function_cnt (); - - liststore = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); - - for (i = 0 ; i < n_funcs ; ++i) - { - const struct operation *op = expr_get_function (i); - - gtk_list_store_append (liststore, &iter); - - gtk_list_store_set (liststore, &iter, - COMPUTE_COL_NAME, expr_operation_get_name (op), - COMPUTE_COL_USAGE, expr_operation_get_prototype (op), - COMPUTE_COL_ARITY, expr_operation_get_arg_cnt (op), - -1); - } - - - - /* Set the cell rendering */ - - { - GtkTreeViewColumn *col; - GtkCellRenderer *renderer; - - - col = gtk_tree_view_column_new (); - - gtk_tree_view_append_column (tv, col); - - renderer = gtk_cell_renderer_text_new (); - - gtk_tree_view_column_pack_start (col, renderer, TRUE); - - gtk_tree_view_column_add_attribute (col, renderer, "text", COMPUTE_COL_USAGE); - } - - gtk_tree_view_set_model (tv, GTK_TREE_MODEL (liststore)); - g_object_unref (liststore); -} - - - - -static void -insert_function_into_syntax_area (GtkTreeIter iter, - GtkWidget *text_view, - GtkTreeModel *model, - gpointer data - ) -{ - GString *string; - GValue name_value = {0}; - GValue arity_value = {0}; - gint arity; - gint i; - - GtkTextBuffer *buffer ; - - g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); - - gtk_tree_model_get_value (model, &iter, COMPUTE_COL_NAME, &name_value); - gtk_tree_model_get_value (model, &iter, COMPUTE_COL_ARITY, &arity_value); - - arity = g_value_get_int (&arity_value); - - string = g_string_new (g_value_get_string (&name_value)); - - g_string_append (string, "("); - for ( i = 0 ; i < arity -1 ; ++i ) - { - g_string_append (string, "?,"); - } - g_string_append (string, "?)"); - - - erase_selection (buffer); - - gtk_text_buffer_insert_at_cursor (buffer, string->str, string->len); - - g_value_unset (&name_value); - g_value_unset (&arity_value); - g_string_free (string, TRUE); - - /* Now position the cursor over the first '?' */ - { - GtkTextIter insert; - GtkTextIter selectbound; - GtkTextMark *cursor = gtk_text_buffer_get_insert (buffer); - gtk_text_buffer_get_iter_at_mark (buffer, &insert, cursor); - for ( i = 0 ; i < arity ; ++i ) - { - gtk_text_iter_backward_cursor_position (&insert); - gtk_text_iter_backward_cursor_position (&insert); - } - selectbound = insert; - gtk_text_iter_forward_cursor_position (&selectbound); - - gtk_text_buffer_select_range (buffer, &insert, &selectbound); - } - -} - -/* Inserts the name of the selected variable into the destination widget. - The destination widget must be a GtkTextView - */ -static void -insert_source_row_into_text_view (GtkTreeIter iter, - GtkWidget *dest, - GtkTreeModel *model, - gpointer data - ) -{ - GtkTreePath *path; - PsppireDict *dict; - gint *idx; - struct variable *var; - GtkTreeIter dict_iter; - GtkTextBuffer *buffer; - - g_return_if_fail (GTK_IS_TEXT_VIEW (dest)); - - if ( GTK_IS_TREE_MODEL_FILTER (model)) - { - dict = PSPPIRE_DICT (gtk_tree_model_filter_get_model - (GTK_TREE_MODEL_FILTER(model))); - - gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER - (model), - &dict_iter, &iter); - } - else - { - dict = PSPPIRE_DICT (model); - dict_iter = iter; - } - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (dict), &dict_iter); - - idx = gtk_tree_path_get_indices (path); - - var = psppire_dict_get_variable (dict, *idx); - - gtk_tree_path_free (path); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dest)); - - erase_selection (buffer); - - gtk_text_buffer_insert_at_cursor (buffer, var_get_name (var), -1); - -} diff --git a/src/ui/gui/compute-dialog.h b/src/ui/gui/compute-dialog.h deleted file mode 100644 index 6e136074a4..0000000000 --- a/src/ui/gui/compute-dialog.h +++ /dev/null @@ -1,24 +0,0 @@ -/* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2007, 2010 Free Software Foundation - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#ifndef __COMPUTE_DIALOG_H -#define __COMPUTE_DIALOG_H - -#include "psppire-data-window.h" - -void compute_dialog (PsppireDataWindow * data); - -#endif diff --git a/src/ui/gui/data-editor.ui b/src/ui/gui/data-editor.ui index 5e944575e6..850f318a06 100644 --- a/src/ui/gui/data-editor.ui +++ b/src/ui/gui/data-editor.ui @@ -222,8 +222,9 @@ - + transform_compute + uimanager1 _Compute... transform-compute diff --git a/src/ui/gui/psppire-data-window.c b/src/ui/gui/psppire-data-window.c index fd2f4ff055..f756586a25 100644 --- a/src/ui/gui/psppire-data-window.c +++ b/src/ui/gui/psppire-data-window.c @@ -28,7 +28,6 @@ #include "ui/gui/autorecode-dialog.h" #include "ui/gui/builder-wrapper.h" #include "ui/gui/comments-dialog.h" -#include "ui/gui/compute-dialog.h" #include "ui/gui/count-dialog.h" #include "ui/gui/entry-dialog.h" #include "ui/gui/executor.h" @@ -956,7 +955,6 @@ psppire_data_window_finish_init (PsppireDataWindow *de, connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog)); connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog)); - connect_action (de, "transform_compute", G_CALLBACK (compute_dialog)); connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog)); connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog)); connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog)); diff --git a/src/ui/gui/psppire-dialog-action-compute.c b/src/ui/gui/psppire-dialog-action-compute.c new file mode 100644 index 0000000000..46944c3fd3 --- /dev/null +++ b/src/ui/gui/psppire-dialog-action-compute.c @@ -0,0 +1,556 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2012, 2013 Free Software Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include + +#include "psppire-dialog-action-compute.h" + +#include + +#include "psppire-var-view.h" + +#include "psppire-dialog.h" +#include "psppire-keypad.h" +#include "psppire-selector.h" +#include "builder-wrapper.h" + +static void psppire_dialog_action_compute_init (PsppireDialogActionCompute *act); +static void psppire_dialog_action_compute_class_init (PsppireDialogActionComputeClass *class); + +G_DEFINE_TYPE (PsppireDialogActionCompute, psppire_dialog_action_compute, PSPPIRE_TYPE_DIALOG_ACTION); + + +static char * +generate_syntax (PsppireDialogAction *act) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (act); + gchar *text; + GString *string; + + const gchar *target_name ; + gchar *expression; + const gchar *label; + GtkTextIter start, end; + + GtkTextBuffer *buffer = + gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview)); + + gtk_text_buffer_get_start_iter (buffer, &start); + gtk_text_buffer_get_end_iter (buffer, &end); + + target_name = gtk_entry_get_text (GTK_ENTRY (cd->target)); + + expression = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); + + string = g_string_sized_new (64); + + if ( cd->use_type && + NULL == psppire_dict_lookup_var (act->dict, target_name )) + { + if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->str_btn))) + { + const char *w = gtk_entry_get_text (GTK_ENTRY (cd->width_entry)); + g_string_append_printf (string, + "STRING %s (a%s).\n", target_name, w); + } + else + g_string_append_printf (string, "NUMERIC %s.\n", target_name); + } + + if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->user_label))) + label = gtk_entry_get_text (GTK_ENTRY (cd->entry)); + else + label = expression; + + if ( strlen (label) > 0 ) + g_string_append_printf (string, "VARIABLE LABEL %s '%s'.\n", + target_name, + label); + + g_string_append_printf (string, "COMPUTE %s = %s.\n", + target_name, + expression + ); + + g_string_append (string, "EXECUTE.\n"); + + text = string->str; + + g_string_free (string, FALSE); + + return text; +} + + +static gboolean +dialog_state_valid (gpointer data) +{ + + return TRUE; +} + +static void +on_target_change (GObject *obj, gpointer rd_) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (rd_); + + const gchar *var_name = gtk_entry_get_text (GTK_ENTRY (cd->target)); + gboolean valid = var_name && strcmp ("", var_name); + + gtk_widget_set_sensitive (cd->type_and_label, valid); +} + +static void +refresh (PsppireDialogAction *rd_) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (rd_); + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (rd_); + GtkTextIter start, end; + GtkTreeSelection *selection; + GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview)); + + cd->use_type = FALSE; + + /* Clear the target variable entry box */ + gtk_entry_set_text (GTK_ENTRY (cd->target), ""); + g_signal_emit_by_name (cd->target, "changed"); + + /* Clear the syntax area textbuffer */ + gtk_text_buffer_get_start_iter (buffer, &start); + gtk_text_buffer_get_end_iter (buffer, &end); + gtk_text_buffer_delete (buffer, &start, &end); + + /* Unselect all items in the treeview */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pda->source)); + gtk_tree_selection_unselect_all (selection); + + /* And the other one */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->functions)); + gtk_tree_selection_unselect_all (selection); +} + + + +enum { + COMPUTE_COL_NAME, + COMPUTE_COL_USAGE, + COMPUTE_COL_ARITY +}; + + +static void +function_list_populate (GtkTreeView *tv) +{ + GtkListStore *liststore; + GtkTreeIter iter; + gint i; + + const gint n_funcs = expr_get_function_cnt (); + + liststore = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); + + for (i = 0 ; i < n_funcs ; ++i) + { + const struct operation *op = expr_get_function (i); + + gtk_list_store_append (liststore, &iter); + + gtk_list_store_set (liststore, &iter, + COMPUTE_COL_NAME, expr_operation_get_name (op), + COMPUTE_COL_USAGE, expr_operation_get_prototype (op), + COMPUTE_COL_ARITY, expr_operation_get_arg_cnt (op), + -1); + } + + + + /* Set the cell rendering */ + + { + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + + + col = gtk_tree_view_column_new (); + + gtk_tree_view_append_column (tv, col); + + renderer = gtk_cell_renderer_text_new (); + + gtk_tree_view_column_pack_start (col, renderer, TRUE); + + gtk_tree_view_column_add_attribute (col, renderer, "text", COMPUTE_COL_USAGE); + } + + gtk_tree_view_set_model (tv, GTK_TREE_MODEL (liststore)); + g_object_unref (liststore); +} + + + +static void +reset_type_label_dialog (PsppireDialogActionCompute *cd) +{ + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (cd); + + const gchar *target_name; + struct variable *target_var; + + + target_name = gtk_entry_get_text (GTK_ENTRY (cd->target)); + + + if ( (target_var = psppire_dict_lookup_var (pda->dict, target_name)) ) + { + /* Existing Variable */ + const gchar *label = var_get_label (target_var); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->user_label), TRUE); + + if ( label ) + { + gtk_entry_set_text (GTK_ENTRY (cd->entry), label); + } + + gtk_widget_set_sensitive (cd->width_entry, FALSE); + + if ( var_is_numeric (target_var)) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->numeric_target), + TRUE); + else + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->str_btn), + TRUE); + + gtk_widget_set_sensitive (cd->numeric_target, FALSE); + gtk_widget_set_sensitive (cd->str_btn, FALSE); + } + else + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->expression), TRUE); + + gtk_widget_set_sensitive (cd->width_entry, TRUE); + gtk_widget_set_sensitive (cd->numeric_target, TRUE); + gtk_widget_set_sensitive (cd->str_btn, TRUE); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->numeric_target), + TRUE); + } + +} + +static void +erase_selection (GtkTextBuffer *buffer) +{ + GtkTextIter start, end; + + gtk_text_buffer_get_selection_bounds (buffer, &start, &end); + + gtk_text_buffer_delete (buffer, &start, &end); +} + + +static void +on_keypad_button (PsppireKeypad *kp, const gchar *syntax, gpointer data) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data); + + GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview)); + + erase_selection (buffer); + + gtk_text_buffer_insert_at_cursor (buffer, syntax, strlen (syntax)); + + if (0 == strcmp (syntax, "()")) + { + GtkTextIter iter; + GtkTextMark *cursor = gtk_text_buffer_get_insert (buffer); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, cursor); + gtk_text_iter_backward_cursor_position (&iter); + gtk_text_buffer_move_mark (buffer, cursor, &iter); + } + +} + +static void +erase (PsppireKeypad *kp, gpointer data) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data); + + GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cd->textview)); + + erase_selection (buffer); +} + + +static void +run_type_label_dialog (GtkButton *b, gpointer data) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data); + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (data); + gint response; + + gtk_window_set_transient_for (GTK_WINDOW (cd->subdialog), GTK_WINDOW (pda->dialog)); + + reset_type_label_dialog (cd); + response = psppire_dialog_run (PSPPIRE_DIALOG (cd->subdialog)); + if ( response == PSPPIRE_RESPONSE_CONTINUE) + cd->use_type = TRUE; +} + +static void +on_type_toggled (GtkToggleButton *button, gpointer data) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data); + if ( gtk_toggle_button_get_active (button)) + { + gtk_widget_set_sensitive (cd->width_entry, TRUE); + gtk_widget_grab_focus (cd->width_entry); + } + else + { + gtk_widget_set_sensitive (cd->width_entry, FALSE); + } +} + + +static void +on_expression_toggle (GtkToggleButton *button, gpointer data) +{ + PsppireDialogActionCompute *cd = PSPPIRE_DIALOG_ACTION_COMPUTE (data); + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (data); + + if ( gtk_toggle_button_get_active (button)) + { + gtk_entry_set_text (GTK_ENTRY (cd->entry), ""); + gtk_widget_set_sensitive (cd->entry, FALSE); + } + else + { + const gchar *target_name = gtk_entry_get_text (GTK_ENTRY (cd->target)); + const struct variable *target_var = psppire_dict_lookup_var (pda->dict, target_name); + if ( target_var ) + { + const char *label = var_get_label (target_var); + + if ( label ) + gtk_entry_set_text (GTK_ENTRY (cd->entry), label); + } + else + gtk_entry_set_text (GTK_ENTRY (cd->entry), ""); + + gtk_widget_set_sensitive (cd->entry, TRUE); + gtk_widget_grab_focus (cd->entry); + } +} + + +/* Inserts the name of the selected variable into the destination widget. + The destination widget must be a GtkTextView + */ +static void +insert_source_row_into_text_view (GtkTreeIter iter, + GtkWidget *dest, + GtkTreeModel *model, + gpointer data + ) +{ + GtkTreePath *path; + PsppireDict *dict; + gint *idx; + struct variable *var; + GtkTreeIter dict_iter; + GtkTextBuffer *buffer; + + g_return_if_fail (GTK_IS_TEXT_VIEW (dest)); + + if ( GTK_IS_TREE_MODEL_FILTER (model)) + { + dict = PSPPIRE_DICT (gtk_tree_model_filter_get_model + (GTK_TREE_MODEL_FILTER(model))); + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER + (model), + &dict_iter, &iter); + } + else + { + dict = PSPPIRE_DICT (model); + dict_iter = iter; + } + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (dict), &dict_iter); + + idx = gtk_tree_path_get_indices (path); + + var = psppire_dict_get_variable (dict, *idx); + + gtk_tree_path_free (path); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dest)); + + erase_selection (buffer); + + gtk_text_buffer_insert_at_cursor (buffer, var_get_name (var), -1); + +} + +static void +insert_function_into_syntax_area (GtkTreeIter iter, + GtkWidget *text_view, + GtkTreeModel *model, + gpointer data) +{ + GString *string; + GValue name_value = {0}; + GValue arity_value = {0}; + gint arity; + gint i; + + GtkTextBuffer *buffer ; + + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); + + gtk_tree_model_get_value (model, &iter, COMPUTE_COL_NAME, &name_value); + gtk_tree_model_get_value (model, &iter, COMPUTE_COL_ARITY, &arity_value); + + arity = g_value_get_int (&arity_value); + + string = g_string_new (g_value_get_string (&name_value)); + + g_string_append (string, "("); + for ( i = 0 ; i < arity -1 ; ++i ) + { + g_string_append (string, "?,"); + } + g_string_append (string, "?)"); + + erase_selection (buffer); + + gtk_text_buffer_insert_at_cursor (buffer, string->str, string->len); + + g_value_unset (&name_value); + g_value_unset (&arity_value); + g_string_free (string, TRUE); + + /* Now position the cursor over the first '?' */ + { + GtkTextIter insert; + GtkTextIter selectbound; + GtkTextMark *cursor = gtk_text_buffer_get_insert (buffer); + gtk_text_buffer_get_iter_at_mark (buffer, &insert, cursor); + for ( i = 0 ; i < arity ; ++i ) + { + gtk_text_iter_backward_cursor_position (&insert); + gtk_text_iter_backward_cursor_position (&insert); + } + selectbound = insert; + gtk_text_iter_forward_cursor_position (&selectbound); + + gtk_text_buffer_select_range (buffer, &insert, &selectbound); + } +} + + + +static void +psppire_dialog_action_compute_activate (GtkAction *a) +{ + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a); + PsppireDialogActionCompute *act = PSPPIRE_DIALOG_ACTION_COMPUTE (a); + + GtkBuilder *xml = builder_new ("compute.ui"); + pda->dialog = get_widget_assert (xml, "compute-variable-dialog"); + pda->source = get_widget_assert (xml, "compute-treeview1"); + + act->textview = get_widget_assert (xml, "compute-textview1"); + act->entry = + get_widget_assert (xml, "type-and-label-label-entry"); + + act->width_entry = + get_widget_assert (xml, "type-and-label-width"); + + act->functions = get_widget_assert (xml, "compute-treeview2"); + act->keypad = get_widget_assert (xml, "psppire-keypad1"); + act->target = get_widget_assert (xml, "compute-entry1"); + act->var_selector = get_widget_assert (xml, "compute-selector1"); + act->func_selector = get_widget_assert (xml, "compute-selector2"); + act->type_and_label = get_widget_assert (xml, "compute-button1"); + + act->subdialog = get_widget_assert (xml, "type-and-label-dialog"); + + act->numeric_target = get_widget_assert (xml, "radio-button-numeric"); + act->expression = get_widget_assert (xml, "radio-button-expression-label"); + act->user_label = get_widget_assert (xml, "radio-button-user-label"); + act->str_btn = get_widget_assert (xml, "radio-button-string"); + + g_signal_connect (act->expression, "toggled", + G_CALLBACK (on_expression_toggle), pda); + + g_signal_connect (act->str_btn, "toggled", + G_CALLBACK (on_type_toggled), pda); + + + g_object_set (pda->source, + "selection-mode", GTK_SELECTION_SINGLE, + NULL); + + psppire_selector_set_select_func (PSPPIRE_SELECTOR (act->var_selector), + insert_source_row_into_text_view, NULL); + + + function_list_populate (GTK_TREE_VIEW (act->functions)); + + psppire_selector_set_select_func (PSPPIRE_SELECTOR (act->func_selector), + insert_function_into_syntax_area, NULL); + + g_signal_connect (act->target, "changed", G_CALLBACK (on_target_change), act); + + g_signal_connect (act->keypad, "insert-syntax", + G_CALLBACK (on_keypad_button), act); + + g_signal_connect (act->keypad, "erase", + G_CALLBACK (erase), act); + + g_signal_connect (act->type_and_label, "clicked", + G_CALLBACK (run_type_label_dialog), pda); + + psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid); + psppire_dialog_action_set_refresh (pda, refresh); + + g_object_unref (xml); + + if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_compute_parent_class)->activate) + PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_compute_parent_class)->activate (pda); +} + +static void +psppire_dialog_action_compute_class_init (PsppireDialogActionComputeClass *class) +{ + GtkActionClass *action_class = GTK_ACTION_CLASS (class); + + action_class->activate = psppire_dialog_action_compute_activate; + PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax; +} + + +static void +psppire_dialog_action_compute_init (PsppireDialogActionCompute *act) +{ +} + diff --git a/src/ui/gui/psppire-dialog-action-compute.h b/src/ui/gui/psppire-dialog-action-compute.h new file mode 100644 index 0000000000..c988710463 --- /dev/null +++ b/src/ui/gui/psppire-dialog-action-compute.h @@ -0,0 +1,95 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2013 Free Software Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include +#include + +#include "psppire-dialog-action.h" + +#ifndef __PSPPIRE_DIALOG_ACTION_COMPUTE_H__ +#define __PSPPIRE_DIALOG_ACTION_COMPUTE_H__ + +G_BEGIN_DECLS + + +#define PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE (psppire_dialog_action_compute_get_type ()) + +#define PSPPIRE_DIALOG_ACTION_COMPUTE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, PsppireDialogActionCompute)) + +#define PSPPIRE_DIALOG_ACTION_COMPUTE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, \ + PsppireDialogActionComputeClass)) + + +#define PSPPIRE_IS_DIALOG_ACTION_COMPUTE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE)) + +#define PSPPIRE_IS_DIALOG_ACTION_COMPUTE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE)) + + +#define PSPPIRE_DIALOG_ACTION_COMPUTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, \ + PsppireDialogActionComputeClass)) + +typedef struct _PsppireDialogActionCompute PsppireDialogActionCompute; +typedef struct _PsppireDialogActionComputeClass PsppireDialogActionComputeClass; + + +struct _PsppireDialogActionCompute +{ + PsppireDialogAction parent; + + /*< private >*/ + gboolean dispose_has_run ; + + gboolean use_type; + + + GtkWidget *subdialog; + + GtkWidget *entry; + GtkWidget *width_entry; + GtkWidget *user_label; + GtkWidget *numeric_target; + GtkWidget *textview; + + GtkWidget *functions; + GtkWidget *keypad; + GtkWidget *target; + GtkWidget *var_selector; + GtkWidget *func_selector; + GtkWidget *type_and_label; + GtkWidget *expression; + GtkWidget *str_btn; +}; + + +struct _PsppireDialogActionComputeClass +{ + PsppireDialogActionClass parent_class; +}; + + +GType psppire_dialog_action_compute_get_type (void) ; + +G_END_DECLS + +#endif /* __PSPPIRE_DIALOG_ACTION_COMPUTE_H__ */ diff --git a/src/ui/gui/widgets.c b/src/ui/gui/widgets.c index 9a4c766d16..220de39642 100644 --- a/src/ui/gui/widgets.c +++ b/src/ui/gui/widgets.c @@ -18,6 +18,7 @@ #include "psppire-dialog-action-binomial.h" #include "psppire-dialog-action-chisquare.h" +#include "psppire-dialog-action-compute.h" #include "psppire-dialog-action-correlation.h" #include "psppire-dialog-action-crosstabs.h" #include "psppire-dialog-action-descriptives.h" @@ -66,6 +67,7 @@ preregister_widgets (void) psppire_dialog_action_1sks_get_type (); psppire_dialog_action_binomial_get_type (); psppire_dialog_action_chisquare_get_type (); + psppire_dialog_action_compute_get_type (); psppire_dialog_action_correlation_get_type (); psppire_dialog_action_crosstabs_get_type (); psppire_dialog_action_descriptives_get_type (); -- 2.30.2