X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-import-assistant.c;h=51eae36241e49ebe6f1d164e13aad433a32d749c;hb=128192d98c77ce9399f90483f8a100942af68205;hp=a7d29f2a8cf0391e8c8edf31e3023954bcc7fb20;hpb=ddd5cf1760a7c97343cebb3421efa07ac2b88c55;p=pspp diff --git a/src/ui/gui/psppire-import-assistant.c b/src/ui/gui/psppire-import-assistant.c index a7d29f2a8c..51eae36241 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 Free Software Foundation + Copyright (C) 2015, 2016, 2017 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,7 +14,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - #include #include @@ -32,6 +31,7 @@ #include "data/ods-reader.h" #include "data/spreadsheet-reader.h" #include "data/value-labels.h" +#include "data/casereader-provider.h" #include "gl/intprops.h" @@ -42,15 +42,19 @@ #include "builder-wrapper.h" #include "helper.h" -#include "pspp-sheet-view.h" -#include "pspp-sheet-selection.h" #include "psppire-import-assistant.h" #include "psppire-scanf.h" #include "psppire-dialog.h" #include "psppire-empty-list-store.h" #include "psppire-encoding-selector.h" #include "psppire-spreadsheet-model.h" -#include "psppire-var-sheet.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" #include @@ -68,21 +72,10 @@ static void split_fields (PsppireImportAssistant *ia); static void choose_column_names (PsppireImportAssistant *ia); -/* Frees IA's file substructure. */ -static void destroy_file (PsppireImportAssistant *ia); - -static void clear_fields (PsppireImportAssistant *ia); - static void intro_page_create (PsppireImportAssistant *ia); static void first_line_page_create (PsppireImportAssistant *ia); -static gboolean process_file (PsppireImportAssistant *ia); - - -static GtkWidget * create_data_tree_view (gboolean input, GtkContainer *parent, - PsppireImportAssistant *ia); - static void separators_page_create (PsppireImportAssistant *ia); static void formats_page_create (PsppireImportAssistant *ia); @@ -139,8 +132,6 @@ 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) { @@ -150,16 +141,10 @@ psppire_import_assistant_finalize (GObject *object) if (ia->spreadsheet) spreadsheet_unref (ia->spreadsheet); - // clear_fields (ia); - destroy_columns (ia); - - ds_destroy (&ia->separators); ds_destroy (&ia->quotes); g_object_unref (ia->builder); - destroy_file (ia); - g_object_unref (ia->prop_renderer); g_object_unref (ia->fixed_renderer); @@ -201,6 +186,7 @@ on_paste (GtkButton *button, PsppireImportAssistant *ia) close_assistant (ia, PSPPIRE_RESPONSE_PASTE); } + /* Revises the contents of the fields tree view based on the currently chosen set of separators. */ static void @@ -208,17 +194,16 @@ revise_fields_preview (PsppireImportAssistant *ia) { push_watch_cursor (ia); - get_separators (ia); - split_fields (ia); + // get_separators (ia); + // split_fields (ia); choose_column_names (ia); - ia->fields_tree_view = - GTK_WIDGET (create_data_tree_view (TRUE, - GTK_CONTAINER (get_widget_assert (ia->builder, "fields-scroller")), - ia)); pop_watch_cursor (ia); } + +#if SHEET_MERGE + /* 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 @@ -252,47 +237,127 @@ find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1], 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 }; - size_t row; /* Construct a histogram of all the characters used in the file. */ - for (row = 0; row < ia->line_cnt; row++) + gboolean valid; + GtkTreeIter iter; + for (valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ia->text_file), &iter); + valid; + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (ia->text_file), &iter)) { - struct substring line = ds_ss (&ia->lines[row]); + 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); } find_commonest_chars (histogram, "\"'", "", &ia->quotes); find_commonest_chars (histogram, ",;:/|!\t-", ",", &ia->separators); } +#endif static void set_separators (PsppireImportAssistant *ia); + +static void +repopulate_delimiter_columns (PsppireImportAssistant *ia) +{ + /* Remove all the columns */ + while (gtk_tree_view_get_n_columns (GTK_TREE_VIEW (ia->fields_tree_view)) > 0) + { + GtkTreeViewColumn *tvc = gtk_tree_view_get_column (GTK_TREE_VIEW (ia->fields_tree_view), 0); + 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); + + /* ... and put them back again. */ + gint f; + for (f = gtk_tree_view_get_n_columns (GTK_TREE_VIEW (ia->fields_tree_view)); + f < n_fields; f++) + { + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + + const gchar *title = NULL; + + if (f == 0) + title = _("line"); + else + { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb))) + { + title = + psppire_delimited_text_get_header_title + (PSPPIRE_DELIMITED_TEXT (ia->delimiters_model), f - 1); + } + if (title == NULL) + title = _("var"); + } + + GtkTreeViewColumn *column = + gtk_tree_view_column_new_with_attributes (title, + renderer, + "text", f, + NULL); + g_object_set (column, + "resizable", TRUE, + "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE, + NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (ia->fields_tree_view), column); + } +} + +static void +reset_tree_view_model (PsppireImportAssistant *ia) +{ + GtkTreeModel *tm = gtk_tree_view_get_model (GTK_TREE_VIEW (ia->fields_tree_view)); + g_object_ref (tm); + gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), NULL); + + + repopulate_delimiter_columns (ia); + + gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), tm); + // gtk_tree_view_columns_autosize (GTK_TREE_VIEW (ia->fields_tree_view)); + + g_object_unref (tm); +} + /* Called just before the separators page becomes visible in the assistant, and when the Reset button is clicked. */ static void prepare_separators_page (PsppireImportAssistant *ia, GtkWidget *page) { + gtk_tree_view_set_model (GTK_TREE_VIEW (ia->fields_tree_view), ia->delimiters_model); + + g_signal_connect_swapped (ia->delimiters_model, "notify::delimiters", + G_CALLBACK (reset_tree_view_model), ia); + + + repopulate_delimiter_columns (ia); + revise_fields_preview (ia); - choose_likely_separators (ia); - set_separators (ia); + // choose_likely_separators (ia); + // set_separators (ia); } struct separator { const char *name; /* Name (for use with get_widget_assert). */ - int c; /* Separator character. */ + gunichar c; /* Separator character. */ }; /* All the separators in the dialog box. */ @@ -311,6 +376,7 @@ static const struct separator separators[] = #define SEPARATOR_CNT (sizeof separators / sizeof *separators) +#if SHEET_MERGE /* Sets the widgets to match IA's separators substructure. */ static void @@ -366,6 +432,7 @@ set_separators (PsppireImportAssistant *ia) gtk_widget_set_sensitive (ia->quote_combo, any_quotes); } +#endif /* Resets IA's intro page to its initial state. */ static void @@ -402,7 +469,7 @@ on_reset (GtkButton *button, PsppireImportAssistant *ia) gint pn = gtk_assistant_get_current_page (GTK_ASSISTANT (ia)); { GtkWidget *page = gtk_assistant_get_nth_page (GTK_ASSISTANT (ia), pn); - + page_func *on_reset = g_object_get_data (G_OBJECT (page), "on-reset"); if (on_reset) @@ -458,7 +525,7 @@ on_prepare (GtkAssistant *assistant, GtkWidget *page, PsppireImportAssistant *ia if (on_entering) on_entering (ia, new_page); } - + ia->current_page = pn; } @@ -478,23 +545,6 @@ on_close (GtkAssistant *assistant, PsppireImportAssistant *ia) } -/* Frees IA's file substructure. */ -static void -destroy_file (PsppireImportAssistant *ia) -{ - size_t i; - - for (i = 0; i < ia->line_cnt; i++) - ds_destroy (&ia->lines[i]); - - g_free (ia->file_name); - ia->file_name = NULL; - - g_free (ia->encoding); - ia->encoding = NULL; -} - - /* 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. */ @@ -524,98 +574,7 @@ pop_watch_cursor (PsppireImportAssistant *ia) } } - -static gboolean -process_file (PsppireImportAssistant *ia) -{ - struct string input; - struct line_reader *reader = line_reader_for_file (ia->encoding, ia->file_name, O_RDONLY); - if (reader == NULL) - { - msg_error (errno, _("Could not open `%s'"), - ia->file_name); - return FALSE; - } - - ds_init_empty (&input); - for (ia->line_cnt = 0; ia->line_cnt < MAX_PREVIEW_LINES; ia->line_cnt++) - { - ds_clear (&input); - if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1) - || ds_length (&input) > MAX_LINE_LEN) - { - if (line_reader_eof (reader)) - break; - else if (line_reader_error (reader)) - msg (ME, _("Error reading `%s': %s"), - ia->file_name, strerror (line_reader_error (reader))); - else - msg (ME, _("Failed to read `%s', because it contains a line " - "over %d bytes long and therefore appears not to be " - "a text file."), - ia->file_name, MAX_LINE_LEN); - line_reader_close (reader); - destroy_file (ia); - ds_destroy (&input); - return FALSE; - } - - char *s = recode_string ("UTF-8", line_reader_get_encoding (reader), ds_cstr (&input), ds_length (&input)); - ds_init_cstr (&ia->lines[ia->line_cnt], s); - free (s); - } - ds_destroy (&input); - if (ia->line_cnt == 0) - { - msg (ME, _("`%s' is empty."), ia->file_name); - line_reader_close (reader); - destroy_file (ia); - return FALSE; - } - - /* Estimate the number of lines in the file. */ - if (ia->line_cnt < MAX_PREVIEW_LINES) - { - ia->total_lines = ia->line_cnt; - ia->total_is_exact = true; - } - else - { - struct stat s; - off_t position = line_reader_tell (reader); - if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0) - { - ia->total_lines = (double) ia->line_cnt / position * s.st_size; - ia->total_is_exact = false; - } - else - { - ia->total_lines = 0; - ia->total_is_exact = true; - } - } - line_reader_close (reader); - return TRUE; -} - - -static void -render_line_number (PsppSheetViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data) -{ - gint row = empty_list_store_iter_to_row (iter); - char s[INT_BUFSIZE_BOUND (int)]; - int first_line = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_model), - "first-line")); - sprintf (s, "%d", first_line + row); - g_object_set (cell, "text", s, NULL); -} - - - +#if SHEET_MERGE static gint get_string_width (GtkWidget *treeview, GtkCellRenderer *renderer, const char *string) @@ -627,7 +586,6 @@ get_string_width (GtkWidget *treeview, GtkCellRenderer *renderer, return width; } - static gint get_monospace_width (GtkWidget *treeview, GtkCellRenderer *renderer, size_t char_cnt) @@ -645,37 +603,18 @@ get_monospace_width (GtkWidget *treeview, GtkCellRenderer *renderer, } static void -add_line_number_column (const PsppireImportAssistant *ia, - GtkWidget *treeview) -{ - PsppSheetViewColumn *column = - pspp_sheet_view_column_new_with_attributes (_("Line"), ia->prop_renderer, (void *) NULL); - - pspp_sheet_view_column_set_fixed_width (column, get_monospace_width (treeview, ia->prop_renderer, 5)); - - pspp_sheet_view_column_set_resizable (column, TRUE); - - pspp_sheet_view_column_set_cell_data_func (column, ia->prop_renderer, - render_line_number, NULL, NULL); - - pspp_sheet_view_append_column (PSPP_SHEET_VIEW (treeview), column); -} - - -static void -set_model_on_treeview (const PsppireImportAssistant *ia, GtkWidget *tree_view, size_t first_line) +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) { @@ -686,13 +625,14 @@ make_tree_view (const PsppireImportAssistant *ia) return tree_view; } +#endif static GtkWidget * add_page_to_assistant (PsppireImportAssistant *ia, GtkWidget *page, GtkAssistantPageType type, const gchar *); -static void +static void on_sheet_combo_changed (GtkComboBox *cb, PsppireImportAssistant *ia) { GtkTreeIter iter; @@ -715,7 +655,7 @@ prepare_sheet_spec_page (PsppireImportAssistant *ia) GtkWidget *sheet_entry = get_widget_assert (builder, "sheet-entry"); GtkWidget *readnames_checkbox = get_widget_assert (builder, "readnames-checkbox"); - gtk_combo_box_set_model (GTK_COMBO_BOX (sheet_entry), + gtk_combo_box_set_model (GTK_COMBO_BOX (sheet_entry), psppire_spreadsheet_model_new (ia->spreadsheet)); gtk_combo_box_set_active (GTK_COMBO_BOX (sheet_entry), 0); @@ -724,14 +664,13 @@ prepare_sheet_spec_page (PsppireImportAssistant *ia) } - /* Initializes IA's sheet_spec substructure. */ static void sheet_spec_page_create (PsppireImportAssistant *ia) { GtkBuilder *builder = ia->builder; GtkWidget *page = get_widget_assert (builder, "Spreadsheet-Importer"); - + GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry"); GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box)); @@ -748,8 +687,7 @@ sheet_spec_page_create (PsppireImportAssistant *ia) g_object_set_data (G_OBJECT (page), "on-entering", prepare_sheet_spec_page); } - -static void +static void on_chosen (PsppireImportAssistant *ia, GtkWidget *page) { GtkFileChooser *fc = GTK_FILE_CHOOSER (page); @@ -764,10 +702,10 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page) if (f && !g_file_test (f, G_FILE_TEST_IS_DIR)) { gtk_assistant_set_page_complete (GTK_ASSISTANT(ia), GTK_WIDGET (fc), TRUE); - + if (ia->spreadsheet) spreadsheet_unref (ia->spreadsheet); - + ia->spreadsheet = gnumeric_probe (f, FALSE); if (!ia->spreadsheet) @@ -783,26 +721,30 @@ on_chosen (PsppireImportAssistant *ia, GtkWidget *page) { sheet_spec_page_create (ia); } - + formats_page_create (ia); } - g_free (f); + g_free (f); } /* This has to be done on a map signal callback, because GtkFileChooserWidget resets everything when it is mapped. */ -static void +static void on_map (PsppireImportAssistant *ia, GtkWidget *page) { +#if TEXT_FILE GtkFileChooser *fc = GTK_FILE_CHOOSER (page); if (ia->file_name) gtk_file_chooser_set_filename (fc, ia->file_name); +#endif on_chosen (ia, page); } + + static void chooser_page_enter (PsppireImportAssistant *ia, GtkWidget *page) { @@ -811,17 +753,20 @@ chooser_page_enter (PsppireImportAssistant *ia, GtkWidget *page) static void chooser_page_leave (PsppireImportAssistant *ia, GtkWidget *page) { - - if (ia->file_name) - g_free (ia->file_name); + 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)); - - if (ia->encoding) - g_free (ia->encoding); - ia->encoding = psppire_encoding_selector_get_encoding (ia->encoding_selector); + gchar *encoding = psppire_encoding_selector_get_encoding (ia->encoding_selector); if (!ia->spreadsheet) - process_file (ia); + { + ia->text_file = psppire_text_file_new (ia->file_name, encoding); + gtk_tree_view_set_model (GTK_TREE_VIEW (ia->first_line_tree_view), + GTK_TREE_MODEL (ia->text_file)); + } + + + g_free (encoding); } static void @@ -835,6 +780,8 @@ chooser_page_reset (PsppireImportAssistant *ia, GtkWidget *page) on_chosen (ia, page); } + + static void chooser_page_create (PsppireImportAssistant *ia) { @@ -853,7 +800,7 @@ chooser_page_create (PsppireImportAssistant *ia) gtk_file_filter_set_name (ia->default_filter, _("All Files")); gtk_file_filter_add_pattern (ia->default_filter, "*"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), ia->default_filter); - + filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("Text Files")); gtk_file_filter_add_mime_type (filter, "text/*"); @@ -909,20 +856,21 @@ chooser_page_create (PsppireImportAssistant *ia) } + static void 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->current_page = -1 ; + /* ia->column_cnt = 0; */ + /* ia->columns = NULL; */ ia->file_name = NULL; - ia->encoding = 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 (); @@ -934,10 +882,10 @@ psppire_import_assistant_init (PsppireImportAssistant *ia) g_signal_connect (ia, "prepare", G_CALLBACK (on_prepare), ia); g_signal_connect (ia, "cancel", G_CALLBACK (on_cancel), ia); g_signal_connect (ia, "close", G_CALLBACK (on_close), ia); - + ia->paste_button = gtk_button_new_with_label (_("Paste")); ia->reset_button = gtk_button_new_with_label (_("Reset")); - + gtk_assistant_add_action_widget (GTK_ASSISTANT(ia), ia->paste_button); g_signal_connect (ia->paste_button, "clicked", G_CALLBACK (on_paste), ia); @@ -947,14 +895,14 @@ psppire_import_assistant_init (PsppireImportAssistant *ia) gtk_window_set_title (GTK_WINDOW (ia), _("Importing Delimited Text Data")); - + gtk_window_set_icon_name (GTK_WINDOW (ia), "pspp"); chooser_page_create (ia); gtk_assistant_set_forward_page_func (GTK_ASSISTANT (ia), next_page_func, NULL, NULL); - gtk_window_fullscreen (GTK_WINDOW (ia)); + gtk_window_maximize (GTK_WINDOW (ia)); } @@ -990,85 +938,7 @@ on_intro_amount_changed (PsppireImportAssistant *p) } -static void -render_line (PsppSheetViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data) -{ - gint row = empty_list_store_iter_to_row (iter); - struct string *lines; - - lines = g_object_get_data (G_OBJECT (tree_model), "lines"); - g_return_if_fail (lines != NULL); - - g_object_set (cell, "text", ds_cstr (&lines[row]), NULL); -} - -/* Sets the widgets to match IA's first_line substructure. */ -static void -set_first_line (PsppireImportAssistant *ia) -{ - GtkTreePath *path = gtk_tree_path_new_from_indices (ia->skip_lines, -1); - - - set_model_on_treeview (ia, ia->tree_view, 0); - - pspp_sheet_view_set_cursor (PSPP_SHEET_VIEW (ia->tree_view), - path, NULL, false); - gtk_tree_path_free (path); - - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON (ia->variable_names_cb), - ia->variable_names); - gtk_widget_set_sensitive (ia->variable_names_cb, - ia->skip_lines > 0); -} - - -/* Creates and returns a tree view that contains each of the - lines in IA's file as a row. */ -static GtkWidget * -create_lines_tree_view (GtkContainer *parent, PsppireImportAssistant *ia) -{ - size_t max_line_length; - gint content_width, header_width; - size_t i; - const gchar *title = _("Text"); - GtkWidget *tree_view = make_tree_view (ia); - PsppSheetViewColumn *column = - pspp_sheet_view_column_new_with_attributes (title, - ia->fixed_renderer, (void *) NULL); - - pspp_sheet_view_column_set_cell_data_func (column, ia->fixed_renderer, - render_line, NULL, NULL); - pspp_sheet_view_column_set_resizable (column, TRUE); - pspp_sheet_view_column_set_expand (column, TRUE); - - max_line_length = 0; - for (i = 0; i < ia->line_cnt; i++) - { - size_t w = ds_length (&ia->lines[i]); - max_line_length = MAX (max_line_length, w); - } - - content_width = get_monospace_width (tree_view, ia->fixed_renderer, - max_line_length); - header_width = get_string_width (tree_view, ia->prop_renderer, title); - pspp_sheet_view_column_set_fixed_width (column, MAX (content_width, - header_width)); - pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), column); - - GtkWidget *oldtv = gtk_bin_get_child (GTK_BIN (parent)); - if (oldtv) - gtk_container_remove (parent, oldtv); - - gtk_container_add (parent, tree_view); - gtk_widget_show (tree_view); - - return tree_view; -} +#if SHEET_MERGE /* Sets IA's first_line substructure to match the widgets. */ @@ -1094,6 +964,8 @@ set_first_line_options (PsppireImportAssistant *ia) gtk_widget_set_sensitive (ia->variable_names_cb, ia->skip_lines > 0); } + + static void reset_first_line_page (PsppireImportAssistant *ia) { @@ -1103,21 +975,76 @@ reset_first_line_page (PsppireImportAssistant *ia) gtk_widget_set_sensitive (ia->variable_names_cb, FALSE); } +#endif + +static void +on_treeview_selection_change (PsppireImportAssistant *ia) +{ + GtkTreeSelection *selection = + gtk_tree_view_get_selection (GTK_TREE_VIEW (ia->first_line_tree_view)); + GtkTreeModel *model = NULL; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + int n; + 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_set (ia->delimiters_model, "first-line", n, NULL); + + // ia->skip_lines = n; + } +} + /* 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", set_first_line); - + g_object_set_data (G_OBJECT (w), "on-entering", on_treeview_selection_change); + add_page_to_assistant (ia, w, GTK_ASSISTANT_PAGE_CONTENT, _("Select the First Line")); - ia->tree_view = GTK_WIDGET (create_lines_tree_view ( - GTK_CONTAINER (get_widget_assert (ia->builder, "first-line-scroller")), ia)); + GtkWidget *scrolled_window = get_widget_assert (ia->builder, "first-line-scroller"); + + if (ia->first_line_tree_view == NULL) + { + ia->first_line_tree_view = gtk_tree_view_new (); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ia->first_line_tree_view), TRUE); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (_("Line"), renderer, + "text", 0, + NULL); + 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_container_add (GTK_CONTAINER (scrolled_window), ia->first_line_tree_view); + + g_signal_connect_swapped (ia->first_line_tree_view, "cursor-changed", + G_CALLBACK (on_treeview_selection_change), ia); + } + 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); @@ -1130,11 +1057,13 @@ first_line_page_create (PsppireImportAssistant *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_enter (PsppireImportAssistant *ia) { @@ -1143,39 +1072,39 @@ intro_on_enter (PsppireImportAssistant *ia) struct string s; - if (ia->line_cnt > MAX_PREVIEW_LINES) - ia->line_cnt = MAX_PREVIEW_LINES; - ds_init_empty (&s); ds_put_cstr (&s, _("This assistant will guide you through the process of " "importing data into PSPP from a text file with one line " "per case, in which fields are separated by tabs, " "commas, or other delimiters.\n\n")); - if (ia->total_is_exact) + if (ia->text_file) { - ds_put_format ( - &s, ngettext ("The selected file contains %'lu line of text. ", - "The selected file contains %'lu lines of text. ", - ia->total_lines), - ia->total_lines); - } - else if (ia->total_lines > 0) - { - ds_put_format ( - &s, ngettext ( - "The selected file contains approximately %'lu line of text. ", - "The selected file contains approximately %'lu lines of text. ", - ia->total_lines), - ia->total_lines); - ds_put_format ( - &s, ngettext ( - "Only the first %zu line of the file will be shown for " - "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->line_cnt), - ia->line_cnt); + if (ia->text_file->total_is_exact) + { + ds_put_format ( + &s, ngettext ("The selected file contains %'lu line of text. ", + "The selected file contains %'lu lines of text. ", + ia->text_file->total_lines), + ia->text_file->total_lines); + } + else if (ia->text_file->total_lines > 0) + { + ds_put_format ( + &s, ngettext ( + "The selected file contains approximately %'lu line of text. ", + "The selected file contains approximately %'lu lines of text. ", + ia->text_file->total_lines), + ia->text_file->total_lines); + ds_put_format ( + &s, ngettext ( + "Only the first %zu line of the file will be shown for " + "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); + } } ds_put_cstr (&s, _("You may choose below how much of the file should " @@ -1194,18 +1123,23 @@ intro_on_enter (PsppireImportAssistant *ia) 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); GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ia->n_cases_spin)); gtk_adjustment_set_lower (adj, 1.0); - if (ia->total_is_exact) - gtk_adjustment_set_value (adj, old_value); - if (ia->total_is_exact) - gtk_adjustment_set_upper (adj, ia->total_lines); - else - gtk_adjustment_set_upper (adj, DBL_MAX); + if (ia->text_file) + { + 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); @@ -1259,10 +1193,16 @@ GtkWidget * psppire_import_assistant_new (GtkWindow *toplevel) { return GTK_WIDGET (g_object_new (PSPPIRE_TYPE_IMPORT_ASSISTANT, - "transient-for", toplevel, + /* Some window managers (notably ratpoison) + ignore the maximise command when a window is + transient. This causes problems for this + window. */ + /* "transient-for", toplevel, */ NULL)); } + + struct column @@ -1289,19 +1229,7 @@ struct column struct substring *contents; }; - -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); -} +#if SHEET_MERGE /* Called to render one of the cells in the fields preview tree view. */ @@ -1336,7 +1264,6 @@ render_input_cell (PsppSheetViewColumn *tree_column, GtkCellRenderer *cell, (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 @@ -1355,7 +1282,7 @@ parse_field (PsppireImportAssistant *ia, bool ok; struct substring field = ia->columns[column].contents[row]; - struct variable *var = dict_get_var (ia->dict, column); + const struct variable *var = dict_get_var (ia->dict, column); union value val; value_init (&val, var_get_width (var)); @@ -1395,7 +1322,6 @@ parse_field (PsppireImportAssistant *ia, return ok; } - /* Called to render one of the cells in the data preview tree view. */ static void @@ -1465,6 +1391,7 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy, } + @@ -1513,7 +1440,7 @@ on_query_output_tooltip (GtkWidget *widget, gint wx, gint wy, free (text); return TRUE; } - +#endif @@ -1544,7 +1471,7 @@ set_quote_list (GtkComboBox *cb) } - +#if SHEET_MERGE /* Sets IA's separators substructure to match the widgets. */ static void @@ -1577,41 +1504,6 @@ get_separators (PsppireImportAssistant *ia) -/* Frees and clears the column data in IA's separators - substructure. */ -static void -clear_fields (PsppireImportAssistant *ia) -{ - if (ia->column_cnt > 0) - { - struct column *col; - size_t row; - - for (row = 0; row < ia->line_cnt; row++) - { - const struct string *line = &ia->lines[row]; - const char *line_start = ds_data (line); - const char *line_end = ds_end (line); - - for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++) - { - char *s = ss_data (col->contents[row]); - if (!(s >= line_start && s <= line_end)) - ss_dealloc (&col->contents[row]); - } - } - - for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++) - { - free (col->name); - free (col->contents); - } - - free (ia->columns); - ia->columns = NULL; - ia->column_cnt = 0; - } -} /* Breaks the file data in IA into columns based on the @@ -1621,9 +1513,7 @@ split_fields (PsppireImportAssistant *ia) { size_t columns_allocated; bool space_sep; - size_t row; - - clear_fields (ia); + size_t row = 0; /* Is space in the set of separators? */ space_sep = ss_find_byte (ds_ss (&ia->separators), ' ') != SIZE_MAX; @@ -1633,13 +1523,20 @@ split_fields (PsppireImportAssistant *ia) contains variables names if ia->first_line.variable_names is TRUE. */ columns_allocated = 0; - for (row = 0; row < ia->line_cnt; row++) + + 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)) { - struct string *line = &ia->lines[row]; - struct substring text = ds_ss (line); + 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++) + for (column_idx = 0; ;column_idx++) { struct substring field = SS_EMPTY_INITIALIZER; struct column *column; @@ -1689,7 +1586,7 @@ split_fields (PsppireImportAssistant *ia) column = &ia->columns[ia->column_cnt++]; column->name = NULL; column->width = 0; - column->contents = xcalloc (ia->line_cnt, + column->contents = xcalloc (n_lines, sizeof *column->contents); } column = &ia->columns[column_idx]; @@ -1708,110 +1605,27 @@ split_fields (PsppireImportAssistant *ia) } } -static PsppSheetViewColumn * -make_data_column (PsppireImportAssistant *ia, GtkWidget *tree_view, - bool input, gint dict_idx) -{ - struct variable *var = NULL; - struct column *column = NULL; - size_t char_cnt; - gint content_width, header_width; - PsppSheetViewColumn *tree_column; - char *name; - - if (input) - column = &ia->columns[dict_idx]; - else - var = dict_get_var (ia->dict, dict_idx); - - name = escape_underscores (input ? column->name : var_get_name (var)); - char_cnt = input ? column->width : var_get_print_format (var)->w; - content_width = get_monospace_width (tree_view, ia->fixed_renderer, - char_cnt); - header_width = get_string_width (tree_view, ia->prop_renderer, - name); - - tree_column = pspp_sheet_view_column_new (); - g_object_set_data (G_OBJECT (tree_column), "column-number", - GINT_TO_POINTER (dict_idx)); - pspp_sheet_view_column_set_title (tree_column, name); - pspp_sheet_view_column_pack_start (tree_column, ia->fixed_renderer, - FALSE); - pspp_sheet_view_column_set_cell_data_func ( - tree_column, ia->fixed_renderer, - input ? render_input_cell : render_output_cell, ia, NULL); - pspp_sheet_view_column_set_fixed_width (tree_column, MAX (content_width, - header_width)); - - free (name); - - return tree_column; -} - - -static GtkWidget * -create_data_tree_view (gboolean input, GtkContainer *parent, - PsppireImportAssistant *ia) -{ - gint i; - GtkWidget *tree_view = make_tree_view (ia); - - set_model_on_treeview (ia, tree_view, ia->skip_lines); - - pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (tree_view)), - PSPP_SHEET_SELECTION_NONE); - - for (i = 0; i < ia->column_cnt; i++) - { - PsppSheetViewColumn *w = make_data_column (ia, tree_view, input, i); - - pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), w); - } - - g_object_set (G_OBJECT (tree_view), "has-tooltip", TRUE, (void *) NULL); - g_signal_connect (tree_view, "query-tooltip", - G_CALLBACK (input ? on_query_input_tooltip - : on_query_output_tooltip), ia); - - GtkWidget *child = gtk_bin_get_child (GTK_BIN (parent)); - if (child) - { - g_object_ref (child); - gtk_container_remove (parent, child); - } - gtk_container_add (parent, tree_view); - if (child) - g_object_unref (child); - - gtk_widget_show (tree_view); - - return tree_view; -} - +#endif /* Chooses a name for each column on the separators page */ static void choose_column_names (PsppireImportAssistant *ia) { - struct dictionary *dict; - unsigned long int generated_name_count = 0; - struct column *col; - size_t name_row; - - dict = dict_create (get_default_encoding ()); - name_row = ia->variable_names && ia->skip_lines ? ia->skip_lines : 0; - for (col = ia->columns; col < &ia->columns[ia->column_cnt]; col++) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->variable_names_cb))) { - char *hint, *name; - - hint = name_row ? ss_xstrdup (col->contents[name_row - 1]) : NULL; - name = dict_make_unique_var_name (dict, hint, &generated_name_count); - free (hint); + 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) + { + const gchar *candidate_name = + psppire_delimited_text_get_header_title (PSPPIRE_DELIMITED_TEXT (ia->delimiters_model), i); - col->name = name; - dict_create_var_assert (dict, name, 0); + char *name = dict_make_unique_var_name (ia->dict, candidate_name, &generated_name_count); + dict_create_var_assert (ia->dict, name, 0); + free (name); + } } - dict_destroy (dict); } @@ -1822,9 +1636,24 @@ static void on_separator_toggle (GtkToggleButton *toggle UNUSED, PsppireImportAssistant *ia) { - revise_fields_preview (ia); + int i; + GSList *delimiters = NULL; + for (i = 0; i < SEPARATOR_CNT; i++) + { + const struct separator *s = &separators[i]; + GtkWidget *button = get_widget_assert (ia->builder, s->name); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) + { + delimiters = g_slist_prepend (delimiters, GINT_TO_POINTER (s->c)); + } + } + + g_object_set (ia->delimiters_model, "delimiters", delimiters, NULL); + + // revise_fields_preview (ia); } + /* Called when the user changes the entry field for custom separators. */ static void @@ -1851,7 +1680,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 @@ -1876,7 +1705,6 @@ separators_page_create (PsppireImportAssistant *ia) g_object_set_data (G_OBJECT (w), "on-entering", prepare_separators_page); g_object_set_data (G_OBJECT (w), "on-reset", prepare_separators_page); - add_page_to_assistant (ia, w, GTK_ASSISTANT_PAGE_CONTENT, _("Choose Separators")); @@ -1887,7 +1715,14 @@ separators_page_create (PsppireImportAssistant *ia) ia->quote_cb = get_widget_assert (builder, "quote-cb"); set_quote_list (GTK_COMBO_BOX (ia->quote_combo)); - ia->fields_tree_view = NULL; + + if (ia->fields_tree_view == NULL) + { + GtkWidget *scroller = get_widget_assert (ia->builder, "fields-scroller"); + ia->fields_tree_view = gtk_tree_view_new (); + gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ia->fields_tree_view)); + gtk_widget_show_all (scroller); + } g_signal_connect (ia->quote_combo, "changed", G_CALLBACK (on_quote_combo_change), ia); @@ -1900,11 +1735,15 @@ separators_page_create (PsppireImportAssistant *ia) for (i = 0; i < SEPARATOR_CNT; i++) g_signal_connect (get_widget_assert (builder, separators[i].name), "toggled", G_CALLBACK (on_separator_toggle), ia); + } + +#if SHEET_MERGE + /* Called when the user changes one of the variables in the dictionary. */ static void @@ -1943,208 +1782,174 @@ on_variable_change (PsppireDict *dict, int dict_idx, pop_watch_cursor (ia); } +#endif +static struct casereader_random_class my_casereader_class; -/* Called just before the formats page of the assistant is - displayed. */ -static void -prepare_formats_page (PsppireImportAssistant *ia) +static struct ccase * +my_read (struct casereader *reader, void *aux, casenumber idx) { - PsppireDict *psppire_dict = NULL; - PsppireVarSheet *var_sheet; - GtkBin *vars_scroller; - GtkWidget *old_var_sheet; + PsppireImportAssistant *ia = PSPPIRE_IMPORT_ASSISTANT (aux); + GtkTreeModel *tm = GTK_TREE_MODEL (ia->delimiters_model); - - push_watch_cursor (ia); + GtkTreePath *tp = gtk_tree_path_new_from_indices (idx, -1); - if (ia->spreadsheet == NULL) - { - struct fmt_guesser *fg; - unsigned long int number = 0; - size_t column_idx; + const struct caseproto *proto = casereader_get_proto (reader); - - ia->dict = dict_create (get_default_encoding ()); - fg = fmt_guesser_create (); - for (column_idx = 0; column_idx < ia->column_cnt; column_idx++) + GtkTreeIter iter; + struct ccase *c = NULL; + if (gtk_tree_model_get_iter (tm, &iter, tp)) + { + c = case_create (proto); + int i; + for (i = 0 ; i < caseproto_get_n_widths (proto); ++i) { - struct variable *modified_var = - (column_idx < ia->modified_var_cnt ? ia->modified_vars[column_idx] : NULL); + GValue value = {0}; + gtk_tree_model_get_value (tm, &iter, i + 1, &value); - if (modified_var == NULL) - { - struct column *column = &ia->columns[column_idx]; - struct variable *var; - struct fmt_spec format; - char *name; - size_t row; - - /* Choose variable name. */ - name = dict_make_unique_var_name (ia->dict, column->name, &number); - - /* Choose variable format. */ - fmt_guesser_clear (fg); - for (row = ia->skip_lines; row < ia->line_cnt; row++) - fmt_guesser_add (fg, column->contents[row]); - fmt_guesser_guess (fg, &format); - fmt_fix_input (&format); - - /* Create variable. */ - var = dict_create_var_assert (ia->dict, name, fmt_var_width (&format)); - var_set_both_formats (var, &format); - - free (name); - } - else - { - char *name; + const struct variable *var = dict_get_var (ia->dict, i); - name = dict_make_unique_var_name (ia->dict, var_get_name (modified_var), - &number); - dict_clone_var_as_assert (ia->dict, modified_var, name); - free (name); - } + 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); + g_value_unset (&value); } - fmt_guesser_destroy (fg); } - else + + gtk_tree_path_free (tp); + + return c; +} + +static void +my_destroy (struct casereader *reader, void *aux) +{ + g_print ("%s:%d %p\n", __FILE__, __LINE__, reader); +} + +static void +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) { - int row_start = -1; - int row_stop = -1; - int col_start = -1; - int col_stop = -1; + const struct variable *var = dict_get_var (ia->dict, i); + proto = caseproto_add_width (proto, var_get_width (var)); + } - GtkBuilder *builder = ia->builder; - struct casereader *reader = NULL; + gint n_rows = gtk_tree_model_iter_n_children (ia->delimiters_model, NULL); - GtkWidget *readnames_checkbox = get_widget_assert (builder, "readnames-checkbox"); - GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry"); - const gchar *range = gtk_entry_get_text (GTK_ENTRY (range_entry)); - GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry"); + struct casereader *reader = + casereader_create_random (proto, n_rows, &my_casereader_class, ia); - gint num = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box)); - struct spreadsheet_read_options sro; - - sro.sheet_name = NULL; - sro.cell_range = NULL; - sro.sheet_index = num + 1; + PsppireDataStore *store = NULL; - if ( convert_cell_ref (range, &col_start, &row_start, &col_stop, &row_stop)) - { - sro.cell_range = g_strdup (range); - } + g_object_get (ia->data_sheet, "data-model", &store, NULL); - sro.read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (readnames_checkbox)); - sro.asw = -1; - - switch (ia->spreadsheet->type) - { - case SPREADSHEET_ODS: - case SPREADSHEET_GNUMERIC: - { - reader = spreadsheet_make_reader (ia->spreadsheet, &sro); - ia->dict = ia->spreadsheet->dict; - } - break; - default: - g_assert_not_reached (); - break; - } - g_free (sro.cell_range); + psppire_data_store_set_reader (store, reader); +} - if (reader && ia->dict) - { - struct ccase *c; - int col; +/* Called just before the formats page of the assistant is + displayed. */ +static void +prepare_formats_page (PsppireImportAssistant *ia) +{ + PsppireDict *dict = psppire_dict_new_from_dict (ia->dict); + g_object_set (ia->var_sheet, "data-model", dict, NULL); - ia->column_cnt = dict_get_var_cnt (ia->dict); - ia->columns = xcalloc (ia->column_cnt, sizeof (*ia->columns)); - for (col = 0; col < ia->column_cnt ; ++col) - { - const struct variable *var = dict_get_var (ia->dict, col); - ia->columns[col].name = xstrdup (var_get_name (var)); - ia->columns[col].contents = NULL; - } + my_casereader_class.read = my_read; + my_casereader_class.destroy = my_destroy; + my_casereader_class.advance = my_advance; - casenumber rows = 0; - for (; (c = casereader_read (reader)) != NULL; case_unref (c)) - { - rows++; - for (col = 0; col < ia->column_cnt ; ++col) - { - char *ss; - const struct variable *var = dict_get_var (ia->dict, col); - - ia->columns[col].contents = xrealloc (ia->columns[col].contents, - sizeof (struct substring) * rows); - - ss = data_out (case_data (c, var), dict_get_encoding (ia->dict), - var_get_print_format (var)); - - ia->columns[col].contents[rows - 1] = ss_cstr (ss); - } - - if (rows > MAX_PREVIEW_LINES) - { - case_unref (c); - break; - } - } - casereader_destroy (reader); - ia->line_cnt = rows; - } - else + 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) + { + fg[i] = fmt_guesser_create (); + } + + gint n_rows = gtk_tree_model_iter_n_children (ia->delimiters_model, NULL); + + GtkTreeIter iter; + gboolean ok; + for (ok = gtk_tree_model_get_iter_first (ia->delimiters_model, &iter); + ok; + ok = gtk_tree_model_iter_next (ia->delimiters_model, &iter)) + { + for (i = 0 ; i < dict_get_var_cnt (ia->dict); ++i) { - GtkWidget * dialog = gtk_message_dialog_new (NULL, - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("An error occurred reading the spreadsheet file.")); - - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); + gchar *s = NULL; + gtk_tree_model_get (ia->delimiters_model, &iter, i+1, &s, -1); + fmt_guesser_add (fg[i], ss_cstr (s)); + free (s); } } - psppire_dict = psppire_dict_new_from_dict (ia->dict); - g_signal_connect (psppire_dict, "variable-changed", - G_CALLBACK (on_variable_change), ia); - ia->psppire_dict = psppire_dict; - - - /* XXX: PsppireVarStore doesn't hold a reference to - psppire_dict for now, but it should. After it does, we - should g_object_ref the psppire_dict here, since we also - hold a reference via ia->formats->dict. */ - var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ()); - g_object_set (var_sheet, - "dictionary", psppire_dict, - "may-create-vars", FALSE, - "may-delete-vars", FALSE, - "format-use", FMT_FOR_INPUT, - "enable-grid-lines", PSPP_SHEET_VIEW_GRID_LINES_BOTH, - (void *) NULL); - - vars_scroller = GTK_BIN (get_widget_assert (ia->builder, "vars-scroller")); - old_var_sheet = gtk_bin_get_child (GTK_BIN (vars_scroller)); - if (old_var_sheet != NULL) - gtk_container_remove (GTK_CONTAINER (vars_scroller), old_var_sheet); - gtk_container_add (GTK_CONTAINER (vars_scroller), GTK_WIDGET (var_sheet)); - gtk_widget_show (GTK_WIDGET (var_sheet)); - - ia->data_tree_view = - GTK_WIDGET (create_data_tree_view ( - FALSE, - GTK_CONTAINER (get_widget_assert (ia->builder, "data-scroller")), - ia)); + 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); - gtk_widget_show (ia->paste_button); + // dict_set_change_callback (ia->dict, foo, ia); - pop_watch_cursor (ia); + struct casereader *reader = + casereader_create_random (proto, n_rows, &my_casereader_class, ia); + + PsppireDataStore *store = psppire_data_store_new (dict); + psppire_data_store_set_reader (store, reader); + + g_object_set (ia->data_sheet, "data-model", store, NULL); + + + gint pmax; + g_object_get (get_widget_assert (ia->builder, "vpaned1"), + "max-position", &pmax, NULL); + + + g_object_set (get_widget_assert (ia->builder, "vpaned1"), + "position", pmax / 2, NULL); + + gtk_widget_show (ia->paste_button); } static void @@ -2152,15 +1957,34 @@ formats_page_create (PsppireImportAssistant *ia) { GtkBuilder *builder = ia->builder; - GtkWidget *w = get_widget_assert (builder, "Formats"); g_object_set_data (G_OBJECT (w), "on-entering", prepare_formats_page); g_object_set_data (G_OBJECT (w), "on-reset", reset_formats_page); - + + GtkWidget *vars_scroller = get_widget_assert (builder, "vars-scroller"); + if (ia->var_sheet == NULL) + { + ia->var_sheet = psppire_variable_sheet_new (); + + gtk_container_add (GTK_CONTAINER (vars_scroller), ia->var_sheet); + + ia->dict = dict_create (get_default_encoding ()); + + gtk_widget_show_all (vars_scroller); + } + GtkWidget *data_scroller = get_widget_assert (builder, "data-scroller"); + if (ia->data_sheet == NULL) + { + ia->data_sheet = psppire_data_sheet_new (); + + gtk_container_add (GTK_CONTAINER (data_scroller), ia->data_sheet); + + gtk_widget_show_all (data_scroller); + } + add_page_to_assistant (ia, w, GTK_ASSISTANT_PAGE_CONFIRM, _("Adjust Variable Formats")); - ia->data_tree_view = NULL; ia->modified_vars = NULL; ia->modified_var_cnt = 0; } @@ -2168,29 +1992,32 @@ formats_page_create (PsppireImportAssistant *ia) -static void +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 (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) { @@ -2198,9 +2025,9 @@ formats_append_syntax (const PsppireImportAssistant *ia, struct string *s) int var_cnt; g_return_if_fail (ia->dict); - + ds_put_cstr (s, " /VARIABLES=\n"); - + var_cnt = dict_get_var_cnt (ia->dict); for (i = 0; i < var_cnt; i++) { @@ -2213,14 +2040,15 @@ formats_append_syntax (const PsppireImportAssistant *ia, struct string *s) } } - static void first_line_append_syntax (const PsppireImportAssistant *ia, struct string *s) { - if (ia->skip_lines > 0) - ds_put_format (s, " /FIRSTCASE=%d\n", ia->skip_lines + 1); -} + 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); +} static void intro_append_syntax (const PsppireImportAssistant *ia, struct string *s) @@ -2329,6 +2157,8 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia) struct string s = DS_EMPTY_INITIALIZER; + char *filename; + g_object_get (ia->text_file, "file-name", &filename, NULL); syntax_gen_pspp (&s, "GET DATA" "\n /TYPE=%ss" @@ -2336,11 +2166,10 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia) "\n /SHEET=index %d" "\n /READNAMES=%ss", (ia->spreadsheet->type == SPREADSHEET_GNUMERIC) ? "GNM" : "ODS", - ia->file_name, + filename, sheet_index, read_names ? "ON" : "OFF"); - if (range && 0 != strcmp ("", range)) { syntax_gen_pspp (&s, @@ -2355,10 +2184,11 @@ sheet_spec_gen_syntax (PsppireImportAssistant *ia) syntax_gen_pspp (&s, "."); - + return ds_cstr (&s); } + gchar * psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia) { @@ -2366,16 +2196,23 @@ psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia) if (!ia->spreadsheet) { - if (ia->file_name == NULL) + 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 NULL; syntax_gen_pspp (&s, "GET DATA" "\n /TYPE=TXT" "\n /FILE=%sq\n", - ia->file_name); - if (ia->encoding && strcmp (ia->encoding, "Auto")) - syntax_gen_pspp (&s, " /ENCODING=%sq\n", ia->encoding); + file_name); + if (encoding && strcmp (encoding, "Auto")) + syntax_gen_pspp (&s, " /ENCODING=%sq\n", encoding); ds_put_cstr (&s, " /ARRANGEMENT=DELIMITED\n" @@ -2392,6 +2229,6 @@ psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia) { return sheet_spec_gen_syntax (ia); } - + return ds_cstr (&s); }