X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-import-assistant.c;h=b88ab887cf4bdd61d4ea772b99f6fa02d5064588;hb=5b6f8f94c5f47443e7afe4cb4c38348d374b7dfa;hp=e5eaecbd563ac16bde69bbcb44496d890a24aaab;hpb=b279085b32f1a9ca6b036beeb19220d5c266d401;p=pspp diff --git a/src/ui/gui/psppire-import-assistant.c b/src/ui/gui/psppire-import-assistant.c index e5eaecbd56..b88ab887cf 100644 --- a/src/ui/gui/psppire-import-assistant.c +++ b/src/ui/gui/psppire-import-assistant.c @@ -14,13 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - #include -#include -#include #include -#include #include "data/casereader.h" #include "data/data-in.h" @@ -34,26 +30,25 @@ #include "data/value-labels.h" #include "data/casereader-provider.h" -#include "gl/intprops.h" - #include "libpspp/i18n.h" #include "libpspp/line-reader.h" #include "libpspp/message.h" +#include "libpspp/hmap.h" +#include "libpspp/hash-functions.h" #include "libpspp/str.h" #include "builder-wrapper.h" -#include "helper.h" -#include "psppire-import-assistant.h" -#include "psppire-scanf.h" + +#include "psppire-data-sheet.h" +#include "psppire-data-store.h" #include "psppire-dialog.h" -#include "psppire-empty-list-store.h" +#include "psppire-delimited-text.h" +#include "psppire-dict.h" #include "psppire-encoding-selector.h" +#include "psppire-import-assistant.h" +#include "psppire-scanf.h" #include "psppire-spreadsheet-model.h" #include "psppire-text-file.h" -#include "psppire-delimited-text.h" -#include "psppire-data-sheet.h" -#include "psppire-data-store.h" -#include "psppire-dict.h" #include "psppire-variable-sheet.h" #include "ui/syntax-gen.h" @@ -65,26 +60,15 @@ enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */ -/* Sets IA's separators substructure to match the widgets. */ -static void get_separators (PsppireImportAssistant *ia); -static void split_fields (PsppireImportAssistant *ia); - /* Chooses a name for each column on the separators page */ static void choose_column_names (PsppireImportAssistant *ia); - - static void intro_page_create (PsppireImportAssistant *ia); static void first_line_page_create (PsppireImportAssistant *ia); static void separators_page_create (PsppireImportAssistant *ia); static void formats_page_create (PsppireImportAssistant *ia); -static void push_watch_cursor (PsppireImportAssistant *ia); -static void pop_watch_cursor (PsppireImportAssistant *ia); - - - static void psppire_import_assistant_init (PsppireImportAssistant *act); static void psppire_import_assistant_class_init (PsppireImportAssistantClass *class); @@ -133,26 +117,20 @@ psppire_import_assistant_get_property (GObject *object, static GObjectClass * parent_class = NULL; -static void destroy_columns (PsppireImportAssistant *ia); - static void psppire_import_assistant_finalize (GObject *object) { PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (object); - if (ia->spreadsheet) spreadsheet_unref (ia->spreadsheet); - // destroy_columns (ia); - - ds_destroy (&ia->separators); ds_destroy (&ia->quotes); g_object_unref (ia->builder); - g_object_unref (ia->prop_renderer); - g_object_unref (ia->fixed_renderer); + ia->response = -1; + g_main_loop_unref (ia->main_loop); if (G_OBJECT_CLASS (parent_class)->finalize) G_OBJECT_CLASS (parent_class)->finalize (object); @@ -198,80 +176,130 @@ on_paste (GtkButton *button, PsppireImportAssistant *ia) static void revise_fields_preview (PsppireImportAssistant *ia) { - push_watch_cursor (ia); - - get_separators (ia); - // split_fields (ia); choose_column_names (ia); - - pop_watch_cursor (ia); } -/* Chooses the most common character among those in TARGETS, - based on the frequency data in HISTOGRAM, and stores it in - RESULT. If there is a tie for the most common character among - those in TARGETS, the earliest character is chosen. If none - of the TARGETS appear at all, then DEF is used as a - fallback. */ -static void -find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1], - const char *targets, const char *def, - struct string *result) + +struct separator { - unsigned char max = 0; - unsigned long int max_count = 0; + const char *name; /* Name (for use with get_widget_assert). */ + gunichar c; /* Separator character. */ +}; + +/* All the separators in the dialog box. */ +static const struct separator separators[] = + { + {"space", ' '}, + {"tab", '\t'}, + {"bang", '!'}, + {"colon", ':'}, + {"comma", ','}, + {"hyphen", '-'}, + {"pipe", '|'}, + {"semicolon", ';'}, + {"slash", '/'}, + }; + +#define SEPARATOR_CNT (sizeof separators / sizeof *separators) + +struct separator_count_node +{ + struct hmap_node node; + int occurance; /* The number of times the separator occurs in a line */ + int quantity; /* The number of lines with this occurance */ +}; - for (; *targets != '\0'; targets++) - { - unsigned char c = *targets; - unsigned long int count = histogram[c]; - if (count > max_count) - { - max = c; - max_count = count; - } - } - if (max_count > 0) - { - ds_clear (result); - ds_put_byte (result, max); - } - else - ds_assign_cstr (result, def); -} /* Picks the most likely separator and quote characters based on IA's file data. */ static void choose_likely_separators (PsppireImportAssistant *ia) { - unsigned long int histogram[UCHAR_MAX + 1] = { 0 }; + gint first_line = 0; + g_object_get (ia->delimiters_model, "first-line", &first_line, NULL); - /* Construct a histogram of all the characters used in the - file. */ gboolean valid; GtkTreeIter iter; - for (valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ia->text_file), &iter); + int j; + + struct hmap count_map[SEPARATOR_CNT]; + for (j = 0; j < SEPARATOR_CNT; ++j) + hmap_init (count_map + j); + + GtkTreePath *p = gtk_tree_path_new_from_indices (first_line, -1); + + for (valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (ia->text_file), &iter, p); valid; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->text_file), &iter)) { - gchar *xxx = 0; - gtk_tree_model_get (GTK_TREE_MODEL (ia->text_file), &iter, 1, &xxx, -1); - struct substring line = ss_cstr (xxx); - size_t length = ss_length (line); - size_t i; - for (i = 0; i < length; i++) - histogram[(unsigned char) line.string[i]]++; - g_free (xxx); - } + gchar *line_text = NULL; + gtk_tree_model_get (GTK_TREE_MODEL (ia->text_file), &iter, 1, &line_text, -1); - find_commonest_chars (histogram, "\"'", "", &ia->quotes); - find_commonest_chars (histogram, ",;:/|!\t-", ",", &ia->separators); -} + gint *counts = xzalloc (sizeof *counts * SEPARATOR_CNT); + struct substring cs = ss_cstr (line_text); + for (; + UINT32_MAX != ss_first_mb (cs); + ss_get_mb (&cs)) + { + ucs4_t character = ss_first_mb (cs); -static void set_separators (PsppireImportAssistant *ia); + int s; + for (s = 0; s < SEPARATOR_CNT; ++s) + { + if (character == separators[s].c) + counts[s]++; + } + } + + int j; + for (j = 0; j < SEPARATOR_CNT; ++j) + { + if (counts[j] > 0) + { + struct separator_count_node *cn = NULL; + unsigned int hash = hash_int (counts[j], 0); + HMAP_FOR_EACH_WITH_HASH (cn, struct separator_count_node, node, hash, &count_map[j]) + { + if (cn->occurance == counts[j]) + break; + } + + if (cn == NULL) + { + struct separator_count_node *new_cn = xzalloc (sizeof *new_cn); + new_cn->occurance = counts[j]; + new_cn->quantity = 1; + hmap_insert (&count_map[j], &new_cn->node, hash); + } + else + cn->quantity++; + } + } + free (line_text); + free (counts); + } + gtk_tree_path_free (p); + + 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); +} static void repopulate_delimiter_columns (PsppireImportAssistant *ia) @@ -283,7 +311,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; @@ -343,9 +372,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); @@ -353,87 +383,8 @@ prepare_separators_page (PsppireImportAssistant *ia, GtkWidget *page) revise_fields_preview (ia); choose_likely_separators (ia); - set_separators (ia); } -struct separator -{ - const char *name; /* Name (for use with get_widget_assert). */ - gunichar c; /* Separator character. */ -}; - -/* All the separators in the dialog box. */ -static const struct separator separators[] = - { - {"space", ' '}, - {"tab", '\t'}, - {"bang", '!'}, - {"colon", ':'}, - {"comma", ','}, - {"hyphen", '-'}, - {"pipe", '|'}, - {"semicolon", ';'}, - {"slash", '/'}, - }; -#define SEPARATOR_CNT (sizeof separators / sizeof *separators) - - - -/* Sets the widgets to match IA's separators substructure. */ -static void -set_separators (PsppireImportAssistant *ia) -{ - unsigned int seps; - struct string custom; - bool any_custom; - bool any_quotes; - size_t i; - - ds_init_empty (&custom); - seps = 0; - for (i = 0; i < ds_length (&ia->separators); i++) - { - unsigned char c = ds_at (&ia->separators, i); - int j; - - for (j = 0; j < SEPARATOR_CNT; j++) - { - const struct separator *s = &separators[j]; - if (s->c == c) - { - seps += 1u << j; - goto next; - } - } - - ds_put_byte (&custom, c); - next:; - } - - for (i = 0; i < SEPARATOR_CNT; i++) - { - const struct separator *s = &separators[i]; - GtkWidget *button = get_widget_assert (ia->builder, s->name); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), - (seps & (1u << i)) != 0); - } - any_custom = !ds_is_empty (&custom); - gtk_entry_set_text (GTK_ENTRY (ia->custom_entry), ds_cstr (&custom)); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->custom_cb), - any_custom); - gtk_widget_set_sensitive (ia->custom_entry, any_custom); - ds_destroy (&custom); - - any_quotes = !ds_is_empty (&ia->quotes); - - gtk_entry_set_text (ia->quote_entry, - any_quotes ? ds_cstr (&ia->quotes) : "\""); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->quote_cb), - any_quotes); - gtk_widget_set_sensitive (ia->quote_combo, any_quotes); -} - - /* Resets IA's intro page to its initial state. */ static void reset_intro_page (PsppireImportAssistant *ia) @@ -451,13 +402,6 @@ reset_intro_page (PsppireImportAssistant *ia) static void reset_formats_page (PsppireImportAssistant *ia, GtkWidget *page) { - size_t i; - - for (i = 0; i < ia->modified_var_cnt; i++) - var_destroy (ia->modified_vars[i]); - free (ia->modified_vars); - ia->modified_vars = NULL; - ia->modified_var_cnt = 0; } static void prepare_formats_page (PsppireImportAssistant *ia); @@ -545,88 +489,6 @@ on_close (GtkAssistant *assistant, PsppireImportAssistant *ia) } -/* Increments the "watch cursor" level, setting the cursor for - the assistant window to a watch face to indicate to the user - that the ongoing operation may take some time. */ -static void -push_watch_cursor (PsppireImportAssistant *ia) -{ - if (++ia->watch_cursor == 1) - { - GtkWidget *widget = GTK_WIDGET (ia); - GdkDisplay *display = gtk_widget_get_display (widget); - GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_WATCH); - gdk_window_set_cursor (gtk_widget_get_window (widget), cursor); - g_object_unref (cursor); - gdk_display_flush (display); - } -} - -/* Decrements the "watch cursor" level. If the level reaches - zero, the cursor is reset to its default shape. */ -static void -pop_watch_cursor (PsppireImportAssistant *ia) -{ - if (--ia->watch_cursor == 0) - { - GtkWidget *widget = GTK_WIDGET (ia); - gdk_window_set_cursor (gtk_widget_get_window (widget), NULL); - } -} - -#if SHEET_MERGE -static gint -get_string_width (GtkWidget *treeview, GtkCellRenderer *renderer, - const char *string) -{ - gint width; - g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL); - gtk_cell_renderer_get_preferred_width (renderer, treeview, - NULL, &width); - return width; -} - -static gint -get_monospace_width (GtkWidget *treeview, GtkCellRenderer *renderer, - size_t char_cnt) -{ - struct string s; - gint width; - - ds_init_empty (&s); - ds_put_byte_multiple (&s, '0', char_cnt); - ds_put_byte (&s, ' '); - width = get_string_width (treeview, renderer, ds_cstr (&s)); - ds_destroy (&s); - - return width; -} - -static void -set_model_on_treeview (PsppireImportAssistant *ia, GtkWidget *tree_view, size_t first_line) -{ - GtkTreeModel *model = GTK_TREE_MODEL (psppire_empty_list_store_new (ia->line_cnt - first_line)); - - g_object_set_data (G_OBJECT (model), "lines", &ia->lines + first_line); - g_object_set_data (G_OBJECT (model), "first-line", GINT_TO_POINTER (first_line)); - - pspp_sheet_view_set_model (PSPP_SHEET_VIEW (tree_view), model); - - g_object_unref (model); -} - -static GtkWidget * -make_tree_view (const PsppireImportAssistant *ia) -{ - GtkWidget *tree_view = pspp_sheet_view_new (); - pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_GRID_LINES_BOTH); - - add_line_number_column (ia, tree_view); - - return tree_view; -} -#endif - static GtkWidget * add_page_to_assistant (PsppireImportAssistant *ia, GtkWidget *page, GtkAssistantPageType type, const gchar *); @@ -699,7 +561,7 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page) gtk_assistant_set_page_complete (GTK_ASSISTANT(ia), GTK_WIDGET (fc), FALSE); - if (f && !g_file_test (f, G_FILE_TEST_IS_DIR)) + if (f && g_file_test (f, G_FILE_TEST_IS_REGULAR)) { gtk_assistant_set_page_complete (GTK_ASSISTANT(ia), GTK_WIDGET (fc), TRUE); @@ -711,15 +573,15 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page) if (!ia->spreadsheet) ia->spreadsheet = ods_probe (f, FALSE); - if (!ia->spreadsheet) + if (ia->spreadsheet) { - intro_page_create (ia); - first_line_page_create (ia); - separators_page_create (ia); + sheet_spec_page_create (ia); } else { - sheet_spec_page_create (ia); + intro_page_create (ia); + first_line_page_create (ia); + separators_page_create (ia); } formats_page_create (ia); @@ -733,9 +595,9 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page) static void on_map (PsppireImportAssistant *ia, GtkWidget *page) { +#if TEXT_FILE GtkFileChooser *fc = GTK_FILE_CHOOSER (page); -#if TEXT_FILE if (ia->file_name) gtk_file_chooser_set_filename (fc, ia->file_name); #endif @@ -753,7 +615,6 @@ chooser_page_enter (PsppireImportAssistant *ia, GtkWidget *page) static void chooser_page_leave (PsppireImportAssistant *ia, GtkWidget *page) { - g_print ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); g_free (ia->file_name); ia->file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (page)); gchar *encoding = psppire_encoding_selector_get_encoding (ia->encoding_selector); @@ -863,21 +724,11 @@ psppire_import_assistant_init (PsppireImportAssistant *ia) ia->builder = builder_new ("text-data-import.ui"); ia->current_page = -1 ; - /* ia->column_cnt = 0; */ - /* ia->columns = NULL; */ - ia->file_name = NULL; ia->spreadsheet = NULL; - ia->watch_cursor = 0; - ia->prop_renderer = gtk_cell_renderer_text_new (); - g_object_ref_sink (ia->prop_renderer); - ia->fixed_renderer = gtk_cell_renderer_text_new (); - g_object_ref_sink (ia->fixed_renderer); - g_object_set (G_OBJECT (ia->fixed_renderer), - "family", "Monospace", - (void *) NULL); + ia->main_loop = g_main_loop_new (NULL, TRUE); g_signal_connect (ia, "prepare", G_CALLBACK (on_prepare), ia); g_signal_connect (ia, "cancel", G_CALLBACK (on_cancel), ia); @@ -929,54 +780,14 @@ static void on_intro_amount_changed (PsppireImportAssistant *p) { gtk_widget_set_sensitive (p->n_cases_spin, - gtk_toggle_button_get_active ( - GTK_TOGGLE_BUTTON (p->n_cases_button))); + gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (p->n_cases_button))); gtk_widget_set_sensitive (p->percent_spin, - gtk_toggle_button_get_active ( - GTK_TOGGLE_BUTTON (p->percent_button))); -} - - -#if SHEET_MERGE - - -/* Sets IA's first_line substructure to match the widgets. */ -static void -set_first_line_options (PsppireImportAssistant *ia) -{ - GtkTreeIter iter; - GtkTreeModel *model; - - PsppSheetSelection *selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view)); - if (pspp_sheet_selection_get_selected (selection, &model, &iter)) - { - GtkTreePath *path = gtk_tree_model_get_path (model, &iter); - int row = gtk_tree_path_get_indices (path)[0]; - gtk_tree_path_free (path); - - ia->skip_lines = row; - ia->variable_names = - (ia->skip_lines > 0 - && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb))); - } - - gtk_widget_set_sensitive (ia->variable_names_cb, ia->skip_lines > 0); -} - - - -static void -reset_first_line_page (PsppireImportAssistant *ia) -{ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb), FALSE); - PsppSheetSelection *selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view)); - pspp_sheet_selection_unselect_all (selection); - gtk_widget_set_sensitive (ia->variable_names_cb, FALSE); + gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (p->percent_button))); } -#endif - static void on_treeview_selection_change (PsppireImportAssistant *ia) { @@ -986,31 +797,44 @@ on_treeview_selection_change (PsppireImportAssistant *ia) GtkTreeIter iter; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gint max_lines; int n; - PsppireTextFile *tf = PSPPIRE_TEXT_FILE (model); GtkTreePath *path = gtk_tree_model_get_path (model, &iter); gint *index = gtk_tree_path_get_indices (path); - n = *index; - gtk_tree_path_free (path); - - gtk_widget_set_sensitive (ia->variable_names_cb, n > 0); - - ia->delimiters_model - = psppire_delimited_text_new (GTK_TREE_MODEL (ia->text_file)); + g_object_get (model, "maximum-lines", &max_lines, NULL); + gtk_widget_set_sensitive (ia->variable_names_cb, + (n > 0 && n < max_lines)); + ia->delimiters_model = + psppire_delimited_text_new (GTK_TREE_MODEL (ia->text_file)); g_object_set (ia->delimiters_model, "first-line", n, NULL); - - // ia->skip_lines = n; } } +static void +render_text_preview_line (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + /* + Set the text to a "insensitive" state if the row + is greater than what the user declared to be the maximum. + */ + GtkTreePath *path = gtk_tree_model_get_path (tree_model, iter); + gint *ii = gtk_tree_path_get_indices (path); + gint max_lines; + g_object_get (tree_model, "maximum-lines", &max_lines, NULL); + g_object_set (cell, "sensitive", (*ii < max_lines), NULL); + gtk_tree_path_free (path); +} /* Initializes IA's first_line substructure. */ static void first_line_page_create (PsppireImportAssistant *ia) { - g_print ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); GtkWidget *w = get_widget_assert (ia->builder, "FirstLine"); g_object_set_data (G_OBJECT (w), "on-entering", on_treeview_selection_change); @@ -1023,6 +847,7 @@ first_line_page_create (PsppireImportAssistant *ia) if (ia->first_line_tree_view == NULL) { ia->first_line_tree_view = gtk_tree_view_new (); + g_object_set (ia->first_line_tree_view, "enable-search", FALSE, NULL); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ia->first_line_tree_view), TRUE); @@ -1030,39 +855,46 @@ first_line_page_create (PsppireImportAssistant *ia) GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (_("Line"), renderer, "text", 0, NULL); + + gtk_tree_view_column_set_cell_data_func (column, renderer, render_text_preview_line, ia, 0); gtk_tree_view_append_column (GTK_TREE_VIEW (ia->first_line_tree_view), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Text"), renderer, "text", 1, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (ia->first_line_tree_view), column); + gtk_tree_view_column_set_cell_data_func (column, renderer, render_text_preview_line, ia, 0); - gtk_container_add (GTK_CONTAINER (scrolled_window), ia->first_line_tree_view); + gtk_tree_view_append_column (GTK_TREE_VIEW (ia->first_line_tree_view), column); g_signal_connect_swapped (ia->first_line_tree_view, "cursor-changed", - G_CALLBACK (on_treeview_selection_change), ia); + G_CALLBACK (on_treeview_selection_change), ia); + gtk_container_add (GTK_CONTAINER (scrolled_window), ia->first_line_tree_view); } + gtk_widget_show_all (scrolled_window); ia->variable_names_cb = get_widget_assert (ia->builder, "variable-names"); - -#if SHEET_MERGE - pspp_sheet_selection_set_mode ( - pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view)), - PSPP_SHEET_SELECTION_BROWSE); - pspp_sheet_view_set_rubber_banding (PSPP_SHEET_VIEW (ia->tree_view), TRUE); - - - g_signal_connect_swapped (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ia->tree_view)), - "changed", G_CALLBACK (set_first_line_options), ia); - - g_signal_connect_swapped (ia->variable_names_cb, "toggled", - G_CALLBACK (set_first_line_options), ia); - - g_object_set_data (G_OBJECT (w), "on-reset", reset_first_line_page); -#endif } - +static void +intro_on_leave (PsppireImportAssistant *ia) +{ + gint lc = 0; + g_object_get (ia->text_file, "line-count", &lc, NULL); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->n_cases_button))) + { + gint max_lines = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin)); + g_object_set (ia->text_file, "maximum-lines", max_lines, NULL); + } + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->percent_button))) + { + gdouble percent = gtk_spin_button_get_value (GTK_SPIN_BUTTON (ia->percent_spin)); + g_object_set (ia->text_file, "maximum-lines", (gint) (lc * percent / 100.0), NULL); + } + else + { + g_object_set (ia->text_file, "maximum-lines", lc, NULL); + } +} static void @@ -1115,43 +947,26 @@ intro_on_enter (PsppireImportAssistant *ia) ds_cstr (&s)); ds_destroy (&s); - GtkWidget *w = gtk_grid_get_child_at (GTK_GRID (table), 1, 1); - int old_value = w ? gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin)) : 1; - if (w) - gtk_container_remove (GTK_CONTAINER (table), w); - - w = gtk_grid_get_child_at (GTK_GRID (table), 1, 2); - if (w) - gtk_container_remove (GTK_CONTAINER (table), w); - - - GtkWidget *hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &ia->n_cases_spin); + if (gtk_grid_get_child_at (GTK_GRID (table), 1, 1) == NULL) + { + GtkWidget *hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &ia->n_cases_spin); + gtk_grid_attach (GTK_GRID (table), hbox_n_cases, + 1, 1, + 1, 1); + } GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ia->n_cases_spin)); gtk_adjustment_set_lower (adj, 1.0); - if (ia->text_file) + if (gtk_grid_get_child_at (GTK_GRID (table), 1, 2) == NULL) { - if (psppire_text_file_get_total_exact (ia->text_file)) - { - gulong total_lines = psppire_text_file_get_n_lines (ia->text_file); - gtk_adjustment_set_upper (adj, total_lines); - gtk_adjustment_set_value (adj, old_value); - } - else - gtk_adjustment_set_upper (adj, DBL_MAX); - } - gtk_grid_attach (GTK_GRID (table), hbox_n_cases, - 1, 1, - 1, 1); - + GtkWidget *hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), + &ia->percent_spin); - GtkWidget *hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), - &ia->percent_spin); - - gtk_grid_attach (GTK_GRID (table), hbox_percent, - 1, 2, - 1, 1); + gtk_grid_attach (GTK_GRID (table), hbox_percent, + 1, 2, + 1, 1); + } gtk_widget_show_all (table); @@ -1185,6 +1000,7 @@ intro_page_create (PsppireImportAssistant *ia) G_CALLBACK (on_intro_amount_changed), ia); + g_object_set_data (G_OBJECT (w), "on-forward", intro_on_leave); g_object_set_data (G_OBJECT (w), "on-entering", intro_on_enter); g_object_set_data (G_OBJECT (w), "on-reset", reset_intro_page); } @@ -1206,271 +1022,17 @@ psppire_import_assistant_new (GtkWindow *toplevel) -struct column -{ - /* Variable name for this column. This is the variable name - used on the separators page; it can be overridden by the - user on the formats page. */ - char *name; - - /* Maximum length of any row in this column. */ - size_t width; - - /* Contents of this column: contents[row] is the contents for - the given row. - - A null substring indicates a missing column for that row - (because the line contains an insufficient number of - separators). - - contents[] elements may be substrings of the lines[] - strings that represent the whole lines of the file, to - save memory. Other elements are dynamically allocated - with ss_alloc_substring. */ - struct substring *contents; -}; - -#if SHEET_MERGE - -static void -destroy_columns (PsppireImportAssistant *ia) -{ - struct column *col; - for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++) - { - free (col->name); - free (col->contents); - } - - free (ia->columns); -} - - - -/* Called to render one of the cells in the fields preview tree - view. */ -static void -render_input_cell (PsppSheetViewColumn *tree_column, GtkCellRenderer *cell, - GtkTreeModel *model, GtkTreeIter *iter, - gpointer ia_) -{ - PsppireImportAssistant *ia = ia_; - struct substring field; - size_t row; - gint column; - - column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column), - "column-number")); - row = empty_list_store_iter_to_row (iter) + ia->skip_lines; - field = ia->columns[column].contents[row]; - if (field.string != NULL) - { - GValue text = {0, }; - g_value_init (&text, G_TYPE_STRING); - g_value_take_string (&text, ss_xstrdup (field)); - g_object_set_property (G_OBJECT (cell), "text", &text); - g_value_unset (&text); - g_object_set (cell, "background-set", FALSE, (void *) NULL); - } - else - g_object_set (cell, - "text", "", - "background", "red", - "background-set", TRUE, - (void *) NULL); -} - -/* Parses the contents of the field at (ROW,COLUMN) according to - its variable format. If OUTPUTP is non-null, then *OUTPUTP - receives the formatted output for that field (which must be - freed with free). If TOOLTIPP is non-null, then *TOOLTIPP - receives a message suitable for use in a tooltip, if one is - needed, or a null pointer otherwise. Returns TRUE if a - tooltip message is needed, otherwise FALSE. */ -static bool -parse_field (PsppireImportAssistant *ia, - size_t row, size_t column, - char **outputp, char **tooltipp) -{ - const struct fmt_spec *in; - struct fmt_spec out; - char *tooltip; - bool ok; - - struct substring field = ia->columns[column].contents[row]; - const struct variable *var = dict_get_var (ia->dict, column); - union value val; - - value_init (&val, var_get_width (var)); - in = var_get_print_format (var); - out = fmt_for_output_from_input (in); - tooltip = NULL; - if (field.string != NULL) - { - char *error = data_in (field, "UTF-8", in->type, &val, var_get_width (var), - dict_get_encoding (ia->dict)); - if (error != NULL) - { - tooltip = xasprintf (_("Cannot parse field content `%.*s' as " - "format %s: %s"), - (int) field.length, field.string, - fmt_name (in->type), error); - free (error); - } - } - else - { - tooltip = xstrdup (_("This input line has too few separators " - "to fill in this field.")); - value_set_missing (&val, var_get_width (var)); - } - if (outputp != NULL) - { - *outputp = data_out (&val, dict_get_encoding (ia->dict), &out); - } - value_destroy (&val, var_get_width (var)); - - ok = tooltip == NULL; - if (tooltipp != NULL) - *tooltipp = tooltip; - else - free (tooltip); - return ok; -} - -/* Called to render one of the cells in the data preview tree - view. */ -static void -render_output_cell (PsppSheetViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer ia_) -{ - PsppireImportAssistant *ia = ia_; - char *output; - GValue gvalue = { 0, }; - bool ok = parse_field (ia, - (empty_list_store_iter_to_row (iter) - + ia->skip_lines), - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column), - "column-number")), - &output, NULL); - - g_value_init (&gvalue, G_TYPE_STRING); - g_value_take_string (&gvalue, output); - g_object_set_property (G_OBJECT (cell), "text", &gvalue); - g_value_unset (&gvalue); - - if (ok) - g_object_set (cell, "background-set", FALSE, (void *) NULL); - else - g_object_set (cell, - "background", "red", - "background-set", TRUE, - (void *) NULL); -} - - -/* Utility functions used by multiple pages of the assistant. */ - -static gboolean -get_tooltip_location (GtkWidget *widget, gint wx, gint wy, - const PsppireImportAssistant *ia, - size_t *row, size_t *column) -{ - PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); - gint bx, by; - GtkTreePath *path; - GtkTreeIter iter; - PsppSheetViewColumn *tree_column; - GtkTreeModel *tree_model; - bool ok; - - pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view, - wx, wy, &bx, &by); - if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by, - &path, &tree_column, NULL, NULL)) - return FALSE; - - *column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column), - "column-number")); - - tree_model = pspp_sheet_view_get_model (tree_view); - ok = gtk_tree_model_get_iter (tree_model, &iter, path); - gtk_tree_path_free (path); - if (!ok) - return FALSE; - - *row = empty_list_store_iter_to_row (&iter) + ia->skip_lines; - return TRUE; -} - - - - - - -/* Called to render a tooltip on one of the cells in the fields - preview tree view. */ -static gboolean -on_query_input_tooltip (GtkWidget *widget, gint wx, gint wy, - gboolean keyboard_mode UNUSED, - GtkTooltip *tooltip, PsppireImportAssistant *ia) -{ - size_t row, column; - - if (!get_tooltip_location (widget, wx, wy, ia, &row, &column)) - return FALSE; - - if (ia->columns[column].contents[row].string != NULL) - return FALSE; - - gtk_tooltip_set_text (tooltip, - _("This input line has too few separators " - "to fill in this field.")); - return TRUE; -} - - -/* Called to render a tooltip for one of the cells in the data - preview tree view. */ -static gboolean -on_query_output_tooltip (GtkWidget *widget, gint wx, gint wy, - gboolean keyboard_mode UNUSED, - GtkTooltip *tooltip, PsppireImportAssistant *ia) -{ - size_t row, column; - char *text; - - if (!gtk_widget_get_mapped (widget)) - return FALSE; - - if (!get_tooltip_location (widget, wx, wy, ia, &row, &column)) - return FALSE; - - if (parse_field (ia, row, column, NULL, &text)) - return FALSE; - - gtk_tooltip_set_text (tooltip, text); - free (text); - return TRUE; -} -#endif - - - static void set_quote_list (GtkComboBox *cb) { GtkListStore *list = gtk_list_store_new (1, G_TYPE_STRING); GtkTreeIter iter; gint i; - const gchar *seperator[3] = {"'\"", "\'", "\""}; + const gchar *separator[3] = {"'\"", "\'", "\""}; for (i = 0; i < 3; i++) { - const gchar *s = seperator[i]; + const gchar *s = separator[i]; /* Add a new row to the model */ gtk_list_store_append (list, &iter); @@ -1486,165 +1048,33 @@ set_quote_list (GtkComboBox *cb) gtk_combo_box_set_entry_text_column (cb, 0); } - - - -/* Sets IA's separators substructure to match the widgets. */ +/* Chooses a name for each column on the separators page */ static void -get_separators (PsppireImportAssistant *ia) +choose_column_names (PsppireImportAssistant *ia) { int i; + unsigned long int generated_name_count = 0; + dict_clear (ia->dict); - ds_clear (&ia->separators); - for (i = 0; i < SEPARATOR_CNT; i++) - { - const struct separator *sep = &separators[i]; - GtkWidget *button = get_widget_assert (ia->builder, sep->name); - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) - ds_put_byte (&ia->separators, sep->c); - } - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->custom_cb))) - ds_put_cstr (&ia->separators, - gtk_entry_get_text (GTK_ENTRY (ia->custom_entry))); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->quote_cb))) - { - const gchar *text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (ia->quote_combo)))); - ds_assign_cstr (&ia->quotes, text); - } - else - ds_clear (&ia->quotes); -} - - - - -#if SHEET_MERGE - -/* Breaks the file data in IA into columns based on the - separators set in IA's separators substructure. */ -static void -split_fields (PsppireImportAssistant *ia) -{ - size_t columns_allocated; - bool space_sep; - size_t row = 0; - - /* Is space in the set of separators? */ - space_sep = ss_find_byte (ds_ss (&ia->separators), ' ') != SIZE_MAX; - - /* Split all the lines, not just those from - ia->first_line.skip_lines on, so that we split the line that - contains variables names if ia->first_line.variable_names is - TRUE. */ - columns_allocated = 0; - - gint n_lines = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (ia->text_file), NULL); - GtkTreeIter iter; - gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ia->text_file), &iter); - while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->text_file), &iter)) + for (i = 0; + i < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (ia->delimiters_model)) - 1; + ++i) { - row++; - gchar *xxx; - gtk_tree_model_get (GTK_TREE_MODEL (ia->text_file), &iter, 1, &xxx, -1); - struct substring text = ss_cstr (xxx); - g_free (xxx); - size_t column_idx; - - for (column_idx = 0; ;column_idx++) - { - struct substring field = SS_EMPTY_INITIALIZER; - struct column *column; - - if (space_sep) - { - ss_ltrim (&text, ss_cstr (" ")); - } - if (ss_is_empty (text)) - { - if (column_idx != 0) - break; - field = text; - } - else if (!ds_is_empty (&ia->quotes) - && ds_find_byte (&ia->quotes, text.string[0]) != SIZE_MAX) - { - int quote = ss_get_byte (&text); - struct string s; - int c; - - ds_init_empty (&s); - while ((c = ss_get_byte (&text)) != EOF) - if (c != quote) - ds_put_byte (&s, c); - else if (ss_match_byte (&text, quote)) - ds_put_byte (&s, quote); - else - break; - field = ds_ss (&s); - } - else - { - ss_get_bytes (&text, ss_cspan (text, ds_ss (&ia->separators)), - &field); - } - - if (column_idx >= ia->column_cnt) - { - struct column *column; + const gchar *candidate_name = NULL; - if (ia->column_cnt >= columns_allocated) - { - ia->columns = x2nrealloc (ia->columns, &columns_allocated, - sizeof *ia->columns); - } - column = &ia->columns[ia->column_cnt++]; - column->name = NULL; - column->width = 0; - column->contents = xcalloc (n_lines, - sizeof *column->contents); - } - column = &ia->columns[column_idx]; - column->contents[row] = field; - if (ss_length (field) > column->width) - column->width = ss_length (field); - - if (space_sep) - ss_ltrim (&text, ss_cstr (" ")); - if (ss_is_empty (text)) - break; - if (ss_find_byte (ds_ss (&ia->separators), ss_first (text)) - != SIZE_MAX) - ss_advance (&text, 1); - } - } -} - -#endif - -/* Chooses a name for each column on the separators page */ -static void -choose_column_names (PsppireImportAssistant *ia) -{ - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb))) - { - int i; - 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) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb))) { - const gchar *candidate_name = - psppire_delimited_text_get_header_title (PSPPIRE_DELIMITED_TEXT (ia->delimiters_model), i); - - char *name = dict_make_unique_var_name (ia->dict, candidate_name, &generated_name_count); - dict_create_var_assert (ia->dict, name, 0); - free (name); + candidate_name = psppire_delimited_text_get_header_title (PSPPIRE_DELIMITED_TEXT (ia->delimiters_model), i); } - } -} + char *name = dict_make_unique_var_name (ia->dict, + candidate_name, + &generated_name_count); + dict_create_var_assert (ia->dict, name, 0); + free (name); + } +} /* Called when the user toggles one of the separators checkboxes. */ @@ -1666,7 +1096,7 @@ on_separator_toggle (GtkToggleButton *toggle UNUSED, g_object_set (ia->delimiters_model, "delimiters", delimiters, NULL); - // revise_fields_preview (ia); + revise_fields_preview (ia); } @@ -1736,6 +1166,7 @@ separators_page_create (PsppireImportAssistant *ia) { GtkWidget *scroller = get_widget_assert (ia->builder, "fields-scroller"); ia->fields_tree_view = gtk_tree_view_new (); + g_object_set (ia->fields_tree_view, "enable-search", FALSE, NULL); gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ia->fields_tree_view)); gtk_widget_show_all (scroller); } @@ -1758,48 +1189,6 @@ separators_page_create (PsppireImportAssistant *ia) -#if SHEET_MERGE - -/* Called when the user changes one of the variables in the - dictionary. */ -static void -on_variable_change (PsppireDict *dict, int dict_idx, - unsigned int what, const struct variable *oldvar, - PsppireImportAssistant *ia) -{ - PsppSheetView *tv = PSPP_SHEET_VIEW (ia->data_tree_view); - gint column_idx = dict_idx + 1; - - push_watch_cursor (ia); - - /* Remove previous column and replace with new column. */ - pspp_sheet_view_remove_column (tv, pspp_sheet_view_get_column (PSPP_SHEET_VIEW (ia->data_tree_view), column_idx)); - pspp_sheet_view_insert_column (tv, PSPP_SHEET_VIEW_COLUMN (make_data_column (ia, ia->data_tree_view, FALSE, dict_idx)), - column_idx); - - /* Save a copy of the modified variable in modified_vars, so - that its attributes will be preserved if we back up to the - previous page with the Prev button and then come back - here. */ - if (dict_idx >= ia->modified_var_cnt) - { - size_t i; - ia->modified_vars = xnrealloc (ia->modified_vars, dict_idx + 1, - sizeof *ia->modified_vars); - for (i = 0; i <= dict_idx; i++) - ia->modified_vars[i] = NULL; - ia->modified_var_cnt = dict_idx + 1; - } - if (ia->modified_vars[dict_idx]) - var_destroy (ia->modified_vars[dict_idx]); - ia->modified_vars[dict_idx] - = var_clone (psppire_dict_get_variable (dict, dict_idx)); - - pop_watch_cursor (ia); -} - -#endif - static struct casereader_random_class my_casereader_class; @@ -1827,16 +1216,18 @@ my_read (struct casereader *reader, void *aux, casenumber idx) const struct variable *var = dict_get_var (ia->dict, i); const gchar *ss = g_value_get_string (&value); - - union value *v = case_data_rw (c, var); - char *xx = data_in (ss_cstr (ss), - "UTF-8", - var_get_write_format (var)->type, - v, var_get_width (var), "UTF-8"); - - /* if (xx) */ - /* g_print ("%s:%d Err %s\n", __FILE__, __LINE__, xx); */ - free (xx); + if (ss) + { + union value *v = case_data_rw (c, var); + char *xx = data_in (ss_cstr (ss), + "UTF-8", + var_get_write_format (var)->type, + v, var_get_width (var), "UTF-8"); + + /* if (xx) */ + /* g_print ("%s:%d Err %s\n", __FILE__, __LINE__, xx); */ + free (xx); + } g_value_unset (&value); } } @@ -1849,8 +1240,7 @@ my_read (struct casereader *reader, void *aux, casenumber idx) static void my_destroy (struct casereader *reader, void *aux) { - PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (aux); - g_print ("%s:%d\n", __FILE__, __LINE__); + g_print ("%s:%d %p\n", __FILE__, __LINE__, reader); } static void @@ -1859,36 +1249,6 @@ 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 @@ -1902,17 +1262,51 @@ prepare_formats_page (PsppireImportAssistant *ia) my_casereader_class.advance = my_advance; struct caseproto *proto = caseproto_create (); + int i; - dict_set_change_callback (ia->dict, foo, ia); + 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); + } + } - 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)); + 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]); } - gint n_rows = gtk_tree_model_iter_n_children (ia->delimiters_model, NULL); + free (fg); struct casereader *reader = casereader_create_random (proto, n_rows, &my_casereader_class, ia); @@ -1966,9 +1360,6 @@ formats_page_create (PsppireImportAssistant *ia) add_page_to_assistant (ia, w, GTK_ASSISTANT_PAGE_CONFIRM, _("Adjust Variable Formats")); - - ia->modified_vars = NULL; - ia->modified_var_cnt = 0; } @@ -1978,25 +1369,28 @@ static void separators_append_syntax (const PsppireImportAssistant *ia, struct string *s) { int i; + ds_put_cstr (s, " /DELIMITERS=\""); - if (ds_find_byte (&ia->separators, '\t') != SIZE_MAX) + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (get_widget_assert (ia->builder, "tab")))) ds_put_cstr (s, "\\t"); - if (ds_find_byte (&ia->separators, '\\') != SIZE_MAX) - ds_put_cstr (s, "\\\\"); - for (i = 0; i < ds_length (&ia->separators); i++) + for (i = 0; i < SEPARATOR_CNT; i++) { - char c = ds_at (&ia->separators, i); - if (c == '"') - ds_put_cstr (s, "\"\""); - else if (c != '\t' && c != '\\') - ds_put_byte (s, c); + const struct separator *seps = &separators[i]; + GtkWidget *button = get_widget_assert (ia->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 (!ds_is_empty (&ia->quotes)) syntax_gen_pspp (s, " /QUALIFIER=%sq\n", ds_cstr (&ia->quotes)); } - static void formats_append_syntax (const PsppireImportAssistant *ia, struct string *s) { @@ -2032,9 +1426,12 @@ first_line_append_syntax (const PsppireImportAssistant *ia, struct string *s) 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, "N OF CASES %d.\n", - gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ia->n_cases_spin))); + 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); @@ -2211,3 +1608,12 @@ psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia) return ds_cstr (&s); } + + +int +psppire_import_assistant_run (PsppireImportAssistant *asst) +{ + g_main_loop_run (asst->main_loop); + return asst->response; +} +