X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Fui%2Fgui%2Fpsppire-import-textfile.c;h=f73280b66b940d4bd148f016133d1a46b9b6c87a;hb=96ccc18094e24d977bb8285143dc4c69f9caa8b4;hp=d293dc0e39117f2b8e2b1114fd9842301dbe7447;hpb=77e2017715a58c01d3e63ad90fb28b5e39eb2a31;p=pspp diff --git a/src/ui/gui/psppire-import-textfile.c b/src/ui/gui/psppire-import-textfile.c index d293dc0e39..f73280b66b 100644 --- a/src/ui/gui/psppire-import-textfile.c +++ b/src/ui/gui/psppire-import-textfile.c @@ -31,6 +31,7 @@ #include "data/casereader-provider.h" #include "data/data-in.h" #include "data/format-guesser.h" +#include "data/value-labels.h" #include "builder-wrapper.h" @@ -73,10 +74,9 @@ choose_likely_separators (PsppireImportAssistant *ia) gboolean valid; GtkTreeIter iter; - int j; - struct hmap count_map[SEPARATOR_CNT]; - for (j = 0; j < SEPARATOR_CNT; ++j) + struct hmap count_map[N_SEPARATORS]; + for (int j = 0; j < N_SEPARATORS; ++j) hmap_init (count_map + j); GtkTreePath *p = gtk_tree_path_new_from_indices (first_line, -1); @@ -88,7 +88,7 @@ choose_likely_separators (PsppireImportAssistant *ia) gchar *line_text = NULL; gtk_tree_model_get (GTK_TREE_MODEL (ia->text_file), &iter, 1, &line_text, -1); - gint *counts = xzalloc (sizeof *counts * SEPARATOR_CNT); + gint *counts = XCALLOC (N_SEPARATORS, gint); struct substring cs = ss_cstr (line_text); for (; @@ -98,7 +98,7 @@ choose_likely_separators (PsppireImportAssistant *ia) ucs4_t character = ss_first_mb (cs); int s; - for (s = 0; s < SEPARATOR_CNT; ++s) + for (s = 0; s < N_SEPARATORS; ++s) { if (character == separators[s].c) counts[s]++; @@ -106,7 +106,7 @@ choose_likely_separators (PsppireImportAssistant *ia) } int j; - for (j = 0; j < SEPARATOR_CNT; ++j) + for (j = 0; j < N_SEPARATORS; ++j) { if (counts[j] > 0) { @@ -120,7 +120,7 @@ choose_likely_separators (PsppireImportAssistant *ia) if (cn == NULL) { - struct separator_count_node *new_cn = xzalloc (sizeof *new_cn); + struct separator_count_node *new_cn = XZALLOC (struct separator_count_node); new_cn->occurance = counts[j]; new_cn->quantity = 1; hmap_insert (&count_map[j], &new_cn->node, hash); @@ -139,7 +139,7 @@ choose_likely_separators (PsppireImportAssistant *ia) { int most_frequent = -1; int largest = 0; - for (j = 0; j < SEPARATOR_CNT; ++j) + for (int j = 0; j < N_SEPARATORS; ++j) { struct separator_count_node *cn; struct separator_count_node *next; @@ -420,8 +420,8 @@ intro_on_enter (PsppireImportAssistant *ia, GtkWidget *page, enum IMPORT_ASSISTA "preview purposes in the following screens. ", "Only the first %zu lines of the file will be shown for " "preview purposes in the following screens. ", - ia->text_file->line_cnt), - ia->text_file->line_cnt); + ia->text_file->n_lines), + ia->text_file->n_lines); } } @@ -535,7 +535,7 @@ on_separator_toggle (GtkToggleButton *toggle UNUSED, { int i; GSList *delimiters = NULL; - for (i = 0; i < SEPARATOR_CNT; i++) + for (i = 0; i < N_SEPARATORS; i++) { const struct separator *s = &separators[i]; GtkWidget *button = get_widget_assert (ia->text_builder, s->name); @@ -577,7 +577,7 @@ on_separators_custom_cb_toggle (GtkToggleButton *custom_cb, static void on_quote_combo_change (GtkComboBox *combo, PsppireImportAssistant *ia) { - // revise_fields_preview (ia); + revise_fields_preview (ia); } /* Called when the user toggles the checkbox that enables @@ -599,7 +599,7 @@ reset_separators_page (PsppireImportAssistant *ia) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->quote_cb), FALSE); gtk_entry_set_text (GTK_ENTRY (ia->custom_entry), ""); - for (gint i = 0; i < SEPARATOR_CNT; i++) + for (gint i = 0; i < N_SEPARATORS; i++) { const struct separator *s = &separators[i]; GtkWidget *button = get_widget_assert (ia->text_builder, s->name); @@ -615,8 +615,11 @@ reset_separators_page (PsppireImportAssistant *ia) /* Called just before the separators page becomes visible in the assistant. */ static void -prepare_separators_page (PsppireImportAssistant *ia) +prepare_separators_page (PsppireImportAssistant *ia, GtkWidget *new_page, enum IMPORT_ASSISTANT_DIRECTION dir) { + if (dir != IMPORT_ASSISTANT_FORWARDS) + return; + gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), GTK_TREE_MODEL (ia->delimiters_model)); @@ -670,7 +673,7 @@ separators_page_create (PsppireImportAssistant *ia) G_CALLBACK (on_separators_custom_entry_notify), ia); g_signal_connect (ia->custom_cb, "toggled", G_CALLBACK (on_separators_custom_cb_toggle), ia); - for (i = 0; i < SEPARATOR_CNT; i++) + for (i = 0; i < N_SEPARATORS; i++) g_signal_connect (get_widget_assert (builder, separators[i].name), "toggled", G_CALLBACK (on_separator_toggle), ia); @@ -718,6 +721,7 @@ my_read (struct casereader *reader, void *aux, casenumber idx) char *xx = data_in (ss_cstr (ss), "UTF-8", var_get_write_format (var)->type, + settings_get_fmt_settings (), v, var_get_width (var), "UTF-8"); free (xx); @@ -738,7 +742,7 @@ my_destroy (struct casereader *reader, void *aux) } static void -my_advance (struct casereader *reader, void *aux, casenumber cnt) +my_advance (struct casereader *reader, void *aux, casenumber n) { g_print ("%s:%d\n", __FILE__, __LINE__); } @@ -746,7 +750,7 @@ my_advance (struct casereader *reader, void *aux, casenumber cnt) static struct casereader * textfile_create_reader (PsppireImportAssistant *ia) { - int n_vars = dict_get_var_cnt (ia->dict); + int n_vars = dict_get_n_vars (ia->dict); int i; @@ -820,7 +824,7 @@ ia_variable_changed_cb (GObject *obj, gint var_num, guint what, PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (data); struct caseproto *proto = caseproto_create(); - for (int i = 0; i < dict_get_var_cnt (ia->dict); i++) + for (int i = 0; i < dict_get_n_vars (ia->dict); i++) { const struct variable *var = dict_get_var (ia->dict, i); int width = var_get_width (var); @@ -860,3 +864,193 @@ textfile_set_data_models (PsppireImportAssistant *ia) g_object_set (ia->data_sheet, "data-model", store, NULL); g_object_set (ia->var_sheet, "data-model", dict, NULL); } + +static void +first_line_append_syntax (const PsppireImportAssistant *ia, struct string *s) +{ + gint first_case = 0; + g_object_get (ia->delimiters_model, "first-line", &first_case, NULL); + + if (first_case > 0) + ds_put_format (s, " /FIRSTCASE=%d\n", first_case + 1); +} + +/* Emits PSPP syntax to S that applies the dictionary attributes + (such as missing values and value labels) of the variables in + DICT. */ +static void +apply_dict (const struct dictionary *dict, struct string *s) +{ + size_t n_vars = dict_get_n_vars (dict); + + for (size_t i = 0; i < n_vars; i++) + { + struct variable *var = dict_get_var (dict, i); + const char *name = var_get_name (var); + enum val_type type = var_get_type (var); + int width = var_get_width (var); + enum measure measure = var_get_measure (var); + enum var_role role = var_get_role (var); + enum alignment alignment = var_get_alignment (var); + const struct fmt_spec *format = var_get_print_format (var); + + if (var_has_missing_values (var)) + { + const struct missing_values *mv = var_get_missing_values (var); + size_t j; + + syntax_gen_pspp (s, "MISSING VALUES %ss (", name); + for (j = 0; j < mv_n_values (mv); j++) + { + if (j) + ds_put_cstr (s, ", "); + syntax_gen_value (s, mv_get_value (mv, j), width, format); + } + + if (mv_has_range (mv)) + { + double low, high; + if (mv_has_value (mv)) + ds_put_cstr (s, ", "); + mv_get_range (mv, &low, &high); + syntax_gen_num_range (s, low, high, format); + } + ds_put_cstr (s, ").\n"); + } + if (var_has_value_labels (var)) + { + const struct val_labs *vls = var_get_value_labels (var); + const struct val_lab **labels = val_labs_sorted (vls); + size_t n_labels = val_labs_count (vls); + + syntax_gen_pspp (s, "VALUE LABELS %ss", name); + for (size_t j = 0; j < n_labels; j++) + { + const struct val_lab *vl = labels[j]; + ds_put_cstr (s, "\n "); + syntax_gen_value (s, &vl->value, width, format); + ds_put_byte (s, ' '); + syntax_gen_string (s, ss_cstr (val_lab_get_escaped_label (vl))); + } + free (labels); + ds_put_cstr (s, ".\n"); + } + if (var_has_label (var)) + syntax_gen_pspp (s, "VARIABLE LABELS %ss %sq.\n", + name, var_get_label (var)); + if (measure != var_default_measure (type)) + syntax_gen_pspp (s, "VARIABLE LEVEL %ss (%ss).\n", + name, measure_to_syntax (measure)); + if (role != ROLE_INPUT) + syntax_gen_pspp (s, "VARIABLE ROLE /%ss %ss.\n", + var_role_to_syntax (role), name); + if (alignment != var_default_alignment (type)) + syntax_gen_pspp (s, "VARIABLE ALIGNMENT %ss (%ss).\n", + name, alignment_to_syntax (alignment)); + if (var_get_display_width (var) != var_default_display_width (width)) + syntax_gen_pspp (s, "VARIABLE WIDTH %ss (%d).\n", + name, var_get_display_width (var)); + } +} + + +static void +intro_append_syntax (const PsppireImportAssistant *ia, struct string *s) +{ + gint first_line = 0; + g_object_get (ia->delimiters_model, "first-line", &first_line, NULL); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->n_cases_button))) + ds_put_format (s, "SELECT IF ($CASENUM <= %d).\n", + gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin)) - first_line); + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->percent_button))) + ds_put_format (s, "SAMPLE %.4g.\n", + gtk_spin_button_get_value (GTK_SPIN_BUTTON (ia->percent_spin)) / 100.0); +} + + +static void +formats_append_syntax (const PsppireImportAssistant *ia, struct string *s) +{ + g_return_if_fail (ia->dict); + + ds_put_cstr (s, " /VARIABLES=\n"); + + int n_vars = dict_get_n_vars (ia->dict); + for (int i = 0; i < n_vars; i++) + { + struct variable *var = dict_get_var (ia->dict, i); + char format_string[FMT_STRING_LEN_MAX + 1]; + fmt_to_string (var_get_print_format (var), format_string); + ds_put_format (s, " %s %s%s\n", + var_get_name (var), format_string, + i == n_vars - 1 ? "." : ""); + } +} + +static void +separators_append_syntax (const PsppireImportAssistant *ia, struct string *s) +{ + int i; + + ds_put_cstr (s, " /DELIMITERS=\""); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->text_builder, "tab")))) + ds_put_cstr (s, "\\t"); + for (i = 0; i < N_SEPARATORS; i++) + { + const struct separator *seps = &separators[i]; + GtkWidget *button = get_widget_assert (ia->text_builder, seps->name); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) + { + if (seps->c == '\t') + continue; + + ds_put_byte (s, seps->c); + } + } + ds_put_cstr (s, "\"\n"); + + 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); + } +} + + +void +text_spec_gen_syntax (PsppireImportAssistant *ia, struct string *s) +{ + gchar *file_name = NULL; + gchar *encoding = NULL; + g_object_get (ia->text_file, + "file-name", &file_name, + "encoding", &encoding, + NULL); + + if (file_name == NULL) + return; + + syntax_gen_pspp (s, + "GET DATA" + "\n /TYPE=TXT" + "\n /FILE=%sq\n", + file_name); + if (encoding && strcmp (encoding, "Auto")) + syntax_gen_pspp (s, " /ENCODING=%sq\n", encoding); + + ds_put_cstr (s, + " /ARRANGEMENT=DELIMITED\n" + " /DELCASE=LINE\n"); + + first_line_append_syntax (ia, s); + separators_append_syntax (ia, s); + + formats_append_syntax (ia, s); + apply_dict (ia->dict, s); + intro_append_syntax (ia, s); +}