From eb98330d56ce2c1947d179648b01d4e6779c665b Mon Sep 17 00:00:00 2001 From: John Darrington Date: Tue, 19 Jan 2016 20:31:27 +0100 Subject: [PATCH] Recode Dialog: Convert to PsppireDialogAction --- src/ui/gui/automake.mk | 4 +- src/ui/gui/data-editor.ui | 8 +- src/ui/gui/psppire-data-window.c | 4 - ...ialog.c => psppire-dialog-action-recode.c} | 948 +++++++++--------- src/ui/gui/psppire-dialog-action-recode.h | 113 +++ src/ui/gui/recode-dialog.h | 26 - src/ui/gui/recode.ui | 1 + src/ui/gui/widgets.c | 2 + 8 files changed, 587 insertions(+), 519 deletions(-) rename src/ui/gui/{recode-dialog.c => psppire-dialog-action-recode.c} (67%) create mode 100644 src/ui/gui/psppire-dialog-action-recode.h delete mode 100644 src/ui/gui/recode-dialog.h diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index 82590e6e1a..43068f2876 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -239,6 +239,8 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/psppire-dialog-action-paired.h \ src/ui/gui/psppire-dialog-action-rank.c \ src/ui/gui/psppire-dialog-action-rank.h \ + src/ui/gui/psppire-dialog-action-recode.c \ + src/ui/gui/psppire-dialog-action-recode.h \ src/ui/gui/psppire-dialog-action-regression.c \ src/ui/gui/psppire-dialog-action-regression.h \ src/ui/gui/psppire-dialog-action-reliability.c \ @@ -309,8 +311,6 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/psppire-window-base.h \ src/ui/gui/psppire-window-register.c \ src/ui/gui/psppire-window-register.h \ - src/ui/gui/recode-dialog.c \ - src/ui/gui/recode-dialog.h \ src/ui/gui/t-test-options.c \ src/ui/gui/t-test-options.h \ src/ui/gui/val-labs-dialog.c \ diff --git a/src/ui/gui/data-editor.ui b/src/ui/gui/data-editor.ui index ebf87c5a94..23f3ad8864 100644 --- a/src/ui/gui/data-editor.ui +++ b/src/ui/gui/data-editor.ui @@ -262,14 +262,18 @@ - + transform_recode-same + uimanager1 + FALSE Recode into _Same Variables... transform-in-to-same-variables - + + uimanager1 + TRUE transform_recode-different Recode into _Different Variables... transform-in-to-different-variables diff --git a/src/ui/gui/psppire-data-window.c b/src/ui/gui/psppire-data-window.c index 6cf3a8f617..d7b8ae6f83 100644 --- a/src/ui/gui/psppire-data-window.c +++ b/src/ui/gui/psppire-data-window.c @@ -37,7 +37,6 @@ #include "ui/gui/psppire-syntax-window.h" #include "ui/gui/psppire-window.h" #include "ui/gui/psppire.h" -#include "ui/gui/recode-dialog.h" #include "ui/syntax-gen.h" #include "gl/c-strcase.h" @@ -1041,9 +1040,6 @@ psppire_data_window_finish_init (PsppireDataWindow *de, g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de); - connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog)); - connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog)); - { GtkWidget *recent_data = gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data"); diff --git a/src/ui/gui/recode-dialog.c b/src/ui/gui/psppire-dialog-action-recode.c similarity index 67% rename from src/ui/gui/recode-dialog.c rename to src/ui/gui/psppire-dialog-action-recode.c index 4ef8ae216d..efbd6e6042 100644 --- a/src/ui/gui/recode-dialog.c +++ b/src/ui/gui/psppire-dialog-action-recode.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2007, 2009, 2010, 2011, 2012, 2014 Free Software Foundation + Copyright (C) 2007, 2009, 2010, 2011, 2012, 2014, 2016 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 @@ -14,42 +14,37 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* This module implements the RECODE dialog. - - It has two forms. One for recoding values into the same variable. - The second for recoding into different variables. -*/ #include -#include "recode-dialog.h" - -#include "executor.h" - #include "psppire-var-view.h" -#include - -#include -#include -#include +#include "psppire-dialog-action-recode.h" +#include "builder-wrapper.h" #include -#include -#include -#include "helper.h" -#include +#include "psppire-acr.h" + +#include "psppire-selector.h" #include "psppire-val-chooser.h" +#include "helper.h" #include -#include "psppire-acr.h" - #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid +/* This might need to be changed to something less naive. + In particular, what happends with dates, etc? + */ +static gchar * +num_to_string (gdouble x) +{ + return g_strdup_printf ("%.*g", DBL_DIG + 1, x); +} + /* Define a boxed type to represent a value which is a candidate to replace an existing value */ @@ -145,249 +140,17 @@ new_value_get_type (void) return t; } - -enum - { - BUTTON_NEW_VALUE, - BUTTON_NEW_COPY, - BUTTON_NEW_SYSMIS, - n_BUTTONS - }; - -struct recode_dialog -{ - PsppireDict *dict; - - GtkWidget *dialog; - PsppireDialog *old_and_new_dialog; - - GtkWidget *dict_treeview; - GtkWidget *variable_treeview; - GtkWidget *toggle[n_BUTTONS]; - - GtkWidget *strings_box; - GtkWidget *convert_button; - GtkWidget *new_copy_label; - - GtkWidget *new_value_entry; - - GtkWidget *old_value_chooser; - - GtkListStore *value_map; - - /* Indicates that the INTO {new variables} form of the dialog - is being used */ - gboolean different; - - PsppireAcr *acr; - - gboolean input_var_is_string; - - GtkWidget *new_name_entry; - GtkWidget *new_label_entry; - GtkWidget *change_button; - - GtkWidget *string_button; - GtkWidget *width_entry; - - /* A hash table of struct nlp's indexed by variable */ - GHashTable *varmap; -}; - - -static void run_old_and_new_dialog (struct recode_dialog *rd); - -static void -refresh (PsppireDialog *dialog, struct recode_dialog *rd) -{ - GtkTreeModel *vars = - gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); - - gtk_list_store_clear (GTK_LIST_STORE (vars)); - - gtk_widget_set_sensitive (rd->change_button, FALSE); - gtk_widget_set_sensitive (rd->new_name_entry, FALSE); - gtk_widget_set_sensitive (rd->new_label_entry, FALSE); - - if ( rd->different && rd->varmap ) - g_hash_table_remove_all (rd->varmap); - - gtk_list_store_clear (GTK_LIST_STORE (rd->value_map)); -} - -static char * generate_syntax (const struct recode_dialog *rd); - -enum { - COL_VALUE_OLD, - COL_VALUE_NEW, - n_COL_VALUES -}; - -/* Dialog is valid iff at least one variable has been selected, - AND the list of mappings is not empty. - */ -static gboolean -dialog_state_valid (gpointer data) -{ - GtkTreeIter not_used; - struct recode_dialog *rd = data; - - if ( ! rd->value_map ) - return FALSE; - - if ( ! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map), - ¬_used) ) - return FALSE; - - if ( rd->different ) - { - GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); - - if (g_hash_table_size (rd->varmap) != gtk_tree_model_iter_n_children (model, NULL) ) - return FALSE; - } - else - { - GtkTreeModel *vars = - gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); - - if ( !gtk_tree_model_get_iter_first (vars, ¬_used)) - return FALSE; - } - - return TRUE; -} - static void -on_old_new_show (struct recode_dialog *rd) +on_string_toggled (GtkToggleButton *b, PsppireDialogActionRecode *rd) { - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE); - - g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled"); - - g_object_set (rd->toggle[BUTTON_NEW_COPY], - "visible", rd->different, NULL); - - g_object_set (rd->new_copy_label, - "visible", rd->different, NULL); - - g_object_set (rd->strings_box, - "visible", rd->different, NULL); -} - -/* Sets the sensitivity of TARGET dependent upon the active status - of BUTTON */ -static void -toggle_sensitivity (GtkToggleButton *button, GtkWidget *target) -{ - gboolean state = gtk_toggle_button_get_active (button); - - /* g_print ("%s Setting %p (%s) to %d because of %p\n", - __FUNCTION__, target, gtk_widget_get_name (target), state, button); */ - - gtk_widget_set_sensitive (target, state); -} - -static void recode_dialog (PsppireDataWindow *de, gboolean diff); - - -/* Pops up the Recode Same version of the dialog box */ -void -recode_same_dialog (PsppireDataWindow *de) -{ - recode_dialog (de, FALSE); -} - -/* Pops up the Recode Different version of the dialog box */ -void -recode_different_dialog (PsppireDataWindow *de) -{ - recode_dialog (de, TRUE); -} - - -/* This might need to be changed to something less naive. - In particular, what happends with dates, etc? - */ -static gchar * -num_to_string (gdouble x) -{ - return g_strdup_printf ("%.*g", DBL_DIG + 1, x); -} - -/* Callback which gets called when a new row is selected - in the acr's variable treeview. - We use if to set the togglebuttons and entries to correspond to the - selected row. -*/ -static void -on_acr_selection_change (GtkTreeSelection *selection, gpointer data) -{ - struct recode_dialog *rd = data; - GtkTreeModel *model = NULL; - GtkTreeIter iter; - - GValue ov_value = {0}; - GValue nv_value = {0}; - struct old_value *ov = NULL; - struct new_value *nv = NULL; - - if ( ! gtk_tree_selection_get_selected (selection, &model, &iter) ) - return; - - - gtk_tree_model_get_value (GTK_TREE_MODEL (model), &iter, - COL_VALUE_OLD, &ov_value); - - gtk_tree_model_get_value (GTK_TREE_MODEL (model), &iter, - COL_VALUE_NEW, &nv_value); - - ov = g_value_get_boxed (&ov_value); - nv = g_value_get_boxed (&nv_value); - - if (nv) - { - switch (nv->type) - { - case NV_NUMERIC: - { - gchar *str = num_to_string (nv->v.v); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_VALUE]), TRUE); - - gtk_entry_set_text (GTK_ENTRY (rd->new_value_entry), str); - g_free (str); - } - break; - case NV_STRING: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_VALUE]), TRUE); - - gtk_entry_set_text (GTK_ENTRY (rd->new_value_entry), nv->v.s); - break; - case NV_SYSMIS: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_SYSMIS]), TRUE); - - break; - case NV_COPY: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_COPY]), TRUE); - - break; - default: - g_warning ("Invalid new value type"); - break; - } - - g_value_unset (&nv_value); - } + gboolean active; + if (! rd->input_var_is_string ) + return ; - psppire_val_chooser_set_status (PSPPIRE_VAL_CHOOSER (rd->old_value_chooser), ov); + active = gtk_toggle_button_get_active (b); + gtk_widget_set_sensitive (rd->convert_button, !active); } /* Name-Label pair */ @@ -433,7 +196,7 @@ nlp_destroy (gpointer data) static void on_selection_change (GtkTreeSelection *selection, gpointer data) { - struct recode_dialog *rd = data; + PsppireDialogActionRecode *rd = data; GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); @@ -486,20 +249,9 @@ on_selection_change (GtkTreeSelection *selection, gpointer data) g_list_free (rows); } -static void -on_string_toggled (GtkToggleButton *b, struct recode_dialog *rd) -{ - gboolean active; - if (! rd->input_var_is_string ) - return ; - - active = gtk_toggle_button_get_active (b); - gtk_widget_set_sensitive (rd->convert_button, !active); -} - static void -on_convert_toggled (GtkToggleButton *b, struct recode_dialog *rd) +on_convert_toggled (GtkToggleButton *b, PsppireDialogActionRecode *rd) { gboolean active; @@ -512,7 +264,7 @@ on_convert_toggled (GtkToggleButton *b, struct recode_dialog *rd) static void on_change_clicked (GObject *obj, gpointer data) { - struct recode_dialog *rd = data; + PsppireDialogActionRecode *rd = data; struct variable *var = NULL; struct nlp *nlp; @@ -552,7 +304,7 @@ on_change_clicked (GObject *obj, gpointer data) static void -focus_value_entry (GtkWidget *w, struct recode_dialog *rd) +focus_value_entry (GtkWidget *w, PsppireDialogActionRecode *rd) { if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) gtk_widget_grab_focus (rd->new_value_entry); @@ -562,252 +314,139 @@ focus_value_entry (GtkWidget *w, struct recode_dialog *rd) /* Callback for the new_value_entry and new_value_togglebutton widgets. It's used to enable/disable the acr. */ static void -set_acr (struct recode_dialog *rd) +set_acr (PsppireDialogActionRecode *rd) { const gchar *text; if ( !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]))) { - psppire_acr_set_enabled (rd->acr, TRUE); + psppire_acr_set_enabled (PSPPIRE_ACR (rd->acr), TRUE); return; } text = gtk_entry_get_text (GTK_ENTRY (rd->new_value_entry)); - psppire_acr_set_enabled (rd->acr, !g_str_equal (text, "")); -} - -static void -render_new_var_name (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data) -{ - struct nlp *nlp = NULL; - struct recode_dialog *rd = data; - - struct variable *var = NULL; - - gtk_tree_model_get (tree_model, iter, - 0, &var, - -1); - - nlp = g_hash_table_lookup (rd->varmap, var); - - if ( nlp ) - g_object_set (cell, "text", nlp->name, NULL); - else - g_object_set (cell, "text", "", NULL); + psppire_acr_set_enabled (PSPPIRE_ACR (rd->acr), !g_str_equal (text, "")); } +enum { + COL_VALUE_OLD, + COL_VALUE_NEW, + n_COL_VALUES +}; - -static void -recode_dialog (PsppireDataWindow *de, gboolean diff) +/* Dialog is valid iff at least one variable has been selected, + AND the list of mappings is not empty. + */ +static gboolean +dialog_state_valid (gpointer data) { - gint response; - - struct recode_dialog rd; - - GtkBuilder *builder = builder_new ("recode.ui"); - - GtkWidget *selector = get_widget_assert (builder, "psppire-selector1"); - - GtkWidget *oldandnew = get_widget_assert (builder, "button1"); - - - GtkWidget *output_variable_box = get_widget_assert (builder,"frame4"); - - rd.change_button = get_widget_assert (builder, "change-button"); - rd.varmap = NULL; - rd.dialog = get_widget_assert (builder, "recode-dialog"); - rd.dict_treeview = get_widget_assert (builder, "treeview1"); - rd.variable_treeview = get_widget_assert (builder, "treeview2"); - rd.new_name_entry = get_widget_assert (builder, "dest-name-entry"); - rd.new_label_entry = get_widget_assert (builder, "dest-label-entry"); - - g_object_get (de->data_editor, "dictionary", &rd.dict, NULL); - - rd.value_map = gtk_list_store_new (2, - old_value_get_type (), - new_value_get_type () - ); - - g_object_set (output_variable_box, "visible", diff, NULL); - - if ( diff ) - gtk_window_set_title (GTK_WINDOW (rd.dialog), - _("Recode into Different Variables")); - else - gtk_window_set_title (GTK_WINDOW (rd.dialog), - _("Recode into Same Variables")); - - rd.different = diff; + GtkTreeIter not_used; + PsppireDialogActionRecode *rd = data; - gtk_window_set_transient_for (GTK_WINDOW (rd.dialog), GTK_WINDOW (de)); + if ( ! rd->value_map ) + return FALSE; - g_object_set (rd.dict_treeview, "model", rd.dict, NULL); + if ( ! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map), + ¬_used) ) + return FALSE; - if (rd.different) + if ( rd->different ) { - GtkTreeSelection *sel; - - GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); - - GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"), - renderer, - "text", NULL, - NULL); - - gtk_tree_view_column_set_cell_data_func (col, renderer, - render_new_var_name, - &rd, NULL); - - - gtk_tree_view_append_column (GTK_TREE_VIEW (rd.variable_treeview), col); - - - col = gtk_tree_view_get_column (GTK_TREE_VIEW (rd.variable_treeview), 0); - - g_object_set (col, "title", _("Old"), NULL); - - g_object_set (rd.variable_treeview, "headers-visible", TRUE, NULL); - - rd.varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy); - - sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (rd.variable_treeview)); - - g_signal_connect (sel, "changed", - G_CALLBACK (on_selection_change), &rd); - - g_signal_connect (rd.change_button, "clicked", - G_CALLBACK (on_change_clicked), &rd); + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); + if (g_hash_table_size (rd->varmap) != gtk_tree_model_iter_n_children (model, NULL) ) + return FALSE; } - - psppire_selector_set_allow (PSPPIRE_SELECTOR (selector), homogeneous_types); - - /* Set up the Old & New Values subdialog */ - { - rd.string_button = get_widget_assert (builder, "checkbutton1"); - rd.width_entry = get_widget_assert (builder, "spinbutton1"); - - rd.convert_button = get_widget_assert (builder, "checkbutton2"); - - rd.old_value_chooser = get_widget_assert (builder, "val-chooser"); - - rd.new_value_entry = get_widget_assert (builder, "entry1"); - - - rd.toggle[BUTTON_NEW_VALUE] = get_widget_assert (builder, "radiobutton1"); - rd.toggle[BUTTON_NEW_SYSMIS] = get_widget_assert (builder, "radiobutton2"); - rd.toggle[BUTTON_NEW_COPY] = get_widget_assert (builder, "radiobutton3"); - - rd.new_copy_label = get_widget_assert (builder, "label3"); - rd.strings_box = get_widget_assert (builder, "table3"); - - rd.old_and_new_dialog = - PSPPIRE_DIALOG (get_widget_assert (builder, "old-new-values-dialog")); - - gtk_window_set_transient_for (GTK_WINDOW (rd.old_and_new_dialog), - GTK_WINDOW (de)); - - rd.acr = PSPPIRE_ACR (get_widget_assert (builder, "psppire-acr1")); - - g_signal_connect_swapped (rd.toggle[BUTTON_NEW_VALUE], "toggled", - G_CALLBACK (set_acr), &rd); - - g_signal_connect_after (rd.toggle[BUTTON_NEW_VALUE], "toggled", - G_CALLBACK (focus_value_entry), &rd); - - g_signal_connect_swapped (rd.new_value_entry, "changed", - G_CALLBACK (set_acr), &rd); - + else { - GtkTreeSelection *sel; - /* Remove the ACR's default column. We don't like it */ - GtkTreeViewColumn *column = gtk_tree_view_get_column (rd.acr->tv, 0); - gtk_tree_view_remove_column (rd.acr->tv, column); - - - column = - gtk_tree_view_column_new_with_attributes (_("Old"), - gtk_cell_renderer_text_new (), - "text", 0, - NULL); - - gtk_tree_view_append_column (rd.acr->tv, column); + GtkTreeModel *vars = + gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); - column = - gtk_tree_view_column_new_with_attributes (_("New"), - gtk_cell_renderer_text_new (), - "text", 1, - NULL); + if ( !gtk_tree_model_get_iter_first (vars, ¬_used)) + return FALSE; + } - gtk_tree_view_append_column (rd.acr->tv, column); - g_object_set (rd.acr->tv, "headers-visible", TRUE, NULL); + return TRUE; +} - sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (rd.acr->tv)); - g_signal_connect (sel, "changed", - G_CALLBACK (on_acr_selection_change), &rd); - } +/* Callback which gets called when a new row is selected + in the acr's variable treeview. + We use if to set the togglebuttons and entries to correspond to the + selected row. +*/ +static void +on_acr_selection_change (GtkTreeSelection *selection, gpointer data) +{ + PsppireDialogActionRecode *rd = data; + GtkTreeModel *model = NULL; + GtkTreeIter iter; + GValue ov_value = {0}; + GValue nv_value = {0}; + struct old_value *ov = NULL; + struct new_value *nv = NULL; - g_signal_connect_swapped (oldandnew, "clicked", - G_CALLBACK (run_old_and_new_dialog), &rd); + if ( ! gtk_tree_selection_get_selected (selection, &model, &iter) ) + return; - g_signal_connect (rd.toggle[BUTTON_NEW_VALUE], "toggled", - G_CALLBACK (toggle_sensitivity), rd.new_value_entry); + gtk_tree_model_get_value (GTK_TREE_MODEL (model), &iter, + COL_VALUE_OLD, &ov_value); - g_signal_connect (rd.string_button, "toggled", - G_CALLBACK (toggle_sensitivity), rd.width_entry); + gtk_tree_model_get_value (GTK_TREE_MODEL (model), &iter, + COL_VALUE_NEW, &nv_value); - g_signal_connect (rd.string_button, "toggled", - G_CALLBACK (on_string_toggled), &rd); + ov = g_value_get_boxed (&ov_value); + nv = g_value_get_boxed (&nv_value); - g_signal_connect (rd.convert_button, "toggled", - G_CALLBACK (on_convert_toggled), &rd); + if (nv) + { + switch (nv->type) + { + case NV_NUMERIC: + { + gchar *str = num_to_string (nv->v.v); - g_signal_connect_swapped (rd.old_and_new_dialog, "show", - G_CALLBACK (on_old_new_show), &rd); - } + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_VALUE]), TRUE); - g_signal_connect (rd.dialog, "refresh", G_CALLBACK (refresh), &rd); + gtk_entry_set_text (GTK_ENTRY (rd->new_value_entry), str); + g_free (str); + } + break; + case NV_STRING: + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_VALUE]), TRUE); + gtk_entry_set_text (GTK_ENTRY (rd->new_value_entry), nv->v.s); + break; + case NV_SYSMIS: + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_SYSMIS]), TRUE); - psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (rd.dialog), - dialog_state_valid, &rd); + break; + case NV_COPY: + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_COPY]), TRUE); - response = psppire_dialog_run (PSPPIRE_DIALOG (rd.dialog)); + break; + default: + g_warning ("Invalid new value type"); + break; + } - switch (response) - { - case GTK_RESPONSE_OK: - g_free (execute_syntax_string (de, generate_syntax (&rd))); - break; - case PSPPIRE_RESPONSE_PASTE: - g_free (paste_syntax_to_window (generate_syntax (&rd))); - break; - default: - break; + g_value_unset (&nv_value); } - if (rd.varmap) - g_hash_table_destroy (rd.varmap); - - gtk_list_store_clear (GTK_LIST_STORE (rd.value_map)); - g_object_unref (rd.value_map); - - g_object_unref (builder); + psppire_val_chooser_set_status (PSPPIRE_VAL_CHOOSER (rd->old_value_chooser), ov); } /* Initialise VAL to reflect the current status of RD */ static gboolean -set_old_value (GValue *val, const struct recode_dialog *rd) +set_old_value (GValue *val, const PsppireDialogActionRecode *rd) { PsppireValChooser *vc = PSPPIRE_VAL_CHOOSER (rd->old_value_chooser); @@ -824,7 +463,7 @@ set_old_value (GValue *val, const struct recode_dialog *rd) /* Initialse VAL to reflect the current status of RD */ static gboolean -set_new_value (GValue *val, const struct recode_dialog *rd) +set_new_value (GValue *val, const PsppireDialogActionRecode *rd) { const gchar *text = NULL; struct new_value nv; @@ -870,12 +509,11 @@ set_new_value (GValue *val, const struct recode_dialog *rd) return TRUE; } - /* A function to set a value in a column in the ACR */ static gboolean set_value (gint col, GValue *val, gpointer data) { - struct recode_dialog *rd = data; + PsppireDialogActionRecode *rd = data; switch ( col ) { @@ -893,13 +531,14 @@ set_value (gint col, GValue *val, gpointer data) } static void -run_old_and_new_dialog (struct recode_dialog *rd) +run_old_and_new_dialog (PsppireDialogActionRecode *rd) { gint response; GtkListStore *local_store = clone_list_store (rd->value_map); + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (rd); - psppire_acr_set_model (rd->acr, local_store); - psppire_acr_set_get_value_func (rd->acr, set_value, rd); + psppire_acr_set_model (PSPPIRE_ACR (rd->acr), local_store); + psppire_acr_set_get_value_func (PSPPIRE_ACR (rd->acr), set_value, rd); gtk_window_set_title (GTK_WINDOW (rd->old_and_new_dialog), rd->different @@ -934,7 +573,7 @@ run_old_and_new_dialog (struct recode_dialog *rd) response = psppire_dialog_run (rd->old_and_new_dialog); - psppire_acr_set_model (rd->acr, NULL); + psppire_acr_set_model (PSPPIRE_ACR (rd->acr), NULL); if ( response == PSPPIRE_RESPONSE_CONTINUE ) @@ -946,10 +585,271 @@ run_old_and_new_dialog (struct recode_dialog *rd) g_object_unref (local_store); - psppire_dialog_notify_change (PSPPIRE_DIALOG (rd->dialog)); + psppire_dialog_notify_change (PSPPIRE_DIALOG (pda->dialog)); +} + +static void +on_old_new_show (PsppireDialogActionRecode *rd) +{ + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE); + + g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled"); + + g_object_set (rd->toggle[BUTTON_NEW_COPY], + "visible", rd->different, NULL); + + g_object_set (rd->new_copy_label, + "visible", rd->different, NULL); + + g_object_set (rd->strings_box, + "visible", rd->different, NULL); +} + + +/* Sets the sensitivity of TARGET dependent upon the active status + of BUTTON */ +static void +toggle_sensitivity (GtkToggleButton *button, GtkWidget *target) +{ + gboolean state = gtk_toggle_button_get_active (button); + + /* g_print ("%s Setting %p (%s) to %d because of %p\n", + __FUNCTION__, target, gtk_widget_get_name (target), state, button); */ + + gtk_widget_set_sensitive (target, state); +} + +static void +render_new_var_name (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + struct nlp *nlp = NULL; + PsppireDialogActionRecode *rd = data; + + struct variable *var = NULL; + + gtk_tree_model_get (tree_model, iter, + 0, &var, + -1); + + nlp = g_hash_table_lookup (rd->varmap, var); + + if ( nlp ) + g_object_set (cell, "text", nlp->name, NULL); + else + g_object_set (cell, "text", "", NULL); +} + + + + + +static void +psppire_dialog_action_recode_class_init (PsppireDialogActionRecodeClass *class); + +G_DEFINE_TYPE (PsppireDialogActionRecode, psppire_dialog_action_recode, PSPPIRE_TYPE_DIALOG_ACTION); + +static void +refresh (PsppireDialogAction *rd_) +{ + PsppireDialogActionRecode *rd = PSPPIRE_DIALOG_ACTION_RECODE (rd_); + + GtkTreeModel *vars = + gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview)); + + gtk_list_store_clear (GTK_LIST_STORE (vars)); + + gtk_widget_set_sensitive (rd->change_button, FALSE); + gtk_widget_set_sensitive (rd->new_name_entry, FALSE); + gtk_widget_set_sensitive (rd->new_label_entry, FALSE); + + if ( rd->different && rd->varmap ) + g_hash_table_remove_all (rd->varmap); + + gtk_list_store_clear (GTK_LIST_STORE (rd->value_map)); } + +static void +psppire_dialog_action_recode_activate (PsppireDialogAction *a) +{ + PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a); + PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a); + + GHashTable *thing = psppire_dialog_action_get_hash_table (pda); + GtkBuilder *xml = g_hash_table_lookup (thing, a); + if (!xml) + { + xml = builder_new ("recode.ui"); + g_hash_table_insert (thing, a, xml); + + pda->dialog = get_widget_assert (xml, "recode-dialog"); + pda->source = get_widget_assert (xml, "treeview1"); + + + GtkWidget *selector = get_widget_assert (xml, "psppire-selector1"); + GtkWidget *oldandnew = get_widget_assert (xml, "button1"); + + + GtkWidget *output_variable_box = get_widget_assert (xml,"frame4"); + + act->change_button = get_widget_assert (xml, "change-button"); + act->varmap = NULL; + act->variable_treeview = get_widget_assert (xml, "treeview2"); + act->new_name_entry = get_widget_assert (xml, "dest-name-entry"); + act->new_label_entry = get_widget_assert (xml, "dest-label-entry"); + + act->value_map = gtk_list_store_new (2, + old_value_get_type (), + new_value_get_type ()); + + if (act->different) + gtk_window_set_title (GTK_WINDOW (pda->dialog), + _("Recode into Different Variables")); + else + gtk_window_set_title (GTK_WINDOW (pda->dialog), + _("Recode into Same Variables")); + + g_object_set (output_variable_box, "visible", act->different, NULL); + + if (act->different) + { + GtkTreeSelection *sel; + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + + GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"), + renderer, + "text", NULL, + NULL); + + gtk_tree_view_column_set_cell_data_func (col, renderer, + render_new_var_name, + act, NULL); + + + gtk_tree_view_append_column (GTK_TREE_VIEW (act->variable_treeview), col); + + + col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->variable_treeview), 0); + + g_object_set (col, "title", _("Old"), NULL); + + g_object_set (act->variable_treeview, "headers-visible", TRUE, NULL); + + act->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy); + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->variable_treeview)); + + g_signal_connect (sel, "changed", + G_CALLBACK (on_selection_change), act); + + g_signal_connect (act->change_button, "clicked", + G_CALLBACK (on_change_clicked), act); + } + + + psppire_selector_set_allow (PSPPIRE_SELECTOR (selector), homogeneous_types); + + /* Set up the Old & New Values subdialog */ + { + act->string_button = get_widget_assert (xml, "checkbutton1"); + act->width_entry = get_widget_assert (xml, "spinbutton1"); + + act->convert_button = get_widget_assert (xml, "checkbutton2"); + + act->old_value_chooser = get_widget_assert (xml, "val-chooser"); + + act->new_value_entry = get_widget_assert (xml, "entry1"); + + + act->toggle[BUTTON_NEW_VALUE] = get_widget_assert (xml, "radiobutton1"); + act->toggle[BUTTON_NEW_SYSMIS] = get_widget_assert (xml, "radiobutton2"); + act->toggle[BUTTON_NEW_COPY] = get_widget_assert (xml, "radiobutton3"); + + act->new_copy_label = get_widget_assert (xml, "label3"); + act->strings_box = get_widget_assert (xml, "table3"); + + act->old_and_new_dialog = + PSPPIRE_DIALOG (get_widget_assert (xml, "old-new-values-dialog")); + + act->acr = get_widget_assert (xml, "psppire-acr1"); + + g_signal_connect_swapped (act->toggle[BUTTON_NEW_VALUE], "toggled", + G_CALLBACK (set_acr), act); + + g_signal_connect_after (act->toggle[BUTTON_NEW_VALUE], "toggled", + G_CALLBACK (focus_value_entry), act); + + g_signal_connect_swapped (act->new_value_entry, "changed", + G_CALLBACK (set_acr), act); + + { + GtkTreeSelection *sel; + /* Remove the ACR's default column. We don't like it */ + GtkTreeViewColumn *column = gtk_tree_view_get_column (PSPPIRE_ACR(act->acr)->tv, 0); + gtk_tree_view_remove_column (PSPPIRE_ACR (act->acr)->tv, column); + + + column = + gtk_tree_view_column_new_with_attributes (_("Old"), + gtk_cell_renderer_text_new (), + "text", 0, + NULL); + + gtk_tree_view_append_column (PSPPIRE_ACR (act->acr)->tv, column); + + column = + gtk_tree_view_column_new_with_attributes (_("New"), + gtk_cell_renderer_text_new (), + "text", 1, + NULL); + + gtk_tree_view_append_column (PSPPIRE_ACR(act->acr)->tv, column); + g_object_set (PSPPIRE_ACR (act->acr)->tv, "headers-visible", TRUE, NULL); + + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (PSPPIRE_ACR(act->acr)->tv)); + g_signal_connect (sel, "changed", + G_CALLBACK (on_acr_selection_change), act); + } + + + g_signal_connect_swapped (oldandnew, "clicked", + G_CALLBACK (run_old_and_new_dialog), act); + + + g_signal_connect (act->toggle[BUTTON_NEW_VALUE], "toggled", + G_CALLBACK (toggle_sensitivity), act->new_value_entry); + + g_signal_connect (act->string_button, "toggled", + G_CALLBACK (toggle_sensitivity), act->width_entry); + + g_signal_connect (act->string_button, "toggled", + G_CALLBACK (on_string_toggled), act); + + g_signal_connect (act->convert_button, "toggled", + G_CALLBACK (on_convert_toggled), act); + + g_signal_connect_swapped (act->old_and_new_dialog, "show", + G_CALLBACK (on_old_new_show), act); + } + } + + psppire_dialog_action_set_refresh (pda, refresh); + + psppire_dialog_action_set_valid_predicate (pda, + dialog_state_valid); + + if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_parent_class)->activate) + PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_parent_class)->activate (pda); +} + /* Generate a syntax fragment for NV and append it to STR */ static void new_value_append_syntax (struct string *dds, const struct new_value *nv) @@ -976,9 +876,8 @@ new_value_append_syntax (struct string *dds, const struct new_value *nv) } } - static char * -generate_syntax (const struct recode_dialog *rd) +generate_syntax (const PsppireDialogActionRecode *rd) { gboolean ok; GtkTreeIter iter; @@ -1105,3 +1004,82 @@ generate_syntax (const struct recode_dialog *rd) return text; } + + +enum +{ + PROP_0, + PROP_DIFF +}; + +static void +__set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (object); + + switch (prop_id) + { + case PROP_DIFF: + act->different = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + }; +} + + +static void +__get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (object); + + switch (prop_id) + { + case PROP_DIFF: + g_value_set_boolean (value, act->different); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + }; +} + + +static void +psppire_dialog_action_recode_class_init (PsppireDialogActionRecodeClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + psppire_dialog_action_set_activation (class, psppire_dialog_action_recode_activate); + + PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax; + + GParamSpec *diff_spec = + g_param_spec_boolean ("recode-to-new-variable", + "Recode to New Variable", + "True iff the new values should be placed in a new variable", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + + object_class->set_property = __set_property; + object_class->get_property = __get_property; + + g_object_class_install_property (object_class, + PROP_DIFF, + diff_spec); +} + + +static void +psppire_dialog_action_recode_init (PsppireDialogActionRecode *act) +{ +} + diff --git a/src/ui/gui/psppire-dialog-action-recode.h b/src/ui/gui/psppire-dialog-action-recode.h new file mode 100644 index 0000000000..37d18d5c46 --- /dev/null +++ b/src/ui/gui/psppire-dialog-action-recode.h @@ -0,0 +1,113 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 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 "psppire-dialog-action.h" + +#ifndef __PSPPIRE_DIALOG_ACTION_RECODE_H__ +#define __PSPPIRE_DIALOG_ACTION_RECODE_H__ + +G_BEGIN_DECLS + +enum + { + BUTTON_NEW_VALUE, + BUTTON_NEW_COPY, + BUTTON_NEW_SYSMIS, + n_BUTTONS + }; + +#define PSPPIRE_TYPE_DIALOG_ACTION_RECODE (psppire_dialog_action_recode_get_type ()) + +#define PSPPIRE_DIALOG_ACTION_RECODE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + PSPPIRE_TYPE_DIALOG_ACTION_RECODE, PsppireDialogActionRecode)) + +#define PSPPIRE_DIALOG_ACTION_RECODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + PSPPIRE_TYPE_DIALOG_ACTION_RECODE, \ + PsppireDialogActionRecodeClass)) + + +#define PSPPIRE_IS_DIALOG_ACTION_RECODE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_RECODE)) + +#define PSPPIRE_IS_DIALOG_ACTION_RECODE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_RECODE)) + + +#define PSPPIRE_DIALOG_ACTION_RECODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + PSPPIRE_TYPE_DIALOG_ACTION_RECODE, \ + PsppireDialogActionRecodeClass)) + +typedef struct _PsppireDialogActionRecode PsppireDialogActionRecode; +typedef struct _PsppireDialogActionRecodeClass PsppireDialogActionRecodeClass; + + +struct _PsppireDialogActionRecode +{ + PsppireDialogAction parent; + + PsppireDialog *old_and_new_dialog; + + GtkWidget *dict_treeview; + GtkWidget *variable_treeview; + GtkWidget *toggle[n_BUTTONS]; + + GtkWidget *strings_box; + GtkWidget *convert_button; + GtkWidget *new_copy_label; + + GtkWidget *new_value_entry; + + GtkWidget *old_value_chooser; + + GtkListStore *value_map; + + /* Indicates that the INTO {new variables} form of the dialog + is being used */ + gboolean different; + + GtkWidget *acr; + + gboolean input_var_is_string; + + GtkWidget *new_name_entry; + GtkWidget *new_label_entry; + GtkWidget *change_button; + + GtkWidget *string_button; + GtkWidget *width_entry; + + /* A hash table of struct nlp's indexed by variable */ + GHashTable *varmap; +}; + + +struct _PsppireDialogActionRecodeClass +{ + PsppireDialogActionClass parent_class; +}; + + +GType psppire_dialog_action_recode_get_type (void) ; + +G_END_DECLS + +#endif /* __PSPPIRE_DIALOG_ACTION_RECODE_H__ */ diff --git a/src/ui/gui/recode-dialog.h b/src/ui/gui/recode-dialog.h deleted file mode 100644 index 03e4a348e0..0000000000 --- a/src/ui/gui/recode-dialog.h +++ /dev/null @@ -1,26 +0,0 @@ -/* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2007 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 __RECODE_DIALOG_H -#define __RECODE_DIALOG_H - - -#include "psppire-data-window.h" - -void recode_same_dialog (PsppireDataWindow * data); -void recode_different_dialog (PsppireDataWindow * data); - -#endif diff --git a/src/ui/gui/recode.ui b/src/ui/gui/recode.ui index 954023454e..c25065f5e1 100644 --- a/src/ui/gui/recode.ui +++ b/src/ui/gui/recode.ui @@ -372,6 +372,7 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Recode into Same Variables True + RECODE True diff --git a/src/ui/gui/widgets.c b/src/ui/gui/widgets.c index 78e67382da..488ec94e1a 100644 --- a/src/ui/gui/widgets.c +++ b/src/ui/gui/widgets.c @@ -42,6 +42,7 @@ #include "psppire-dialog-action-oneway.h" #include "psppire-means-layer.h" #include "psppire-dialog-action-rank.h" +#include "psppire-dialog-action-recode.h" #include "psppire-dialog-action-regression.h" #include "psppire-dialog-action-reliability.h" #include "psppire-dialog-action-roc.h" @@ -90,6 +91,7 @@ static const get_type_func dialog_action_types[]= psppire_dialog_action_indep_samps_get_type, psppire_dialog_action_var_info_get_type, psppire_dialog_action_rank_get_type, + psppire_dialog_action_recode_get_type, psppire_dialog_action_reliability_get_type, psppire_dialog_action_regression_get_type, psppire_dialog_action_roc_get_type, -- 2.30.2