/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2015, 2016, 2017, 2018 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
ds_destroy (&ia->quotes);
+ dict_unref (ia->dict);
+ dict_unref (ia->casereader_dict);
+
g_object_unref (ia->builder);
ia->response = -1;
}
gtk_tree_path_free (p);
- int most_frequent = -1;
- int largest = 0;
- for (j = 0; j < SEPARATOR_CNT; ++j)
+ if (hmap_count (count_map) > 0)
{
- struct separator_count_node *cn;
- HMAP_FOR_EACH (cn, struct separator_count_node, node, &count_map[j])
- {
- if (largest < cn->quantity)
- {
- largest = cn->quantity;
- most_frequent = j;
- }
- }
- hmap_destroy (&count_map[j]);
- }
+ int most_frequent = -1;
+ int largest = 0;
+ for (j = 0; j < SEPARATOR_CNT; ++j)
+ {
+ struct separator_count_node *cn;
+ HMAP_FOR_EACH (cn, struct separator_count_node, node, &count_map[j])
+ {
+ if (largest < cn->quantity)
+ {
+ largest = cn->quantity;
+ most_frequent = j;
+ }
+ }
+ hmap_destroy (&count_map[j]);
+ }
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->builder, separators[most_frequent].name)), TRUE);
+ g_return_if_fail (most_frequent >= 0);
+
+ GtkWidget *toggle =
+ get_widget_assert (ia->builder, separators[most_frequent].name);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), TRUE);
+ }
}
static void
ia->file_name = NULL;
ia->spreadsheet = NULL;
+ ia->dict = NULL;
+ ia->casereader_dict = NULL;
ia->main_loop = g_main_loop_new (NULL, TRUE);
\f
-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)
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)
{
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,
g_print ("%s:%d\n", __FILE__, __LINE__);
}
+static struct casereader *
+textfile_create_reader (PsppireImportAssistant *ia)
+{
+ int n_vars = dict_get_var_cnt (ia->dict);
+
+ int i;
+
+ struct fmt_guesser **fg = XCALLOC (n_vars, struct fmt_guesser *);
+ for (i = 0 ; i < n_vars; ++i)
+ {
+ fg[i] = fmt_guesser_create ();
+ }
+
+ 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 (GTK_TREE_MODEL (ia->delimiters_model), &iter);
+ ok;
+ ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->delimiters_model), &iter))
+ {
+ for (i = 0 ; i < n_vars; ++i)
+ {
+ gchar *s = NULL;
+ 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);
+ }
+ }
+
+ struct caseproto *proto = caseproto_create ();
+ for (i = 0 ; i < n_vars; ++i)
+ {
+ struct fmt_spec fs;
+ fmt_guesser_guess (fg[i], &fs);
+
+ fmt_fix (&fs, FMT_FOR_INPUT);
+
+ struct variable *var = dict_get_var (ia->dict, i);
+
+ int width = fmt_var_width (&fs);
+
+ var_set_width_and_formats (var, width,
+ &fs, &fs);
+
+ proto = caseproto_add_width (proto, width);
+ fmt_guesser_destroy (fg[i]);
+ }
+
+ free (fg);
+
+ 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 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
struct casereader *reader = spreadsheet_make_reader (ia->spreadsheet, &opts);
- PsppireDict *dict = psppire_dict_new_from_dict (dict_clone (ia->spreadsheet->dict));
+ 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);
}
else
{
- PsppireDict *dict = psppire_dict_new_from_dict (ia->dict);
- g_object_set (ia->var_sheet, "data-model", dict, NULL);
-
- 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)
- {
- fg[i] = fmt_guesser_create ();
- }
-
- 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 (GTK_TREE_MODEL (ia->delimiters_model), &iter);
- ok;
- ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->delimiters_model), &iter))
- {
- for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i)
- {
- gchar *s = NULL;
- 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);
- }
- }
-
- struct caseproto *proto = caseproto_create ();
- for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i)
- {
- struct fmt_spec fs;
- fmt_guesser_guess (fg[i], &fs);
-
- fmt_fix (&fs, FMT_FOR_INPUT);
-
- struct variable *var = dict_get_var (ia->dict, i);
-
- int width = fmt_var_width (&fs);
-
- var_set_width_and_formats (var, width,
- &fs, &fs);
-
- proto = caseproto_add_width (proto, width);
- fmt_guesser_destroy (fg[i]);
- }
-
- free (fg);
-
- struct casereader *reader =
- casereader_create_random (proto, n_rows, &my_casereader_class, ia);
+ struct casereader *reader = textfile_create_reader (ia);
+ 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);
- caseproto_unref (proto);
+ g_object_set (ia->var_sheet, "data-model", dict, NULL);
}
gint pmax;
}
}
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
}
- syntax_gen_pspp (s, ".");
+ syntax_gen_pspp (s, ".\n");
}
g_main_loop_run (asst->main_loop);
return asst->response;
}
-