X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-import-assistant.c;h=635941c2d25d55e72be412e4d9c0fad835fe5e6f;hb=0931dbb924b98df79989e2b4017f538f2ab6b23c;hp=ab959211c0a399b52cbfb85df3c06e4499cba34b;hpb=400c90fe0e7684dac41663389f2060d19c0667d0;p=pspp diff --git a/src/ui/gui/psppire-import-assistant.c b/src/ui/gui/psppire-import-assistant.c index ab959211c0..635941c2d2 100644 --- a/src/ui/gui/psppire-import-assistant.c +++ b/src/ui/gui/psppire-import-assistant.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2015, 2016, 2017 Free Software Foundation + Copyright (C) 2015, 2016, 2017, 2018, 2020 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 @@ -127,6 +127,9 @@ psppire_import_assistant_finalize (GObject *object) ds_destroy (&ia->quotes); + dict_unref (ia->dict); + dict_unref (ia->casereader_dict); + g_object_unref (ia->builder); ia->response = -1; @@ -298,7 +301,8 @@ choose_likely_separators (PsppireImportAssistant *ia) hmap_destroy (&count_map[j]); } - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->builder, separators[most_frequent].name)), TRUE); + const char* sepname = separators[MAX (0,most_frequent)].name; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->builder, sepname)), TRUE); } static void @@ -311,7 +315,8 @@ repopulate_delimiter_columns (PsppireImportAssistant *ia) gtk_tree_view_remove_column (GTK_TREE_VIEW (ia->fields_tree_view), tvc); } - gint n_fields = gtk_tree_model_get_n_columns (ia->delimiters_model); + gint n_fields = + gtk_tree_model_get_n_columns (GTK_TREE_MODEL (ia->delimiters_model)); /* ... and put them back again. */ gint f; @@ -371,9 +376,10 @@ reset_tree_view_model (PsppireImportAssistant *ia) static void prepare_separators_page (PsppireImportAssistant *ia, GtkWidget *page) { - gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), ia->delimiters_model); + gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), + GTK_TREE_MODEL (ia->delimiters_model)); - g_signal_connect_swapped (ia->delimiters_model, "notify::delimiters", + g_signal_connect_swapped (GTK_TREE_MODEL (ia->delimiters_model), "notify::delimiters", G_CALLBACK (reset_tree_view_model), ia); @@ -725,6 +731,8 @@ psppire_import_assistant_init (PsppireImportAssistant *ia) ia->file_name = NULL; ia->spreadsheet = NULL; + ia->dict = NULL; + ia->casereader_dict = NULL; ia->main_loop = g_main_loop_new (NULL, TRUE); @@ -821,7 +829,6 @@ render_text_preview_line (GtkTreeViewColumn *tree_column, Set the text to a "insensitive" state if the row is greater than what the user declared to be the maximum. */ - PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (data); GtkTreePath *path = gtk_tree_model_get_path (tree_model, iter); gint *ii = gtk_tree_path_get_indices (path); gint max_lines; @@ -1021,34 +1028,6 @@ psppire_import_assistant_new (GtkWindow *toplevel) -static void -set_quote_list (GtkComboBox *cb) -{ - GtkListStore *list = gtk_list_store_new (1, G_TYPE_STRING); - GtkTreeIter iter; - gint i; - const gchar *separator[3] = {"'\"", "\'", "\""}; - - for (i = 0; i < 3; i++) - { - const gchar *s = separator[i]; - - /* Add a new row to the model */ - gtk_list_store_append (list, &iter); - gtk_list_store_set (list, &iter, - 0, s, - -1); - - } - - gtk_combo_box_set_model (GTK_COMBO_BOX (cb), GTK_TREE_MODEL (list)); - g_object_unref (list); - - gtk_combo_box_set_entry_text_column (cb, 0); -} - - - /* Chooses a name for each column on the separators page */ static void choose_column_names (PsppireImportAssistant *ia) @@ -1057,7 +1036,9 @@ choose_column_names (PsppireImportAssistant *ia) unsigned long int generated_name_count = 0; dict_clear (ia->dict); - for (i = 0; i < gtk_tree_model_get_n_columns (ia->delimiters_model) - 1; ++i) + for (i = 0; + i < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (ia->delimiters_model)) - 1; + ++i) { const gchar *candidate_name = NULL; @@ -1075,8 +1056,6 @@ choose_column_names (PsppireImportAssistant *ia) } } - - /* Called when the user toggles one of the separators checkboxes. */ static void @@ -1158,10 +1137,9 @@ separators_page_create (PsppireImportAssistant *ia) ia->custom_cb = get_widget_assert (builder, "custom-cb"); ia->custom_entry = get_widget_assert (builder, "custom-entry"); ia->quote_combo = get_widget_assert (builder, "quote-combo"); - ia->quote_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (ia->quote_combo))); ia->quote_cb = get_widget_assert (builder, "quote-cb"); - set_quote_list (GTK_COMBO_BOX (ia->quote_combo)); + gtk_combo_box_set_active (GTK_COMBO_BOX (ia->quote_combo), 0); if (ia->fields_tree_view == NULL) { @@ -1214,12 +1192,19 @@ my_read (struct casereader *reader, void *aux, casenumber idx) GValue value = {0}; gtk_tree_model_get_value (tm, &iter, i + 1, &value); - const struct variable *var = dict_get_var (ia->dict, i); + const struct variable *var = dict_get_var (ia->casereader_dict, i); const gchar *ss = g_value_get_string (&value); if (ss) { union value *v = case_data_rw (c, var); + /* In this reader we derive the union value from the + string in the tree_model. We retrieve the width and format + from a dictionary which is stored directly after + the reader creation. Changes in ia->dict in the + variable window are not reflected here and therefore + this is always compatible with the width in the + caseproto. See bug #58298 */ char *xx = data_in (ss_cstr (ss), "UTF-8", var_get_write_format (var)->type, @@ -1250,75 +1235,39 @@ my_advance (struct casereader *reader, void *aux, casenumber cnt) g_print ("%s:%d\n", __FILE__, __LINE__); } -static void -foo (struct dictionary *dict, void *aux) -{ - PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (aux); - g_print ("%s:%d\n", __FILE__, __LINE__); - - struct caseproto *proto = caseproto_create (); - - int i; - for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i) - { - const struct variable *var = dict_get_var (ia->dict, i); - proto = caseproto_add_width (proto, var_get_width (var)); - } - - - gint n_rows = gtk_tree_model_iter_n_children (ia->delimiters_model, NULL); - - struct casereader *reader = - casereader_create_random (proto, n_rows, &my_casereader_class, ia); - - - PsppireDataStore *store = NULL; - - g_object_get (ia->data_sheet, "data-model", &store, NULL); - - psppire_data_store_set_reader (store, reader); -} - -/* Called just before the formats page of the assistant is - displayed. */ -static void -prepare_formats_page (PsppireImportAssistant *ia) +static struct casereader * +textfile_create_reader (PsppireImportAssistant *ia) { - PsppireDict *dict = psppire_dict_new_from_dict (ia->dict); - g_object_set (ia->var_sheet, "data-model", dict, NULL); - - my_casereader_class.read = my_read; - my_casereader_class.destroy = my_destroy; - my_casereader_class.advance = my_advance; + int n_vars = dict_get_var_cnt (ia->dict); - struct caseproto *proto = caseproto_create (); int i; - struct fmt_guesser **fg = xcalloc (sizeof *fg, dict_get_var_cnt (ia->dict)); - for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i) + struct fmt_guesser **fg = xcalloc (n_vars, sizeof *fg); + for (i = 0 ; i < n_vars; ++i) { fg[i] = fmt_guesser_create (); } - gint n_rows = gtk_tree_model_iter_n_children (ia->delimiters_model, NULL); + gint n_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (ia->delimiters_model), NULL); GtkTreeIter iter; gboolean ok; - for (ok = gtk_tree_model_get_iter_first (ia->delimiters_model, &iter); + for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ia->delimiters_model), &iter); ok; - ok = gtk_tree_model_iter_next (ia->delimiters_model, &iter)) + ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->delimiters_model), &iter)) { - for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i) + for (i = 0 ; i < n_vars; ++i) { gchar *s = NULL; - gtk_tree_model_get (ia->delimiters_model, &iter, i+1, &s, -1); + gtk_tree_model_get (GTK_TREE_MODEL (ia->delimiters_model), &iter, i+1, &s, -1); if (s) fmt_guesser_add (fg[i], ss_cstr (s)); free (s); } } - for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i) + struct caseproto *proto = caseproto_create (); + for (i = 0 ; i < n_vars; ++i) { struct fmt_spec fs; fmt_guesser_guess (fg[i], &fs); @@ -1338,16 +1287,94 @@ prepare_formats_page (PsppireImportAssistant *ia) free (fg); - // dict_set_change_callback (ia->dict, foo, ia); + struct casereader *cr = casereader_create_random (proto, n_rows, &my_casereader_class, ia); + /* Store the dictionary at this point when the casereader is created. + my_read depends on the dictionary to interpret the strings in the treeview. + This guarantees that the union value is produced according to the + caseproto in the reader. */ + ia->casereader_dict = dict_clone (ia->dict); + caseproto_unref (proto); + return cr; +} + +/* When during import the variable type is changed, the reader is reinitialized + based on the new dictionary with a fresh caseprototype. The default behaviour + when a variable type is changed and the column is resized is that the union + value is interpreted with new variable type and an overlay for that column + is generated. Here we reinit to the original reader based on strings. + As a result you can switch from string to numeric to string without loosing + the string information. */ +static void +ia_variable_changed_cb (GObject *obj, gint var_num, guint what, + const struct variable *oldvar, gpointer data) +{ + PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (data); - struct casereader *reader = - casereader_create_random (proto, n_rows, &my_casereader_class, ia); + struct caseproto *proto = caseproto_create(); + for (int i = 0; i < dict_get_var_cnt (ia->dict); i++) + { + const struct variable *var = dict_get_var (ia->dict, i); + int width = var_get_width (var); + proto = caseproto_add_width (proto, width); + } + + gint n_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (ia->delimiters_model), NULL); + + PsppireDataStore *store = NULL; + g_object_get (ia->data_sheet, "data-model", &store, NULL); + + struct casereader *cr = casereader_create_random (proto, n_rows, + &my_casereader_class, ia); + psppire_data_store_set_reader (store, cr); + dict_unref (ia->casereader_dict); + ia->casereader_dict = dict_clone (ia->dict); +} + +/* Called just before the formats page of the assistant is + displayed. */ +static void +prepare_formats_page (PsppireImportAssistant *ia) +{ + my_casereader_class.read = my_read; + my_casereader_class.destroy = my_destroy; + my_casereader_class.advance = my_advance; - PsppireDataStore *store = psppire_data_store_new (dict); - psppire_data_store_set_reader (store, reader); + if (ia->spreadsheet) + { + GtkBuilder *builder = ia->builder; + GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry"); + GtkWidget *rnc = get_widget_assert (builder, "readnames-checkbox"); + GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry"); + + struct spreadsheet_read_options opts; + opts.sheet_name = NULL; + opts.sheet_index = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)) + 1; + opts.read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rnc)); + opts.cell_range = g_strdup (gtk_entry_get_text (GTK_ENTRY (range_entry))); + opts.asw = 8; + + struct casereader *reader = spreadsheet_make_reader (ia->spreadsheet, &opts); + + PsppireDict *dict = psppire_dict_new_from_dict (ia->spreadsheet->dict); + PsppireDataStore *store = psppire_data_store_new (dict); + psppire_data_store_set_reader (store, reader); + g_object_set (ia->data_sheet, "data-model", store, NULL); + g_object_set (ia->var_sheet, "data-model", dict, NULL); + } + else + { + struct casereader *reader = textfile_create_reader (ia); - g_object_set (ia->data_sheet, "data-model", store, NULL); + PsppireDict *dict = psppire_dict_new_from_dict (ia->dict); + PsppireDataStore *store = psppire_data_store_new (dict); + psppire_data_store_set_reader (store, reader); + g_signal_connect (dict, "variable-changed", + G_CALLBACK (ia_variable_changed_cb), + ia); + g_object_set (ia->data_sheet, "data-model", store, NULL); + g_object_set (ia->var_sheet, "data-model", dict, NULL); + } gint pmax; g_object_get (get_widget_assert (ia->builder, "vpaned1"), @@ -1384,6 +1411,7 @@ formats_page_create (PsppireImportAssistant *ia) if (ia->data_sheet == NULL) { ia->data_sheet = psppire_data_sheet_new (); + g_object_set (ia->data_sheet, "editable", FALSE, NULL); gtk_container_add (GTK_CONTAINER (data_scroller), ia->data_sheet); @@ -1419,8 +1447,15 @@ separators_append_syntax (const PsppireImportAssistant *ia, struct string *s) } } ds_put_cstr (s, "\"\n"); - if (!ds_is_empty (&ia->quotes)) - syntax_gen_pspp (s, " /QUALIFIER=%sq\n", ds_cstr (&ia->quotes)); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->quote_cb))) + { + GtkComboBoxText *cbt = GTK_COMBO_BOX_TEXT (ia->quote_combo); + gchar *quotes = gtk_combo_box_text_get_active_text (cbt); + if (quotes && *quotes) + syntax_gen_pspp (s, " /QUALIFIER=%sq\n", quotes); + free (quotes); + } } static void @@ -1552,8 +1587,8 @@ apply_dict (const struct dictionary *dict, struct string *s) -static char * -sheet_spec_gen_syntax (PsppireImportAssistant *ia) +static void +sheet_spec_gen_syntax (PsppireImportAssistant *ia, struct string *s) { GtkBuilder *builder = ia->builder; GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry"); @@ -1563,11 +1598,13 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia) int sheet_index = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (sheet_entry)); gboolean read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rnc)); - struct string s = DS_EMPTY_INITIALIZER; char *filename; - g_object_get (ia->text_file, "file-name", &filename, NULL); - syntax_gen_pspp (&s, + if (ia->spreadsheet) + filename = ia->spreadsheet->file_name; + else + g_object_get (ia->text_file, "file-name", &filename, NULL); + syntax_gen_pspp (s, "GET DATA" "\n /TYPE=%ss" "\n /FILE=%sq" @@ -1580,20 +1617,17 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia) if (range && 0 != strcmp ("", range)) { - syntax_gen_pspp (&s, + syntax_gen_pspp (s, "\n /CELLRANGE=RANGE %sq", range); } else { - syntax_gen_pspp (&s, + syntax_gen_pspp (s, "\n /CELLRANGE=FULL"); } - syntax_gen_pspp (&s, "."); - - - return ds_cstr (&s); + syntax_gen_pspp (s, ".\n"); } @@ -1635,7 +1669,7 @@ psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia) } else { - return sheet_spec_gen_syntax (ia); + sheet_spec_gen_syntax (ia, &s); } return ds_cstr (&s); @@ -1648,4 +1682,3 @@ psppire_import_assistant_run (PsppireImportAssistant *asst) g_main_loop_run (asst->main_loop); return asst->response; } -