From: Ben Pfaff Date: Tue, 7 May 2013 05:09:59 +0000 (-0700) Subject: Merge 'psppsheet' into 'master'. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b0ca44889e637251cb5f2dbf3c7fdc4ec8b9bd7;p=pspp Merge 'psppsheet' into 'master'. This merge required considerable manual resolution in text-data-import-dialog.c because that file was split into multiple files on master. --- 0b0ca44889e637251cb5f2dbf3c7fdc4ec8b9bd7 diff --cc src/ui/gui/page-assistant.c index 0000000000,88314734e2..608412b03c mode 000000,100644..100644 --- a/src/ui/gui/page-assistant.c +++ b/src/ui/gui/page-assistant.c @@@ -1,0 -1,247 +1,245 @@@ + /* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + #include + + #include "ui/gui/text-data-import-dialog.h" + + #include + #include -#include + #include + #include + #include + #include + + #include "data/data-in.h" + #include "data/data-out.h" + #include "data/format-guesser.h" + #include "data/value-labels.h" + #include "language/data-io/data-parser.h" + #include "language/lexer/lexer.h" + #include "libpspp/assertion.h" + #include "libpspp/i18n.h" + #include "libpspp/line-reader.h" + #include "libpspp/message.h" + #include "ui/gui/checkbox-treeview.h" + #include "ui/gui/dialog-common.h" + #include "ui/gui/executor.h" + #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" + #include "ui/gui/psppire-data-window.h" + #include "ui/gui/psppire-dialog.h" + #include "ui/gui/psppire-encoding-selector.h" + #include "ui/gui/psppire-empty-list-store.h" + #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + + #include "gl/error.h" + #include "gl/intprops.h" + #include "gl/xalloc.h" + + #include "gettext.h" + #define _(msgid) gettext (msgid) + #define N_(msgid) msgid + + /* Assistant. */ + + static void close_assistant (struct import_assistant *, int response); + static void on_prepare (GtkAssistant *assistant, GtkWidget *page, + struct import_assistant *); + static void on_cancel (GtkAssistant *assistant, struct import_assistant *); + static void on_close (GtkAssistant *assistant, struct import_assistant *); + static void on_paste (GtkButton *button, struct import_assistant *); + static void on_reset (GtkButton *button, struct import_assistant *); + + /* Initializes IA's asst substructure. PARENT_WINDOW must be the + window to use as the assistant window's parent. */ + struct import_assistant * + init_assistant (GtkWindow *parent_window) + { + struct import_assistant *ia = xzalloc (sizeof *ia); + struct assistant *a = &ia->asst; + + a->builder = builder_new ("text-data-import.ui"); + a->assistant = GTK_ASSISTANT (gtk_assistant_new ()); + + a->prop_renderer = gtk_cell_renderer_text_new (); + g_object_ref_sink (a->prop_renderer); + a->fixed_renderer = gtk_cell_renderer_text_new (); + g_object_ref_sink (a->fixed_renderer); + g_object_set (G_OBJECT (a->fixed_renderer), + "family", "Monospace", + (void *) NULL); + + g_signal_connect (a->assistant, "prepare", G_CALLBACK (on_prepare), ia); + g_signal_connect (a->assistant, "cancel", G_CALLBACK (on_cancel), ia); + g_signal_connect (a->assistant, "close", G_CALLBACK (on_close), ia); + a->paste_button = gtk_button_new_from_stock (GTK_STOCK_PASTE); + gtk_assistant_add_action_widget (a->assistant, a->paste_button); + g_signal_connect (a->paste_button, "clicked", G_CALLBACK (on_paste), ia); + a->reset_button = gtk_button_new_from_stock ("pspp-stock-reset"); + gtk_assistant_add_action_widget (a->assistant, a->reset_button); + g_signal_connect (a->reset_button, "clicked", G_CALLBACK (on_reset), ia); + gtk_window_set_title (GTK_WINDOW (a->assistant), + _("Importing Delimited Text Data")); + gtk_window_set_transient_for (GTK_WINDOW (a->assistant), parent_window); + gtk_window_set_icon_name (GTK_WINDOW (a->assistant), "pspp"); + + + return ia; + } + + /* Frees IA's asst substructure. */ + void + destroy_assistant (struct import_assistant *ia) + { + struct assistant *a = &ia->asst; + + g_object_unref (a->prop_renderer); + g_object_unref (a->fixed_renderer); + g_object_unref (a->builder); + } + + /* Appends a page of the given TYPE, with PAGE as its content, to + the GtkAssistant encapsulated by IA. Returns the GtkWidget + that represents the page. */ + GtkWidget * + add_page_to_assistant (struct import_assistant *ia, + GtkWidget *page, GtkAssistantPageType type) + { + const char *title; + char *title_copy; + GtkWidget *content; + + title = gtk_window_get_title (GTK_WINDOW (page)); + title_copy = xstrdup (title ? title : ""); + + content = gtk_bin_get_child (GTK_BIN (page)); + assert (content); + g_object_ref (content); + gtk_container_remove (GTK_CONTAINER (page), content); + + gtk_widget_destroy (page); + + gtk_assistant_append_page (ia->asst.assistant, content); + gtk_assistant_set_page_type (ia->asst.assistant, content, type); + gtk_assistant_set_page_title (ia->asst.assistant, content, title_copy); + gtk_assistant_set_page_complete (ia->asst.assistant, content, true); + + free (title_copy); + + return content; + } + + /* Called just before PAGE is displayed as the current page of + ASSISTANT, this updates IA content according to the new + page. */ + static void + on_prepare (GtkAssistant *assistant, GtkWidget *page, + struct import_assistant *ia) + { + int pn = gtk_assistant_get_current_page (assistant); + + gtk_widget_show (ia->asst.reset_button); + gtk_widget_hide (ia->asst.paste_button); + + if ( ia->spreadsheet) + { + if (pn == 0) + { + } + else if (pn == 1) + { + prepare_formats_page (ia); + } + } + else + { + if (pn == 0) + prepare_separators_page (ia); + else if (pn == 3) + prepare_formats_page (ia); + } + + + if (gtk_assistant_get_page_type (assistant, page) + == GTK_ASSISTANT_PAGE_CONFIRM) + gtk_widget_grab_focus (assistant->apply); + else + gtk_widget_grab_focus (assistant->forward); + } + + /* Called when the Cancel button in the assistant is clicked. */ + static void + on_cancel (GtkAssistant *assistant, struct import_assistant *ia) + { + close_assistant (ia, GTK_RESPONSE_CANCEL); + } + + /* Called when the Apply button on the last page of the assistant + is clicked. */ + static void + on_close (GtkAssistant *assistant, struct import_assistant *ia) + { + close_assistant (ia, GTK_RESPONSE_APPLY); + } + + /* Called when the Paste button on the last page of the assistant + is clicked. */ + static void + on_paste (GtkButton *button, struct import_assistant *ia) + { + close_assistant (ia, PSPPIRE_RESPONSE_PASTE); + } + + static GtkWidget * + assist_get_page (struct assist_page *ap) + { + if (ap == NULL) + return NULL; + + return ap->page; + } + + /* Called when the Reset button is clicked. */ + static void + on_reset (GtkButton *button, struct import_assistant *ia) + { + gint page_num = gtk_assistant_get_current_page (ia->asst.assistant); + GtkWidget *page = gtk_assistant_get_nth_page (ia->asst.assistant, page_num); + + if (page == assist_get_page ((struct assist_page *) ia->intro)) + reset_intro_page (ia); + else if (page == assist_get_page ((struct assist_page *) ia->first_line)) + reset_first_line_page (ia); + else if (page == assist_get_page ((struct assist_page *) ia->separators)) + reset_separators_page (ia); + else if (page == assist_get_page ((struct assist_page *) ia->formats)) + reset_formats_page (ia); + } + + /* Causes the assistant to close, returning RESPONSE for + interpretation by text_data_import_assistant. */ + static void + close_assistant (struct import_assistant *ia, int response) + { + ia->asst.response = response; + /* Use our loop_done variable until we find out + why g_main_loop_quit (ia->asst.main_loop); doesn't work. + */ + ia->asst.loop_done = true; + gtk_widget_hide (GTK_WIDGET (ia->asst.assistant)); + } + diff --cc src/ui/gui/page-file.c index 0000000000,93bc1edd9f..850f20787d mode 000000,100644..100644 --- a/src/ui/gui/page-file.c +++ b/src/ui/gui/page-file.c @@@ -1,0 -1,257 +1,255 @@@ + /* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + #include + + #include "ui/gui/text-data-import-dialog.h" + + #include + #include -#include + #include + #include + #include + #include + + #include "data/data-in.h" + #include "data/data-out.h" + #include "data/format-guesser.h" + #include "data/casereader.h" + #include "data/gnumeric-reader.h" + #include "data/ods-reader.h" + #include "data/spreadsheet-reader.h" + #include "data/value-labels.h" + #include "language/data-io/data-parser.h" + #include "language/lexer/lexer.h" + #include "libpspp/assertion.h" + #include "libpspp/i18n.h" + #include "libpspp/line-reader.h" + #include "libpspp/message.h" + #include "ui/gui/checkbox-treeview.h" + #include "ui/gui/dialog-common.h" + #include "ui/gui/executor.h" + #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" + #include "ui/gui/psppire-data-window.h" + #include "ui/gui/psppire-dialog.h" + #include "ui/gui/psppire-encoding-selector.h" + #include "ui/gui/psppire-empty-list-store.h" + #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + #include "ui/gui/psppire-scanf.h" + #include "ui/syntax-gen.h" + + #include "gl/error.h" + #include "gl/intprops.h" + #include "gl/xalloc.h" + + #include "gettext.h" + #define _(msgid) gettext (msgid) + #define N_(msgid) msgid + + struct import_assistant; + + /* Choose a file */ + static char *choose_file (GtkWindow *parent_window, gchar **encodingp); + + + + + /* Obtains the file to import from the user and initializes IA's + file substructure. PARENT_WINDOW must be the window to use + as the file chooser window's parent. + + Returns true if successful, false if the file name could not + be obtained or the file could not be read. */ + bool + init_file (struct import_assistant *ia, GtkWindow *parent_window) + { + enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */ + struct file *file = &ia->file; + + file->lines = NULL; + file->file_name = choose_file (parent_window, &file->encoding); + if (file->file_name == NULL) + return false; + + if (ia->spreadsheet == NULL) + ia->spreadsheet = gnumeric_probe (file->file_name, false); + + if (ia->spreadsheet == NULL) + ia->spreadsheet = ods_probe (file->file_name, false); + + if (ia->spreadsheet == NULL) + { + struct string input; + struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY); + if (reader == NULL) + { + msg (ME, _("Could not open `%s': %s"), + file->file_name, strerror (errno)); + return false; + } + + ds_init_empty (&input); + file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines); + for (; file->line_cnt < MAX_PREVIEW_LINES; file->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"), + file->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."), + file->file_name, MAX_LINE_LEN); + line_reader_close (reader); + destroy_file (ia); + ds_destroy (&input); + return false; + } + + ds_init_cstr (&file->lines[file->line_cnt], + recode_string ("UTF-8", line_reader_get_encoding (reader), + ds_cstr (&input), ds_length (&input))); + } + ds_destroy (&input); + + if (file->line_cnt == 0) + { + msg (ME, _("`%s' is empty."), file->file_name); + line_reader_close (reader); + destroy_file (ia); + return false; + } + + /* Estimate the number of lines in the file. */ + if (file->line_cnt < MAX_PREVIEW_LINES) + file->total_lines = file->line_cnt; + else + { + struct stat s; + off_t position = line_reader_tell (reader); + if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0) + file->total_lines = (double) file->line_cnt / position * s.st_size; + else + file->total_lines = 0; + } + + line_reader_close (reader); + } + + return true; + } + + /* Frees IA's file substructure. */ + void + destroy_file (struct import_assistant *ia) + { + struct file *f = &ia->file; + size_t i; + + if (f->lines) + { + for (i = 0; i < f->line_cnt; i++) + ds_destroy (&f->lines[i]); + free (f->lines); + } + + g_free (f->file_name); + g_free (f->encoding); + } + + /* Obtains the file to read from the user. If successful, returns the name of + the file and stores the user's chosen encoding for the file into *ENCODINGP. + The caller must free each of these strings with g_free(). + + On failure, stores a null pointer and stores NULL in *ENCODINGP. + + PARENT_WINDOW must be the window to use as the file chooser window's + parent. */ + static char * + choose_file (GtkWindow *parent_window, gchar **encodingp) + { + char *file_name; + GtkFileFilter *filter = NULL; + + GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"), + parent_window, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + g_object_set (dialog, "local-only", FALSE, NULL); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Text Files")); + gtk_file_filter_add_mime_type (filter, "text/*"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Text (*.txt) Files")); + gtk_file_filter_add_pattern (filter, "*.txt"); + gtk_file_filter_add_pattern (filter, "*.TXT"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files")); + gtk_file_filter_add_mime_type (filter, "text/plain"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Comma Separated Value Files")); + gtk_file_filter_add_mime_type (filter, "text/csv"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + + /* I've never encountered one of these, but it's listed here: + http://www.iana.org/assignments/media-types/text/tab-separated-values */ + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Tab Separated Value Files")); + gtk_file_filter_add_mime_type (filter, "text/tab-separated-values"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + + + gtk_file_chooser_set_extra_widget ( + GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true)); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("All Files")); + gtk_file_filter_add_pattern (filter, "*"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + + switch (gtk_dialog_run (GTK_DIALOG (dialog))) + { + case GTK_RESPONSE_ACCEPT: + file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + *encodingp = psppire_encoding_selector_get_encoding ( + gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog))); + break; + default: + file_name = NULL; + *encodingp = NULL; + break; + } + gtk_widget_destroy (dialog); + + return file_name; + } diff --cc src/ui/gui/page-first-line.c index 0000000000,d3191e78ca..8d21e7c55c mode 000000,100644..100644 --- a/src/ui/gui/page-first-line.c +++ b/src/ui/gui/page-first-line.c @@@ -1,0 -1,244 +1,244 @@@ + /* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + #include + + #include "page-first-line.h" + + #include "ui/gui/text-data-import-dialog.h" + + #include + #include -#include + #include + #include + #include + #include + + #include "data/data-in.h" + #include "data/data-out.h" + #include "data/format-guesser.h" + #include "data/value-labels.h" + #include "language/data-io/data-parser.h" + #include "language/lexer/lexer.h" + #include "libpspp/assertion.h" + #include "libpspp/i18n.h" + #include "libpspp/line-reader.h" + #include "libpspp/message.h" + #include "ui/gui/checkbox-treeview.h" + #include "ui/gui/dialog-common.h" + #include "ui/gui/executor.h" + #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" ++#include "ui/gui/pspp-sheet-selection.h" ++#include "ui/gui/pspp-sheet-view-column.h" ++#include "ui/gui/pspp-sheet-view.h" + #include "ui/gui/psppire-data-window.h" + #include "ui/gui/psppire-dialog.h" + #include "ui/gui/psppire-encoding-selector.h" + #include "ui/gui/psppire-empty-list-store.h" + #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + #include "ui/gui/psppire-scanf.h" + + #include "gl/error.h" + #include "gl/intprops.h" + #include "gl/xalloc.h" + + #include "gettext.h" + #define _(msgid) gettext (msgid) + #define N_(msgid) msgid + + + + /* The "first line" page of the assistant. */ + + /* Page where the user chooses the first line of data. */ + struct first_line_page + { + GtkWidget *page; - GtkTreeView *tree_view; ++ PsppSheetView *tree_view; + GtkWidget *variable_names_cb; + }; + -static GtkTreeView *create_lines_tree_view (GtkContainer *parent_window, - struct import_assistant *); ++static PsppSheetView *create_lines_tree_view (GtkContainer *parent_window, ++ struct import_assistant *); + static void on_first_line_change (GtkTreeSelection *, + struct import_assistant *); + static void on_variable_names_cb_toggle (GtkToggleButton *, + struct import_assistant *); + static void set_first_line (struct import_assistant *); + static void get_first_line (struct import_assistant *); + + /* Initializes IA's first_line substructure. */ + struct first_line_page * + first_line_page_create (struct import_assistant *ia) + { + struct first_line_page *p = xzalloc (sizeof *p); + + GtkBuilder *builder = ia->asst.builder; + + p->page = add_page_to_assistant (ia, get_widget_assert (builder, "FirstLine"), + GTK_ASSISTANT_PAGE_CONTENT); + + gtk_widget_destroy (get_widget_assert (builder, "first-line")); + p->tree_view = create_lines_tree_view ( + GTK_CONTAINER (get_widget_assert (builder, "first-line-scroller")), ia); + p->variable_names_cb = get_widget_assert (builder, "variable-names"); - gtk_tree_selection_set_mode ( - gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)), - GTK_SELECTION_BROWSE); - g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)), ++ pspp_sheet_selection_set_mode ( ++ pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (p->tree_view)), ++ PSPP_SHEET_SELECTION_BROWSE); ++ pspp_sheet_view_set_rubber_banding (PSPP_SHEET_VIEW (p->tree_view), TRUE); ++ g_signal_connect (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (p->tree_view)), + "changed", G_CALLBACK (on_first_line_change), ia); + g_signal_connect (p->variable_names_cb, "toggled", + G_CALLBACK (on_variable_names_cb_toggle), ia); + return p; + } + + /* Resets the first_line page to its initial content. */ + void + reset_first_line_page (struct import_assistant *ia) + { + ia->skip_lines = 0; + ia->variable_names = false; + set_first_line (ia); + } + + static void -render_line (GtkTreeViewColumn *tree_column, ++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); + } + + + /* Creates and returns a tree view that contains each of the + lines in IA's file as a row. */ -static GtkTreeView * ++static PsppSheetView * + create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia) + { - GtkTreeView *tree_view = NULL; - GtkTreeViewColumn *column; ++ PsppSheetView *tree_view = NULL; ++ PsppSheetViewColumn *column; + size_t max_line_length; + gint content_width, header_width; + size_t i; + const gchar *title = _("Text"); + + make_tree_view (ia, 0, &tree_view); + - column = gtk_tree_view_column_new_with_attributes ( ++ column = pspp_sheet_view_column_new_with_attributes ( + title, ia->asst.fixed_renderer, (void *) NULL); - gtk_tree_view_column_set_cell_data_func (column, ia->asst.fixed_renderer, ++ pspp_sheet_view_column_set_cell_data_func (column, ia->asst.fixed_renderer, + render_line, NULL, NULL); - gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); ++ pspp_sheet_view_column_set_resizable (column, TRUE); + + max_line_length = 0; + for (i = 0; i < ia->file.line_cnt; i++) + { + size_t w = ds_length (&ia->file.lines[i]); + max_line_length = MAX (max_line_length, w); + } + + content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer, + max_line_length); + header_width = get_string_width (tree_view, ia->asst.prop_renderer, title); - gtk_tree_view_column_set_fixed_width (column, MAX (content_width, ++ pspp_sheet_view_column_set_fixed_width (column, MAX (content_width, + header_width)); - gtk_tree_view_append_column (tree_view, column); - - gtk_tree_view_set_fixed_height_mode (tree_view, true); ++ pspp_sheet_view_append_column (tree_view, column); + + gtk_container_add (parent, GTK_WIDGET (tree_view)); + gtk_widget_show (GTK_WIDGET (tree_view)); + + return tree_view; + } + + /* Called when the line selected in the first_line tree view + changes. */ + static void + on_first_line_change (GtkTreeSelection *selection UNUSED, + struct import_assistant *ia) + { + get_first_line (ia); + } + + /* Called when the checkbox that indicates whether variable + names are in the row above the first line is toggled. */ + static void + on_variable_names_cb_toggle (GtkToggleButton *variable_names_cb UNUSED, + struct import_assistant *ia) + { + get_first_line (ia); + } + + /* Sets the widgets to match IA's first_line substructure. */ + static void + set_first_line (struct import_assistant *ia) + { + GtkTreePath *path; + + path = gtk_tree_path_new_from_indices (ia->skip_lines, -1); - gtk_tree_view_set_cursor (GTK_TREE_VIEW (ia->first_line->tree_view), ++ pspp_sheet_view_set_cursor (PSPP_SHEET_VIEW (ia->first_line->tree_view), + path, NULL, false); + gtk_tree_path_free (path); + + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON (ia->first_line->variable_names_cb), + ia->variable_names); + gtk_widget_set_sensitive (ia->first_line->variable_names_cb, + ia->skip_lines > 0); + } + + /* Sets IA's first_line substructure to match the widgets. */ + static void + get_first_line (struct import_assistant *ia) + { - GtkTreeSelection *selection; ++ PsppSheetSelection *selection; + GtkTreeIter iter; + GtkTreeModel *model; + - selection = gtk_tree_view_get_selection (ia->first_line->tree_view); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) ++ selection = pspp_sheet_view_get_selection (ia->first_line->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->first_line->variable_names_cb))); + } + gtk_widget_set_sensitive (ia->first_line->variable_names_cb, + ia->skip_lines > 0); + } + + + + void + first_line_append_syntax (const struct import_assistant *ia, struct string *s) + { + if (ia->skip_lines > 0) + ds_put_format (s, " /FIRSTCASE=%d\n", ia->skip_lines + 1); + } diff --cc src/ui/gui/page-formats.c index 0000000000,6a2109d44a..5b06bcb3d4 mode 000000,100644..100644 --- a/src/ui/gui/page-formats.c +++ b/src/ui/gui/page-formats.c @@@ -1,0 -1,292 +1,288 @@@ + /* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + #include + + #include "ui/gui/text-data-import-dialog.h" + + #include + #include -#include + #include + #include + #include + #include + + #include "data/data-in.h" + #include "data/data-out.h" + #include "data/format-guesser.h" + #include "data/value-labels.h" + #include "language/data-io/data-parser.h" + #include "language/lexer/lexer.h" + #include "libpspp/assertion.h" + #include "libpspp/i18n.h" + #include "libpspp/line-reader.h" + #include "libpspp/message.h" + #include "ui/gui/checkbox-treeview.h" + #include "ui/gui/dialog-common.h" + #include "ui/gui/executor.h" + #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" + #include "ui/gui/psppire-data-window.h" + #include "ui/gui/psppire-dialog.h" + #include "ui/gui/psppire-encoding-selector.h" + #include "ui/gui/psppire-empty-list-store.h" + #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + #include "ui/gui/psppire-scanf.h" + + #include "gl/error.h" + #include "gl/intprops.h" + #include "gl/xalloc.h" + + #include "gettext.h" + #define _(msgid) gettext (msgid) + #define N_(msgid) msgid + + /* Page where the user verifies and adjusts input formats. */ + struct formats_page + { + GtkWidget *page; - GtkTreeView *data_tree_view; ++ PsppSheetView *data_tree_view; + PsppireDict *psppire_dict; + struct variable **modified_vars; + size_t modified_var_cnt; + }; + + /* The "formats" page of the assistant. */ + + static void on_variable_change (PsppireDict *dict, int idx, + struct import_assistant *); + static void clear_modified_vars (struct import_assistant *); + + /* Initializes IA's formats substructure. */ + + struct formats_page * + formats_page_create (struct import_assistant *ia) + { + GtkBuilder *builder = ia->asst.builder; + struct formats_page *p = xzalloc (sizeof *p); + + p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Formats"), + GTK_ASSISTANT_PAGE_CONFIRM); + - p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "data")); ++ p->data_tree_view = PSPP_SHEET_VIEW (get_widget_assert (builder, "data")); + p->modified_vars = NULL; + p->modified_var_cnt = 0; + + return p; + } + + /* Frees IA's formats substructure. */ + void + destroy_formats_page (struct import_assistant *ia) + { + struct formats_page *p = ia->formats; + + if (p->psppire_dict != NULL) + { + dict_destroy (p->psppire_dict->dict); + g_object_unref (p->psppire_dict); + } + clear_modified_vars (ia); + } + + /* Called just before the formats page of the assistant is + displayed. */ + void + prepare_formats_page (struct import_assistant *ia) + { + struct dictionary *dict; + PsppireDict *psppire_dict; - PsppireVarStore *var_store; + GtkBin *vars_scroller; + GtkWidget *old_var_sheet; + PsppireVarSheet *var_sheet; + struct formats_page *p = ia->formats; + struct fmt_guesser *fg; + unsigned long int number = 0; + size_t column_idx; + + push_watch_cursor (ia); + + dict = dict_create (get_default_encoding ()); + fg = fmt_guesser_create (); + for (column_idx = 0; column_idx < ia->column_cnt; column_idx++) + { + struct variable *modified_var = + (column_idx < p->modified_var_cnt ? p->modified_vars[column_idx] : NULL); + 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 (dict, column->name, &number); + + /* Choose variable format. */ + fmt_guesser_clear (fg); + for (row = ia->skip_lines; row < ia->file.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 (dict, name, fmt_var_width (&format)); + var_set_both_formats (var, &format); + + free (name); + } + else + { + char *name; + + name = dict_make_unique_var_name (dict, var_get_name (modified_var), + &number); + dict_clone_var_as_assert (dict, modified_var, name); + free (name); + } + } + fmt_guesser_destroy (fg); + + psppire_dict = psppire_dict_new_from_dict (dict); + g_signal_connect (psppire_dict, "variable_changed", + G_CALLBACK (on_variable_change), ia); + ia->dict = dict; + ia->formats->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_store = psppire_var_store_new (psppire_dict); - g_object_set (var_store, - "format-type", PSPPIRE_VAR_STORE_INPUT_FORMATS, - (void *) NULL); + var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ()); + g_object_set (var_sheet, - "model", var_store, ++ "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->asst.builder, "vars-scroller")); + old_var_sheet = gtk_bin_get_child (vars_scroller); + if (old_var_sheet != NULL) + gtk_widget_destroy (old_var_sheet); + gtk_container_add (GTK_CONTAINER (vars_scroller), GTK_WIDGET (var_sheet)); + gtk_widget_show (GTK_WIDGET (var_sheet)); + + gtk_widget_destroy (GTK_WIDGET (ia->formats->data_tree_view)); + ia->formats->data_tree_view = create_data_tree_view ( + false, + GTK_CONTAINER (get_widget_assert (ia->asst.builder, "data-scroller")), + ia); + + gtk_widget_show (ia->asst.paste_button); + + pop_watch_cursor (ia); + } + + /* Clears the set of user-modified variables from IA's formats + substructure. This discards user modifications to variable + formats, thereby causing formats to revert to their + defaults. */ + static void + clear_modified_vars (struct import_assistant *ia) + { + struct formats_page *p = ia->formats; + size_t i; + + for (i = 0; i < p->modified_var_cnt; i++) + var_destroy (p->modified_vars[i]); + free (p->modified_vars); + p->modified_vars = NULL; + p->modified_var_cnt = 0; + } + + /* Resets the formats page to its defaults, discarding user + modifications. */ + void + reset_formats_page (struct import_assistant *ia) + { + clear_modified_vars (ia); + prepare_formats_page (ia); + } + + + + /* Called when the user changes one of the variables in the + dictionary. */ + static void + on_variable_change (PsppireDict *dict, int dict_idx, + struct import_assistant *ia) + { + struct formats_page *p = ia->formats; - GtkTreeView *tv = ia->formats->data_tree_view; ++ PsppSheetView *tv = ia->formats->data_tree_view; + gint column_idx = dict_idx + 1; + + push_watch_cursor (ia); + + /* Remove previous column and replace with new column. */ - gtk_tree_view_remove_column (tv, gtk_tree_view_get_column (tv, column_idx)); - gtk_tree_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx), - column_idx); ++ pspp_sheet_view_remove_column (tv, pspp_sheet_view_get_column (tv, column_idx)); ++ pspp_sheet_view_insert_column (tv, make_data_column (ia, tv, 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 >= p->modified_var_cnt) + { + size_t i; + p->modified_vars = xnrealloc (p->modified_vars, dict_idx + 1, + sizeof *p->modified_vars); + for (i = 0; i <= dict_idx; i++) + p->modified_vars[i] = NULL; + p->modified_var_cnt = dict_idx + 1; + } + if (p->modified_vars[dict_idx]) + var_destroy (p->modified_vars[dict_idx]); + p->modified_vars[dict_idx] + = var_clone (psppire_dict_get_variable (dict, dict_idx)); + + pop_watch_cursor (ia); + } + + + + + void + formats_append_syntax (const struct import_assistant *ia, struct string *s) + { + int i; + int var_cnt; + ds_put_cstr (s, " /VARIABLES=\n"); + + var_cnt = dict_get_var_cnt (ia->dict); + for (i = 0; i < var_cnt; i++) + { + struct variable *var = dict_get_var (ia->dict, i); + char format_string[FMT_STRING_LEN_MAX + 1]; + fmt_to_string (var_get_print_format (var), format_string); + ds_put_format (s, " %s %s%s\n", + var_get_name (var), format_string, + i == var_cnt - 1 ? "." : ""); + } + } diff --cc src/ui/gui/page-intro.c index 0000000000,e0d51f537c..59c252b46c mode 000000,100644..100644 --- a/src/ui/gui/page-intro.c +++ b/src/ui/gui/page-intro.c @@@ -1,0 -1,200 +1,198 @@@ + /* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + #include + + #include "page-intro.h" + + #include "ui/gui/text-data-import-dialog.h" + + #include + #include -#include + #include + #include + #include + #include + + #include "data/data-in.h" + #include "data/data-out.h" + #include "data/format-guesser.h" + #include "data/value-labels.h" + #include "language/data-io/data-parser.h" + #include "language/lexer/lexer.h" + #include "libpspp/assertion.h" + #include "libpspp/i18n.h" + #include "libpspp/line-reader.h" + #include "libpspp/message.h" + #include "ui/gui/checkbox-treeview.h" + #include "ui/gui/dialog-common.h" + #include "ui/gui/executor.h" + #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" + #include "ui/gui/psppire-data-window.h" + #include "ui/gui/psppire-dialog.h" + #include "ui/gui/psppire-encoding-selector.h" + #include "ui/gui/psppire-empty-list-store.h" + #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + #include "ui/gui/psppire-scanf.h" + #include "ui/syntax-gen.h" + + #include "gl/error.h" + #include "gl/intprops.h" + #include "gl/xalloc.h" + + #include "gettext.h" + #define _(msgid) gettext (msgid) + #define N_(msgid) msgid + + struct import_assistant; + + + + /* The "intro" page of the assistant. */ + + /* The introduction page of the assistant. */ + struct intro_page + { + GtkWidget *page; + GtkWidget *all_cases_button; + GtkWidget *n_cases_button; + GtkWidget *n_cases_spin; + GtkWidget *percent_button; + GtkWidget *percent_spin; + }; + + static void on_intro_amount_changed (struct intro_page *); + + /* Initializes IA's intro substructure. */ + struct intro_page * + intro_page_create (struct import_assistant *ia) + { + GtkBuilder *builder = ia->asst.builder; + struct string s; + GtkWidget *hbox_n_cases ; + GtkWidget *hbox_percent ; + GtkWidget *table ; + + struct intro_page *p = xzalloc (sizeof (*p)); + + p->n_cases_spin = gtk_spin_button_new_with_range (0, INT_MAX, 100); + + hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &p->n_cases_spin); + + table = get_widget_assert (builder, "button-table"); + + gtk_table_attach_defaults (GTK_TABLE (table), hbox_n_cases, + 1, 2, + 1, 2); + + p->percent_spin = gtk_spin_button_new_with_range (0, 100, 10); + + hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), &p->percent_spin); + + gtk_table_attach_defaults (GTK_TABLE (table), hbox_percent, + 1, 2, + 2, 3); + + p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Intro"), + GTK_ASSISTANT_PAGE_INTRO); + + p->all_cases_button = get_widget_assert (builder, "import-all-cases"); + + p->n_cases_button = get_widget_assert (builder, "import-n-cases"); + + p->percent_button = get_widget_assert (builder, "import-percent"); + + g_signal_connect_swapped (p->all_cases_button, "toggled", + G_CALLBACK (on_intro_amount_changed), p); + g_signal_connect_swapped (p->n_cases_button, "toggled", + G_CALLBACK (on_intro_amount_changed), p); + g_signal_connect_swapped (p->percent_button, "toggled", + G_CALLBACK (on_intro_amount_changed), p); + + on_intro_amount_changed (p); + + 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->file.total_is_exact) + ds_put_format ( + &s, ngettext ("The selected file contains %zu line of text. ", + "The selected file contains %zu lines of text. ", + ia->file.line_cnt), + ia->file.line_cnt); + else if (ia->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->file.total_lines), + ia->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->file.line_cnt), + ia->file.line_cnt); + } + ds_put_cstr (&s, _("You may choose below how much of the file should " + "actually be imported.")); + gtk_label_set_text (GTK_LABEL (get_widget_assert (builder, "intro-label")), + ds_cstr (&s)); + ds_destroy (&s); + + return p; + } + + /* Resets IA's intro page to its initial state. */ + void + reset_intro_page (struct import_assistant *ia) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->intro->all_cases_button), + true); + } + + /* Called when one of the radio buttons is clicked. */ + static void + on_intro_amount_changed (struct intro_page *p) + { + gtk_widget_set_sensitive (p->n_cases_spin, + 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))); + } + + + void + intro_append_syntax (const struct intro_page *p, struct string *s) + { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (p->n_cases_button))) + ds_put_format (s, " /IMPORTCASES=FIRST %d\n", + gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (p->n_cases_spin))); + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (p->percent_button))) + ds_put_format (s, " /IMPORTCASES=PERCENT %d\n", + gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (p->percent_spin))); + else + ds_put_cstr (s, " /IMPORTCASES=ALL\n"); + } diff --cc src/ui/gui/page-separators.c index 0000000000,e147881730..f1e08a6b59 mode 000000,100644..100644 --- a/src/ui/gui/page-separators.c +++ b/src/ui/gui/page-separators.c @@@ -1,0 -1,616 +1,614 @@@ + /* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + #include + + #include "page-separators.h" + + #include "ui/gui/text-data-import-dialog.h" + + #include + #include -#include + #include + #include + #include + #include + + #include "data/data-in.h" + #include "data/data-out.h" + #include "data/format-guesser.h" + #include "data/value-labels.h" + #include "language/data-io/data-parser.h" + #include "language/lexer/lexer.h" + #include "libpspp/assertion.h" + #include "libpspp/i18n.h" + #include "libpspp/line-reader.h" + #include "libpspp/message.h" + #include "ui/gui/checkbox-treeview.h" + #include "ui/gui/dialog-common.h" + #include "ui/gui/executor.h" + #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" + #include "ui/gui/psppire-data-window.h" + #include "ui/gui/psppire-dialog.h" + #include "ui/gui/psppire-encoding-selector.h" + #include "ui/gui/psppire-empty-list-store.h" + #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + #include "ui/gui/psppire-scanf.h" + #include "ui/syntax-gen.h" + + #include "gl/error.h" + #include "gl/intprops.h" + #include "gl/xalloc.h" + + #include "gettext.h" + #define _(msgid) gettext (msgid) + #define N_(msgid) msgid + + /* Page where the user chooses field separators. */ + struct separators_page + { + /* How to break lines into columns. */ + struct string separators; /* Field separators. */ + struct string quotes; /* Quote characters. */ + bool escape; /* Doubled quotes yield a quote mark? */ + + GtkWidget *page; + GtkWidget *custom_cb; + GtkWidget *custom_entry; + GtkWidget *quote_cb; + GtkWidget *quote_combo; + GtkEntry *quote_entry; + GtkWidget *escape_cb; - GtkTreeView *fields_tree_view; ++ PsppSheetView *fields_tree_view; + }; + + /* The "separators" page of the assistant. */ + + static void revise_fields_preview (struct import_assistant *ia); + static void choose_likely_separators (struct import_assistant *ia); + static void find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1], + const char *targets, const char *def, + struct string *result); + static void clear_fields (struct import_assistant *ia); + static void revise_fields_preview (struct import_assistant *); + static void set_separators (struct import_assistant *); + static void get_separators (struct import_assistant *); + static void on_separators_custom_entry_notify (GObject *UNUSED, + GParamSpec *UNUSED, + struct import_assistant *); + static void on_separators_custom_cb_toggle (GtkToggleButton *custom_cb, + struct import_assistant *); + static void on_quote_combo_change (GtkComboBox *combo, + struct import_assistant *); + static void on_quote_cb_toggle (GtkToggleButton *quote_cb, + struct import_assistant *); + static void on_separator_toggle (GtkToggleButton *, struct import_assistant *); + + /* A common field separator and its identifying name. */ + struct separator + { + const char *name; /* Name (for use with get_widget_assert). */ + int 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) + + static void + set_quote_list (GtkComboBoxEntry *cb) + { + GtkListStore *list = gtk_list_store_new (1, G_TYPE_STRING); + GtkTreeIter iter; + gint i; + const gchar *seperator[3] = {"'\"", "\'", "\""}; + + for (i = 0; i < 3; i++) + { + const gchar *s = seperator[i]; + + /* Add a new row to the model */ + gtk_list_store_append (list, &iter); + gtk_list_store_set (list, &iter, + 0, s, + -1); + + } + + gtk_combo_box_set_model (GTK_COMBO_BOX (cb), GTK_TREE_MODEL (list)); + g_object_unref (list); + + gtk_combo_box_entry_set_text_column (cb, 0); + } + + /* Initializes IA's separators substructure. */ + + struct separators_page * + separators_page_create (struct import_assistant *ia) + { + GtkBuilder *builder = ia->asst.builder; + + size_t i; + + struct separators_page *p = xzalloc (sizeof *p); + + p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Separators"), + GTK_ASSISTANT_PAGE_CONTENT); + + p->custom_cb = get_widget_assert (builder, "custom-cb"); + p->custom_entry = get_widget_assert (builder, "custom-entry"); + p->quote_combo = get_widget_assert (builder, "quote-combo"); + p->quote_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (p->quote_combo))); + p->quote_cb = get_widget_assert (builder, "quote-cb"); + p->escape_cb = get_widget_assert (builder, "escape"); + + set_quote_list (GTK_COMBO_BOX_ENTRY (p->quote_combo)); - p->fields_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "fields")); ++ p->fields_tree_view = PSPP_SHEET_VIEW (get_widget_assert (builder, "fields")); + g_signal_connect (p->quote_combo, "changed", + G_CALLBACK (on_quote_combo_change), ia); + g_signal_connect (p->quote_cb, "toggled", + G_CALLBACK (on_quote_cb_toggle), ia); + g_signal_connect (p->custom_entry, "notify::text", + G_CALLBACK (on_separators_custom_entry_notify), ia); + g_signal_connect (p->custom_cb, "toggled", + G_CALLBACK (on_separators_custom_cb_toggle), 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); + g_signal_connect (p->escape_cb, "toggled", + G_CALLBACK (on_separator_toggle), ia); + + return p; + } + + /* Frees IA's separators substructure. */ + void + destroy_separators_page (struct import_assistant *ia) + { + struct separators_page *s = ia->separators; + + ds_destroy (&s->separators); + ds_destroy (&s->quotes); + clear_fields (ia); + } + + /* Called just before the separators page becomes visible in the + assistant. */ + void + prepare_separators_page (struct import_assistant *ia) + { + revise_fields_preview (ia); + } + + /* Called when the Reset button is clicked on the separators + page, resets the separators to the defaults. */ + void + reset_separators_page (struct import_assistant *ia) + { + choose_likely_separators (ia); + set_separators (ia); + } + + /* Frees and clears the column data in IA's separators + substructure. */ + static void + clear_fields (struct import_assistant *ia) + { + if (ia->column_cnt > 0) + { + struct column *col; + size_t row; + + for (row = 0; row < ia->file.line_cnt; row++) + { + const struct string *line = &ia->file.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 + separators set in IA's separators substructure. */ + static void + split_fields (struct import_assistant *ia) + { + struct separators_page *s = ia->separators; + size_t columns_allocated; + bool space_sep; + size_t row; + + clear_fields (ia); + + /* Is space in the set of separators? */ + space_sep = ss_find_byte (ds_ss (&s->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; + for (row = 0; row < ia->file.line_cnt; row++) + { + struct string *line = &ia->file.lines[row]; + struct substring text = ds_ss (line); + size_t column_idx; + + for (column_idx = 0; ; column_idx++) + { + struct substring field; + 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 (&s->quotes) + && ds_find_byte (&s->quotes, text.string[0]) != SIZE_MAX) + { + int quote = ss_get_byte (&text); + if (!s->escape) + ss_get_until (&text, quote, &field); + else + { + 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 (&s->separators)), + &field); + + if (column_idx >= ia->column_cnt) + { + struct column *column; + + 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 (ia->file.line_cnt, + 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 (&s->separators), ss_first (text)) + != SIZE_MAX) + ss_advance (&text, 1); + } + } + } + + /* Chooses a name for each column on the separators page */ + static void + choose_column_names (struct import_assistant *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++) + { + 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); + + col->name = name; + dict_create_var_assert (dict, name, 0); + } + dict_destroy (dict); + } + + /* Picks the most likely separator and quote characters based on + IA's file data. */ + static void + choose_likely_separators (struct import_assistant *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->file.line_cnt; row++) + { + struct substring line = ds_ss (&ia->file.lines[row]); + size_t length = ss_length (line); + size_t i; + for (i = 0; i < length; i++) + histogram[(unsigned char) line.string[i]]++; + } + + find_commonest_chars (histogram, "\"'", "", &ia->separators->quotes); + find_commonest_chars (histogram, ",;:/|!\t-", ",", &ia->separators->separators); + ia->separators->escape = true; + } + + /* 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) + { + unsigned char max = 0; + unsigned long int max_count = 0; + + 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); + } + + /* Revises the contents of the fields tree view based on the + currently chosen set of separators. */ + static void + revise_fields_preview (struct import_assistant *ia) + { + GtkWidget *w; + + push_watch_cursor (ia); + + w = GTK_WIDGET (ia->separators->fields_tree_view); + gtk_widget_destroy (w); + get_separators (ia); + split_fields (ia); + choose_column_names (ia); + ia->separators->fields_tree_view = create_data_tree_view ( + true, + GTK_CONTAINER (get_widget_assert (ia->asst.builder, "fields-scroller")), + ia); + + pop_watch_cursor (ia); + } + + /* Sets the widgets to match IA's separators substructure. */ + static void + set_separators (struct import_assistant *ia) + { + struct separators_page *s = ia->separators; + 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 (&s->separators); i++) + { + unsigned char c = ds_at (&s->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->asst.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 (s->custom_entry), ds_cstr (&custom)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->custom_cb), + any_custom); + gtk_widget_set_sensitive (s->custom_entry, any_custom); + ds_destroy (&custom); + + any_quotes = !ds_is_empty (&s->quotes); + + gtk_entry_set_text (s->quote_entry, + any_quotes ? ds_cstr (&s->quotes) : "\""); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->quote_cb), + any_quotes); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->escape_cb), + s->escape); + gtk_widget_set_sensitive (s->quote_combo, any_quotes); + gtk_widget_set_sensitive (s->escape_cb, any_quotes); + } + + /* Sets IA's separators substructure to match the widgets. */ + static void + get_separators (struct import_assistant *ia) + { + struct separators_page *s = ia->separators; + int i; + + ds_clear (&s->separators); + for (i = 0; i < SEPARATOR_CNT; i++) + { + const struct separator *sep = &separators[i]; + GtkWidget *button = get_widget_assert (ia->asst.builder, sep->name); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) + ds_put_byte (&s->separators, sep->c); + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->custom_cb))) + ds_put_cstr (&s->separators, + gtk_entry_get_text (GTK_ENTRY (s->custom_entry))); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->quote_cb))) + { + gchar *text = gtk_combo_box_get_active_text ( + GTK_COMBO_BOX (s->quote_combo)); + ds_assign_cstr (&s->quotes, text); + g_free (text); + } + else + ds_clear (&s->quotes); + s->escape = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->escape_cb)); + } + + /* Called when the user changes the entry field for custom + separators. */ + static void + on_separators_custom_entry_notify (GObject *gobject UNUSED, + GParamSpec *arg1 UNUSED, + struct import_assistant *ia) + { + revise_fields_preview (ia); + } + + /* Called when the user toggles the checkbox that enables custom + separators. */ + static void + on_separators_custom_cb_toggle (GtkToggleButton *custom_cb, + struct import_assistant *ia) + { + bool is_active = gtk_toggle_button_get_active (custom_cb); + gtk_widget_set_sensitive (ia->separators->custom_entry, is_active); + revise_fields_preview (ia); + } + + /* Called when the user changes the selection in the combo box + that selects a quote character. */ + static void + on_quote_combo_change (GtkComboBox *combo, struct import_assistant *ia) + { + revise_fields_preview (ia); + } + + /* Called when the user toggles the checkbox that enables + quoting. */ + static void + on_quote_cb_toggle (GtkToggleButton *quote_cb, struct import_assistant *ia) + { + bool is_active = gtk_toggle_button_get_active (quote_cb); + gtk_widget_set_sensitive (ia->separators->quote_combo, is_active); + gtk_widget_set_sensitive (ia->separators->escape_cb, is_active); + revise_fields_preview (ia); + } + + /* Called when the user toggles one of the separators + checkboxes. */ + static void + on_separator_toggle (GtkToggleButton *toggle UNUSED, + struct import_assistant *ia) + { + revise_fields_preview (ia); + } + + + + void + separators_append_syntax (const struct import_assistant *ia, struct string *s) + { + int i; + ds_put_cstr (s, " /DELIMITERS=\""); + if (ds_find_byte (&ia->separators->separators, '\t') != SIZE_MAX) + ds_put_cstr (s, "\\t"); + if (ds_find_byte (&ia->separators->separators, '\\') != SIZE_MAX) + ds_put_cstr (s, "\\\\"); + for (i = 0; i < ds_length (&ia->separators->separators); i++) + { + char c = ds_at (&ia->separators->separators, i); + if (c == '"') + ds_put_cstr (s, "\"\""); + else if (c != '\t' && c != '\\') + ds_put_byte (s, c); + } + ds_put_cstr (s, "\"\n"); + if (!ds_is_empty (&ia->separators->quotes)) + syntax_gen_pspp (s, " /QUALIFIER=%sq\n", ds_cstr (&ia->separators->quotes)); + if (!ds_is_empty (&ia->separators->quotes) && ia->separators->escape) + ds_put_cstr (s, " /ESCAPE\n"); + } diff --cc src/ui/gui/psppire-data-window.c index 73c98b383e,500877bdd3..ce9309b1ce --- a/src/ui/gui/psppire-data-window.c +++ b/src/ui/gui/psppire-data-window.c @@@ -938,9 -1026,13 +938,9 @@@ psppire_data_window_finish_init (Psppir G_CALLBACK (enable_save), de); enable_save (de); - connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy)); - - connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut)); - connect_action (de, "file_new_data", G_CALLBACK (create_data_window)); - connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant)); + connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant)); connect_action (de, "file_save", G_CALLBACK (psppire_window_save)); diff --cc src/ui/gui/text-data-import-dialog.c index 4badb6550d,20bac652cc..ce23093fee --- a/src/ui/gui/text-data-import-dialog.c +++ b/src/ui/gui/text-data-import-dialog.c @@@ -18,8 -18,14 +18,13 @@@ #include "ui/gui/text-data-import-dialog.h" + #include "page-intro.h" + #include "page-first-line.h" + #include "page-separators.h" + #include "page-formats.h" + #include #include -#include #include #include #include @@@ -40,14 -45,14 +44,15 @@@ #include "ui/gui/dialog-common.h" #include "ui/gui/executor.h" #include "ui/gui/helper.h" + #include "ui/gui/builder-wrapper.h" +#include "ui/gui/pspp-sheet-selection.h" +#include "ui/gui/pspp-sheet-view.h" #include "ui/gui/psppire-data-window.h" #include "ui/gui/psppire-dialog.h" #include "ui/gui/psppire-encoding-selector.h" #include "ui/gui/psppire-empty-list-store.h" - #include "ui/gui/psppire-scanf.h" #include "ui/gui/psppire-var-sheet.h" -#include "ui/gui/psppire-var-store.h" + #include "ui/gui/psppire-scanf.h" #include "ui/syntax-gen.h" #include "gl/error.h" @@@ -63,162 -68,8 +68,8 @@@ struct import_assistant static void apply_dict (const struct dictionary *, struct string *); static char *generate_syntax (const struct import_assistant *); - static gboolean get_tooltip_location (GtkWidget *widget, gint wx, gint wy, - const struct import_assistant *, - size_t *row, size_t *column); - static void make_tree_view (const struct import_assistant *ia, - size_t first_line, - PsppSheetView **tree_view); static void add_line_number_column (const struct import_assistant *, - GtkTreeView *); + PsppSheetView *); - static gint get_monospace_width (PsppSheetView *, GtkCellRenderer *, - size_t char_cnt); - static gint get_string_width (PsppSheetView *, GtkCellRenderer *, - const char *string); - static PsppSheetViewColumn *make_data_column (struct import_assistant *, - PsppSheetView *, bool input, - gint column_idx); - static PsppSheetView *create_data_tree_view (bool input, GtkContainer *parent, - struct import_assistant *); - static void push_watch_cursor (struct import_assistant *); - static void pop_watch_cursor (struct import_assistant *); /* Pops up the Text Data Import assistant. */ void @@@ -354,701 -222,36 +222,36 @@@ static char generate_syntax (const struct import_assistant *ia) { struct string s = DS_EMPTY_INITIALIZER; - size_t var_cnt; - size_t i; - - syntax_gen_pspp (&s, - "GET DATA\n" - " /TYPE=TXT\n" - " /FILE=%sq\n", - ia->file.file_name); - if (ia->file.encoding && strcmp (ia->file.encoding, "Auto")) - syntax_gen_pspp (&s, " /ENCODING=%sq\n", ia->file.encoding); - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( - ia->intro.n_cases_button))) - ds_put_format (&s, " /IMPORTCASES=FIRST %d\n", - gtk_spin_button_get_value_as_int ( - GTK_SPIN_BUTTON (ia->intro.n_cases_spin))); - else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( - ia->intro.percent_button))) - ds_put_format (&s, " /IMPORTCASES=PERCENT %d\n", - gtk_spin_button_get_value_as_int ( - GTK_SPIN_BUTTON (ia->intro.percent_spin))); - else - ds_put_cstr (&s, " /IMPORTCASES=ALL\n"); - ds_put_cstr (&s, - " /ARRANGEMENT=DELIMITED\n" - " /DELCASE=LINE\n"); - if (ia->first_line.skip_lines > 0) - ds_put_format (&s, " /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1); - ds_put_cstr (&s, " /DELIMITERS=\""); - if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX) - ds_put_cstr (&s, "\\t"); - if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX) - ds_put_cstr (&s, "\\\\"); - for (i = 0; i < ds_length (&ia->separators.separators); i++) - { - char c = ds_at (&ia->separators.separators, i); - if (c == '"') - ds_put_cstr (&s, "\"\""); - else if (c != '\t' && c != '\\') - ds_put_byte (&s, c); - } - ds_put_cstr (&s, "\"\n"); - if (!ds_is_empty (&ia->separators.quotes)) - syntax_gen_pspp (&s, " /QUALIFIER=%sq\n", ds_cstr (&ia->separators.quotes)); - if (!ds_is_empty (&ia->separators.quotes) && ia->separators.escape) - ds_put_cstr (&s, " /ESCAPE\n"); - ds_put_cstr (&s, " /VARIABLES=\n"); - - var_cnt = dict_get_var_cnt (ia->formats.dict); - for (i = 0; i < var_cnt; i++) - { - struct variable *var = dict_get_var (ia->formats.dict, i); - char format_string[FMT_STRING_LEN_MAX + 1]; - fmt_to_string (var_get_print_format (var), format_string); - ds_put_format (&s, " %s %s%s\n", - var_get_name (var), format_string, - i == var_cnt - 1 ? "." : ""); - } - - apply_dict (ia->formats.dict, &s); - - return ds_cstr (&s); - } - - /* Choosing a file and reading it. */ - - static char *choose_file (GtkWindow *parent_window, gchar **encodingp); - - /* Obtains the file to import from the user and initializes IA's - file substructure. PARENT_WINDOW must be the window to use - as the file chooser window's parent. - - Returns true if successful, false if the file name could not - be obtained or the file could not be read. */ - static bool - init_file (struct import_assistant *ia, GtkWindow *parent_window) - { - struct file *file = &ia->file; - enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */ - enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */ - struct line_reader *reader; - struct string input; - - file->file_name = choose_file (parent_window, &file->encoding); - if (file->file_name == NULL) - return false; - - reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY); - if (reader == NULL) - { - msg (ME, _("Could not open `%s': %s"), - file->file_name, strerror (errno)); - return false; - } - - ds_init_empty (&input); - file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines); - for (; file->line_cnt < MAX_PREVIEW_LINES; file->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"), - file->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."), - file->file_name, MAX_LINE_LEN); - line_reader_close (reader); - destroy_file (ia); - ds_destroy (&input); - return false; - } - - ds_init_cstr (&file->lines[file->line_cnt], - recode_string ("UTF-8", line_reader_get_encoding (reader), - ds_cstr (&input), ds_length (&input))); - } - ds_destroy (&input); - - if (file->line_cnt == 0) - { - msg (ME, _("`%s' is empty."), file->file_name); - line_reader_close (reader); - destroy_file (ia); - return false; - } - - /* Estimate the number of lines in the file. */ - if (file->line_cnt < MAX_PREVIEW_LINES) - file->total_lines = file->line_cnt; - else - { - struct stat s; - off_t position = line_reader_tell (reader); - if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0) - file->total_lines = (double) file->line_cnt / position * s.st_size; - else - file->total_lines = 0; - } - - line_reader_close (reader); - - return true; - } - - /* Frees IA's file substructure. */ - static void - destroy_file (struct import_assistant *ia) - { - struct file *f = &ia->file; - size_t i; - - for (i = 0; i < f->line_cnt; i++) - ds_destroy (&f->lines[i]); - free (f->lines); - g_free (f->file_name); - g_free (f->encoding); - } - - /* Obtains the file to read from the user. If successful, returns the name of - the file and stores the user's chosen encoding for the file into *ENCODINGP. - The caller must free each of these strings with g_free(). - - On failure, stores a null pointer and stores NULL in *ENCODINGP. - - PARENT_WINDOW must be the window to use as the file chooser window's - parent. */ - static char * - choose_file (GtkWindow *parent_window, gchar **encodingp) - { - char *file_name; - GtkFileFilter *filter = NULL; - - GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"), - parent_window, - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - - g_object_set (dialog, "local-only", FALSE, NULL); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Text files")); - gtk_file_filter_add_mime_type (filter, "text/*"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Text (*.txt) Files")); - gtk_file_filter_add_pattern (filter, "*.txt"); - gtk_file_filter_add_pattern (filter, "*.TXT"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files")); - gtk_file_filter_add_mime_type (filter, "text/plain"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Comma Separated Value Files")); - gtk_file_filter_add_mime_type (filter, "text/csv"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - /* I've never encountered one of these, but it's listed here: - http://www.iana.org/assignments/media-types/text/tab-separated-values */ - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Tab Separated Value Files")); - gtk_file_filter_add_mime_type (filter, "text/tab-separated-values"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - gtk_file_chooser_set_extra_widget ( - GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true)); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("All Files")); - gtk_file_filter_add_pattern (filter, "*"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - switch (gtk_dialog_run (GTK_DIALOG (dialog))) - { - case GTK_RESPONSE_ACCEPT: - file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - *encodingp = psppire_encoding_selector_get_encoding ( - gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog))); - break; - default: - file_name = NULL; - *encodingp = NULL; - break; - } - gtk_widget_destroy (dialog); - - return file_name; - } - - /* Assistant. */ - - static void close_assistant (struct import_assistant *, int response); - static void on_prepare (GtkAssistant *assistant, GtkWidget *page, - struct import_assistant *); - static void on_cancel (GtkAssistant *assistant, struct import_assistant *); - static void on_close (GtkAssistant *assistant, struct import_assistant *); - static void on_paste (GtkButton *button, struct import_assistant *); - static void on_reset (GtkButton *button, struct import_assistant *); - static void close_assistant (struct import_assistant *, int response); - - /* Initializes IA's asst substructure. PARENT_WINDOW must be the - window to use as the assistant window's parent. */ - static void - init_assistant (struct import_assistant *ia, GtkWindow *parent_window) - { - struct assistant *a = &ia->asst; - - a->builder = builder_new ("text-data-import.ui"); - a->assistant = GTK_ASSISTANT (gtk_assistant_new ()); - g_signal_connect (a->assistant, "prepare", G_CALLBACK (on_prepare), ia); - g_signal_connect (a->assistant, "cancel", G_CALLBACK (on_cancel), ia); - g_signal_connect (a->assistant, "close", G_CALLBACK (on_close), ia); - a->paste_button = gtk_button_new_from_stock (GTK_STOCK_PASTE); - gtk_assistant_add_action_widget (a->assistant, a->paste_button); - g_signal_connect (a->paste_button, "clicked", G_CALLBACK (on_paste), ia); - a->reset_button = gtk_button_new_from_stock ("pspp-stock-reset"); - gtk_assistant_add_action_widget (a->assistant, a->reset_button); - g_signal_connect (a->reset_button, "clicked", G_CALLBACK (on_reset), ia); - gtk_window_set_title (GTK_WINDOW (a->assistant), - _("Importing Delimited Text Data")); - gtk_window_set_transient_for (GTK_WINDOW (a->assistant), parent_window); - gtk_window_set_icon_name (GTK_WINDOW (a->assistant), "pspp"); - - a->prop_renderer = gtk_cell_renderer_text_new (); - g_object_ref_sink (a->prop_renderer); - a->fixed_renderer = gtk_cell_renderer_text_new (); - g_object_ref_sink (a->fixed_renderer); - g_object_set (G_OBJECT (a->fixed_renderer), - "family", "Monospace", - (void *) NULL); - } - - /* Frees IA's asst substructure. */ - static void - destroy_assistant (struct import_assistant *ia) - { - struct assistant *a = &ia->asst; - - g_object_unref (a->prop_renderer); - g_object_unref (a->fixed_renderer); - g_object_unref (a->builder); - } - - /* Appends a page of the given TYPE, with PAGE as its content, to - the GtkAssistant encapsulated by IA. Returns the GtkWidget - that represents the page. */ - static GtkWidget * - add_page_to_assistant (struct import_assistant *ia, - GtkWidget *page, GtkAssistantPageType type) - { - const char *title; - char *title_copy; - GtkWidget *content; - - title = gtk_window_get_title (GTK_WINDOW (page)); - title_copy = xstrdup (title ? title : ""); - - content = gtk_bin_get_child (GTK_BIN (page)); - assert (content); - g_object_ref (content); - gtk_container_remove (GTK_CONTAINER (page), content); - - gtk_widget_destroy (page); - - gtk_assistant_append_page (ia->asst.assistant, content); - gtk_assistant_set_page_type (ia->asst.assistant, content, type); - gtk_assistant_set_page_title (ia->asst.assistant, content, title_copy); - gtk_assistant_set_page_complete (ia->asst.assistant, content, true); - - free (title_copy); - - return content; - } - - /* Called just before PAGE is displayed as the current page of - ASSISTANT, this updates IA content according to the new - page. */ - static void - on_prepare (GtkAssistant *assistant, GtkWidget *page, - struct import_assistant *ia) - { - - if (gtk_assistant_get_page_type (assistant, page) - == GTK_ASSISTANT_PAGE_CONFIRM) - gtk_widget_grab_focus (assistant->apply); - else - gtk_widget_grab_focus (assistant->forward); - - if (page == ia->separators.page) - prepare_separators_page (ia); - else if (page == ia->formats.page) - prepare_formats_page (ia); - - gtk_widget_show (ia->asst.reset_button); - if (page == ia->formats.page) - gtk_widget_show (ia->asst.paste_button); - else - gtk_widget_hide (ia->asst.paste_button); - } - - /* Called when the Cancel button in the assistant is clicked. */ - static void - on_cancel (GtkAssistant *assistant, struct import_assistant *ia) - { - close_assistant (ia, GTK_RESPONSE_CANCEL); - } - - /* Called when the Apply button on the last page of the assistant - is clicked. */ - static void - on_close (GtkAssistant *assistant, struct import_assistant *ia) - { - close_assistant (ia, GTK_RESPONSE_APPLY); - } - - /* Called when the Paste button on the last page of the assistant - is clicked. */ - static void - on_paste (GtkButton *button, struct import_assistant *ia) - { - close_assistant (ia, PSPPIRE_RESPONSE_PASTE); - } - - /* Called when the Reset button is clicked. */ - static void - on_reset (GtkButton *button, struct import_assistant *ia) - { - gint page_num = gtk_assistant_get_current_page (ia->asst.assistant); - GtkWidget *page = gtk_assistant_get_nth_page (ia->asst.assistant, page_num); - - if (page == ia->intro.page) - reset_intro_page (ia); - else if (page == ia->first_line.page) - reset_first_line_page (ia); - else if (page == ia->separators.page) - reset_separators_page (ia); - else if (page == ia->formats.page) - reset_formats_page (ia); - } - - /* Causes the assistant to close, returning RESPONSE for - interpretation by text_data_import_assistant. */ - static void - close_assistant (struct import_assistant *ia, int response) - { - ia->asst.response = response; - g_main_loop_quit (ia->asst.main_loop); - gtk_widget_hide (GTK_WIDGET (ia->asst.assistant)); - } - - /* The "intro" page of the assistant. */ - - static void on_intro_amount_changed (struct import_assistant *); - - /* Initializes IA's intro substructure. */ - static void - init_intro_page (struct import_assistant *ia) - { - GtkBuilder *builder = ia->asst.builder; - struct intro_page *p = &ia->intro; - struct string s; - GtkWidget *hbox_n_cases ; - GtkWidget *hbox_percent ; - GtkWidget *table ; - - - p->n_cases_spin = gtk_spin_button_new_with_range (0, INT_MAX, 100); - - hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &p->n_cases_spin); - - table = get_widget_assert (builder, "button-table"); - - gtk_table_attach_defaults (GTK_TABLE (table), hbox_n_cases, - 1, 2, - 1, 2); - - p->percent_spin = gtk_spin_button_new_with_range (0, 100, 10); - - hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), &p->percent_spin); - - gtk_table_attach_defaults (GTK_TABLE (table), hbox_percent, - 1, 2, - 2, 3); - - p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Intro"), - GTK_ASSISTANT_PAGE_INTRO); - - p->all_cases_button = get_widget_assert (builder, "import-all-cases"); - p->n_cases_button = get_widget_assert (builder, "import-n-cases"); - - p->percent_button = get_widget_assert (builder, "import-percent"); - - g_signal_connect_swapped (p->all_cases_button, "toggled", - G_CALLBACK (on_intro_amount_changed), ia); - g_signal_connect_swapped (p->n_cases_button, "toggled", - G_CALLBACK (on_intro_amount_changed), ia); - g_signal_connect_swapped (p->percent_button, "toggled", - G_CALLBACK (on_intro_amount_changed), ia); - - on_intro_amount_changed (ia); - - 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->file.total_is_exact) - ds_put_format ( - &s, ngettext ("The selected file contains %zu line of text. ", - "The selected file contains %zu lines of text. ", - ia->file.line_cnt), - ia->file.line_cnt); - else if (ia->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->file.total_lines), - ia->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->file.line_cnt), - ia->file.line_cnt); - } - ds_put_cstr (&s, _("You may choose below how much of the file should " - "actually be imported.")); - gtk_label_set_text (GTK_LABEL (get_widget_assert (builder, "intro-label")), - ds_cstr (&s)); - ds_destroy (&s); - } - - /* Resets IA's intro page to its initial state. */ - static void - reset_intro_page (struct import_assistant *ia) - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->intro.all_cases_button), - true); - } - - /* Called when one of the radio buttons is clicked. */ - static void - on_intro_amount_changed (struct import_assistant *ia) - { - struct intro_page *p = &ia->intro; - - gtk_widget_set_sensitive (p->n_cases_spin, - 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))); - } - - /* The "first line" page of the assistant. */ - - static PsppSheetView *create_lines_tree_view (GtkContainer *parent_window, - struct import_assistant *); - static void on_first_line_change (PsppSheetSelection *, - struct import_assistant *); - static void on_variable_names_cb_toggle (GtkToggleButton *, - struct import_assistant *); - static void set_first_line (struct import_assistant *); - static void get_first_line (struct import_assistant *); - - /* Initializes IA's first_line substructure. */ - static void - init_first_line_page (struct import_assistant *ia) - { - struct first_line_page *p = &ia->first_line; - GtkBuilder *builder = ia->asst.builder; - - p->page = add_page_to_assistant (ia, get_widget_assert (builder, "FirstLine"), - GTK_ASSISTANT_PAGE_CONTENT); - gtk_widget_destroy (get_widget_assert (builder, "first-line")); - p->tree_view = create_lines_tree_view ( - GTK_CONTAINER (get_widget_assert (builder, "first-line-scroller")), ia); - p->variable_names_cb = get_widget_assert (builder, "variable-names"); - pspp_sheet_selection_set_mode ( - pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (p->tree_view)), - PSPP_SHEET_SELECTION_BROWSE); - pspp_sheet_view_set_rubber_banding (PSPP_SHEET_VIEW (p->tree_view), TRUE); - set_first_line (ia); - g_signal_connect (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (p->tree_view)), - "changed", G_CALLBACK (on_first_line_change), ia); - g_signal_connect (p->variable_names_cb, "toggled", - G_CALLBACK (on_variable_names_cb_toggle), ia); - } - - /* Resets the first_line page to its initial content. */ - static void - reset_first_line_page (struct import_assistant *ia) - { - ia->first_line.skip_lines = 0; - ia->first_line.variable_names = false; - set_first_line (ia); - } + syntax_gen_pspp (&s, + "GET DATA" + "\n /TYPE=TXT" + "\n /FILE=%sq\n", + ia->file.file_name); + if (ia->file.encoding && strcmp (ia->file.encoding, "Auto")) + syntax_gen_pspp (&s, " /ENCODING=%sq\n", ia->file.encoding); - 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); + intro_append_syntax (ia->intro, &s); - g_object_set (cell, "text", ds_cstr (&lines[row]), NULL); - } + ds_put_cstr (&s, + " /ARRANGEMENT=DELIMITED\n" + " /DELCASE=LINE\n"); - /* Creates and returns a tree view that contains each of the - lines in IA's file as a row. */ - static PsppSheetView * - create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia) - { - PsppSheetView *tree_view; - PsppSheetViewColumn *column; - size_t max_line_length; - gint content_width, header_width; - size_t i; - const gchar *title = _("Text"); - - make_tree_view (ia, 0, &tree_view); - - column = pspp_sheet_view_column_new_with_attributes ( - title, ia->asst.fixed_renderer, (void *) NULL); - pspp_sheet_view_column_set_cell_data_func (column, ia->asst.fixed_renderer, - render_line, NULL, NULL); - pspp_sheet_view_column_set_resizable (column, TRUE); - - max_line_length = 0; - for (i = 0; i < ia->file.line_cnt; i++) - { - size_t w = ds_length (&ia->file.lines[i]); - max_line_length = MAX (max_line_length, w); + first_line_append_syntax (ia, &s); + separators_append_syntax (ia, &s); + formats_append_syntax (ia, &s); + apply_dict (ia->dict, &s); } - content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer, - max_line_length); - header_width = get_string_width (tree_view, ia->asst.prop_renderer, title); - pspp_sheet_view_column_set_fixed_width (column, MAX (content_width, - header_width)); - pspp_sheet_view_append_column (tree_view, column); - - gtk_container_add (parent, GTK_WIDGET (tree_view)); - gtk_widget_show (GTK_WIDGET (tree_view)); - - return tree_view; - } - - /* Called when the line selected in the first_line tree view - changes. */ - static void - on_first_line_change (PsppSheetSelection *selection UNUSED, - struct import_assistant *ia) - { - get_first_line (ia); - } - - /* Called when the checkbox that indicates whether variable - names are in the row above the first line is toggled. */ - static void - on_variable_names_cb_toggle (GtkToggleButton *variable_names_cb UNUSED, - struct import_assistant *ia) - { - get_first_line (ia); + return ds_cstr (&s); } - /* Sets the widgets to match IA's first_line substructure. */ - static void - set_first_line (struct import_assistant *ia) - { - GtkTreePath *path; - path = gtk_tree_path_new_from_indices (ia->first_line.skip_lines, -1); - pspp_sheet_view_set_cursor (PSPP_SHEET_VIEW (ia->first_line.tree_view), - path, NULL, false); - gtk_tree_path_free (path); - - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON (ia->first_line.variable_names_cb), - ia->first_line.variable_names); - gtk_widget_set_sensitive (ia->first_line.variable_names_cb, - ia->first_line.skip_lines > 0); - } - - /* Sets IA's first_line substructure to match the widgets. */ - static void - get_first_line (struct import_assistant *ia) - { - PsppSheetSelection *selection; - GtkTreeIter iter; - GtkTreeModel *model; - selection = pspp_sheet_view_get_selection (ia->first_line.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->first_line.skip_lines = row; - ia->first_line.variable_names = - (ia->first_line.skip_lines > 0 - && gtk_toggle_button_get_active ( - GTK_TOGGLE_BUTTON (ia->first_line.variable_names_cb))); - } - gtk_widget_set_sensitive (ia->first_line.variable_names_cb, - ia->first_line.skip_lines > 0); - } - - /* The "separators" page of the assistant. */ - - static void revise_fields_preview (struct import_assistant *ia); - static void choose_likely_separators (struct import_assistant *ia); - static void find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1], - const char *targets, const char *def, - struct string *result); - static void clear_fields (struct import_assistant *ia); - static void revise_fields_preview (struct import_assistant *); - static void set_separators (struct import_assistant *); - static void get_separators (struct import_assistant *); - static void on_separators_custom_entry_notify (GObject *UNUSED, - GParamSpec *UNUSED, - struct import_assistant *); - static void on_separators_custom_cb_toggle (GtkToggleButton *custom_cb, - struct import_assistant *); - static void on_quote_combo_change (GtkComboBox *combo, - struct import_assistant *); - static void on_quote_cb_toggle (GtkToggleButton *quote_cb, - struct import_assistant *); - static void on_separator_toggle (GtkToggleButton *, struct import_assistant *); -static void render_input_cell (GtkTreeViewColumn *tree_column, +static void render_input_cell (PsppSheetViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer ia); @@@ -1943,9 -468,9 +468,9 @@@ get_tooltip_location (GtkWidget *widget if (!gtk_widget_get_mapped (widget)) return FALSE; - gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, - wx, wy, &bx, &by); - if (!gtk_tree_view_get_path_at_pos (tree_view, bx, by, + pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view, - wx, wy, &bx, &by); ++ wx, wy, &bx, &by); + if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by, &path, &tree_column, NULL, NULL)) return FALSE; @@@ -1962,17 -487,16 +487,17 @@@ return TRUE; } - static void + void make_tree_view (const struct import_assistant *ia, size_t first_line, - GtkTreeView **tree_view) + PsppSheetView **tree_view) { GtkTreeModel *model; - *tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); + *tree_view = PSPP_SHEET_VIEW (pspp_sheet_view_new ()); + pspp_sheet_view_set_grid_lines (*tree_view, PSPP_SHEET_VIEW_GRID_LINES_BOTH); model = GTK_TREE_MODEL (psppire_empty_list_store_new ( - ia->file.line_cnt - first_line)); + ia->file.line_cnt - first_line)); g_object_set_data (G_OBJECT (model), "lines", ia->file.lines + first_line); g_object_set_data (G_OBJECT (model), "first-line", GINT_TO_POINTER (first_line)); @@@ -2001,22 -525,23 +526,22 @@@ render_line_number (PsppSheetViewColum static void add_line_number_column (const struct import_assistant *ia, - GtkTreeView *treeview) + PsppSheetView *treeview) { - GtkTreeViewColumn *column; - - column = gtk_tree_view_column_new_with_attributes ( - _("Line"), ia->asst.prop_renderer, (void *) NULL); - gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); - gtk_tree_view_column_set_fixed_width ( - column, get_monospace_width (treeview, ia->asst.prop_renderer, 5)); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_cell_data_func (column, ia->asst.prop_renderer, - render_line_number, NULL, NULL); - gtk_tree_view_append_column (treeview, column); + PsppSheetViewColumn *column; + + column = pspp_sheet_view_column_new_with_attributes ( + _("Line"), ia->asst.prop_renderer, (void *) NULL); + pspp_sheet_view_column_set_fixed_width ( + column, get_monospace_width (treeview, ia->asst.prop_renderer, 5)); + pspp_sheet_view_column_set_resizable (column, TRUE); + pspp_sheet_view_column_set_cell_data_func (column, ia->asst.prop_renderer, + render_line_number, NULL, NULL); + pspp_sheet_view_append_column (treeview, column); } - static gint + gint -get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer, +get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer, size_t char_cnt) { struct string s; @@@ -2031,8 -556,8 +556,8 @@@ return width; } - static gint + gint -get_string_width (GtkTreeView *treeview, GtkCellRenderer *renderer, +get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer, const char *string) { gint width; @@@ -2042,8 -567,8 +567,8 @@@ return width; } - static PsppSheetViewColumn * -GtkTreeViewColumn * -make_data_column (struct import_assistant *ia, GtkTreeView *tree_view, ++PsppSheetViewColumn * +make_data_column (struct import_assistant *ia, PsppSheetView *tree_view, bool input, gint dict_idx) { struct variable *var = NULL; @@@ -2065,44 -590,45 +590,44 @@@ header_width = get_string_width (tree_view, ia->asst.prop_renderer, name); - tree_column = gtk_tree_view_column_new (); + tree_column = pspp_sheet_view_column_new (); g_object_set_data (G_OBJECT (tree_column), "column-number", GINT_TO_POINTER (dict_idx)); - gtk_tree_view_column_set_title (tree_column, name); - gtk_tree_view_column_pack_start (tree_column, ia->asst.fixed_renderer, - FALSE); - gtk_tree_view_column_set_cell_data_func ( - tree_column, ia->asst.fixed_renderer, - input ? render_input_cell : render_output_cell, ia, NULL); - gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_FIXED); - gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width, - header_width)); + pspp_sheet_view_column_set_title (tree_column, name); + pspp_sheet_view_column_pack_start (tree_column, ia->asst.fixed_renderer, - FALSE); ++ FALSE); + pspp_sheet_view_column_set_cell_data_func ( + tree_column, ia->asst.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)); - pspp_sheet_view_column_set_resizable (tree_column, TRUE); ++ header_width)); free (name); return tree_column; } - static PsppSheetView * -GtkTreeView * ++PsppSheetView * create_data_tree_view (bool input, GtkContainer *parent, struct import_assistant *ia) { - GtkTreeView *tree_view; + PsppSheetView *tree_view; gint i; - make_tree_view (ia, ia->first_line.skip_lines, &tree_view); + make_tree_view (ia, ia->skip_lines, &tree_view); - gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view), - GTK_SELECTION_NONE); + pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (tree_view), - PSPP_SHEET_SELECTION_NONE); ++ PSPP_SHEET_SELECTION_NONE); - for (i = 0; i < ia->separators.column_cnt; i++) + for (i = 0; i < ia->column_cnt; i++) - gtk_tree_view_append_column (tree_view, - make_data_column (ia, tree_view, input, i)); + pspp_sheet_view_append_column (tree_view, - make_data_column (ia, tree_view, input, i)); ++ make_data_column (ia, tree_view, input, i)); 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); - gtk_tree_view_set_fixed_height_mode (tree_view, true); + + gtk_container_add (parent, GTK_WIDGET (tree_view)); gtk_widget_show (GTK_WIDGET (tree_view)); diff --cc src/ui/gui/text-data-import-dialog.h index 664249c964,0c026858fe..59b5819c3e --- a/src/ui/gui/text-data-import-dialog.h +++ b/src/ui/gui/text-data-import-dialog.h @@@ -22,4 -114,54 +114,54 @@@ GtkWidget * add_page_to_assistant (stru void text_data_import_assistant (PsppireDataWindow *); + /* FIXME: Should this be private to first line page ? */ + void make_tree_view (const struct import_assistant *ia, + size_t first_line, - GtkTreeView **tree_view); ++ PsppSheetView **tree_view); + -gint get_monospace_width (GtkTreeView *, GtkCellRenderer *, ++gint get_monospace_width (PsppSheetView *, GtkCellRenderer *, + size_t char_cnt); -gint get_string_width (GtkTreeView *, GtkCellRenderer *, ++gint get_string_width (PsppSheetView *, GtkCellRenderer *, + const char *string); + + + + void push_watch_cursor (struct import_assistant *); + void pop_watch_cursor (struct import_assistant *); + + -GtkTreeView *create_data_tree_view (bool input, GtkContainer *parent, - struct import_assistant *); ++PsppSheetView *create_data_tree_view (bool input, GtkContainer *parent, ++ struct import_assistant *); + -GtkTreeViewColumn *make_data_column (struct import_assistant *, - GtkTreeView *, bool input, - gint column_idx); ++PsppSheetViewColumn *make_data_column (struct import_assistant *, ++ PsppSheetView *, bool input, ++ gint column_idx); + + + void update_assistant (struct import_assistant *ia); + + bool init_file (struct import_assistant *ia, GtkWindow *parent_window); + void destroy_file (struct import_assistant *ia); + + void prepare_sheet_spec_page (struct import_assistant *ia); + void reset_sheet_spec_page (struct import_assistant *); + void post_sheet_spec_page (struct import_assistant *ia); + + void prepare_first_line_page (struct import_assistant *ia); + void reset_first_line_page (struct import_assistant *); + + void reset_intro_page (struct import_assistant *ia); + + void prepare_separators_page (struct import_assistant *ia); + void reset_separators_page (struct import_assistant *); + void destroy_separators_page (struct import_assistant *ia); + + void prepare_formats_page (struct import_assistant *ia); + void reset_formats_page (struct import_assistant *); + void destroy_formats_page (struct import_assistant *ia); + + struct import_assistant * init_assistant (GtkWindow *); + void destroy_assistant (struct import_assistant *); + + #endif