From e4902aff3ef2f8865a2d304ce0979d7aed1c35c0 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Sat, 5 Jan 2013 20:35:23 +0100 Subject: [PATCH] Basic working spreadsheet import dialog (sort of) --- src/ui/gui/automake.mk | 1 + src/ui/gui/page-file.c | 149 +++++++++++++++------------ src/ui/gui/page-formats.c | 7 +- src/ui/gui/page-sheet-spec.c | 85 +++++++++++++++ src/ui/gui/text-data-import-dialog.c | 144 +++++++++++++++----------- src/ui/gui/text-data-import-dialog.h | 20 ++++ src/ui/gui/text-data-import.ui | 120 +++++++++++++++++++++ 7 files changed, 399 insertions(+), 127 deletions(-) create mode 100644 src/ui/gui/page-sheet-spec.c diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index 955d8391c6..eba09d0036 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -310,6 +310,7 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/page-first-line.c \ src/ui/gui/page-formats.c \ src/ui/gui/page-separators.c \ + src/ui/gui/page-sheet-spec.c \ src/ui/gui/text-data-import-dialog.c \ src/ui/gui/text-data-import-dialog.h \ src/ui/gui/transpose-dialog.c \ diff --git a/src/ui/gui/page-file.c b/src/ui/gui/page-file.c index ff135f677f..e4cb781559 100644 --- a/src/ui/gui/page-file.c +++ b/src/ui/gui/page-file.c @@ -29,6 +29,8 @@ #include "data/data-in.h" #include "data/data-out.h" #include "data/format-guesser.h" +#include "data/gnumeric-reader.h" +#include "data/spreadsheet-reader.h" #include "data/value-labels.h" #include "language/data-io/data-parser.h" #include "language/lexer/lexer.h" @@ -74,75 +76,92 @@ 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); + struct dictionary *dict = NULL; + struct spreadsheet_read_info sri; + + sri.sheet_name = NULL; + sri.file_name = file->file_name; + sri.cell_range = NULL; + sri.sheet_index = 1; + sri.read_names = true; + sri.asw = 0; + + struct casereader *creader = gnumeric_open_reader (&sri, &dict); + printf ("%s:%d %s\n", __FILE__, __LINE__, sri.file_name); + ia->file.type = FTYPE_SPREADSHEET; + + if (creader == NULL) + { + enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */ + enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */ + + 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); + ia->file.type = FTYPE_TEXT; + } return true; } diff --git a/src/ui/gui/page-formats.c b/src/ui/gui/page-formats.c index ee9b540bdc..c79551fb04 100644 --- a/src/ui/gui/page-formats.c +++ b/src/ui/gui/page-formats.c @@ -104,7 +104,7 @@ prepare_formats_page (struct import_assistant *ia) GtkBin *vars_scroller; GtkWidget *old_var_sheet; PsppireVarSheet *var_sheet; - struct separators_page *s = &ia->separators; + struct separators_page *seps = &ia->separators; struct formats_page *p = &ia->formats; struct fmt_guesser *fg; unsigned long int number = 0; @@ -114,7 +114,8 @@ prepare_formats_page (struct import_assistant *ia) dict = dict_create (get_default_encoding ()); fg = fmt_guesser_create (); - for (column_idx = 0; column_idx < s->column_cnt; column_idx++) + printf ("%s:%d Column count %d\n", __FILE__, __LINE__, seps->column_cnt); + for (column_idx = 0; column_idx < seps->column_cnt; column_idx++) { struct variable *modified_var; @@ -122,7 +123,7 @@ prepare_formats_page (struct import_assistant *ia) ? p->modified_vars[column_idx] : NULL); if (modified_var == NULL) { - struct column *column = &s->columns[column_idx]; + struct column *column = &seps->columns[column_idx]; struct variable *var; struct fmt_spec format; char *name; diff --git a/src/ui/gui/page-sheet-spec.c b/src/ui/gui/page-sheet-spec.c new file mode 100644 index 0000000000..4905a78494 --- /dev/null +++ b/src/ui/gui/page-sheet-spec.c @@ -0,0 +1,85 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 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 "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 "sheet-spec" page of the assistant. */ + + +/* Initializes IA's sheet_spec substructure. */ +void +init_sheet_spec_page (struct import_assistant *ia) +{ + GtkBuilder *builder = ia->asst.builder; + struct sheet_spec_page *p = &ia->sheet_spec; + + p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Sheet"), + GTK_ASSISTANT_PAGE_INTRO); + +} + +/* Resets IA's sheet_spec page to its initial state. */ +void +reset_sheet_spec_page (struct import_assistant *ia) +{ +} + diff --git a/src/ui/gui/text-data-import-dialog.c b/src/ui/gui/text-data-import-dialog.c index bb7ce56e48..00e82a7035 100644 --- a/src/ui/gui/text-data-import-dialog.c +++ b/src/ui/gui/text-data-import-dialog.c @@ -79,10 +79,20 @@ text_data_import_assistant (PsppireDataWindow *dw) return; } + printf ("%s:%d %s\n", __FILE__, __LINE__, ia->file.file_name); + init_assistant (ia, parent_window); - init_intro_page (ia); - init_first_line_page (ia); - init_separators_page (ia); + if ( ia->file.type == FTYPE_TEXT) + { + init_intro_page (ia); + init_first_line_page (ia); + init_separators_page (ia); + } + else + { + init_sheet_spec_page (ia); + } + init_formats_page (ia); gtk_widget_show_all (GTK_WIDGET (ia->asst.assistant)); @@ -103,8 +113,12 @@ text_data_import_assistant (PsppireDataWindow *dw) break; } - destroy_formats_page (ia); - destroy_separators_page (ia); + if ( ia->file.type == FTYPE_TEXT) + { + destroy_formats_page (ia); + destroy_separators_page (ia); + } + destroy_assistant (ia); destroy_file (ia); free (ia); @@ -199,65 +213,77 @@ 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))); + if (ia->file.type == FTYPE_TEXT) + { + 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); + } 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 ? "." : ""); + syntax_gen_pspp (&s, + "GET DATA\n" + " /TYPE=GNM\n" + " /FILE=%sq\n", + ia->file.file_name); } - apply_dict (ia->formats.dict, &s); return ds_cstr (&s); } diff --git a/src/ui/gui/text-data-import-dialog.h b/src/ui/gui/text-data-import-dialog.h index 0966365d42..b23130d7f4 100644 --- a/src/ui/gui/text-data-import-dialog.h +++ b/src/ui/gui/text-data-import-dialog.h @@ -22,10 +22,21 @@ #include "libpspp/str.h" +enum file_type + { + FTYPE_TEXT, + FTYPE_SPREADSHEET + }; + /* The file to be imported. */ struct file { char *file_name; /* File name. */ + + enum file_type type; + + /* Relevant only for text files */ + gchar *encoding; /* Encoding. */ unsigned long int total_lines; /* Number of lines in file. */ bool total_is_exact; /* Is total_lines exact (or an estimate)? */ @@ -50,6 +61,14 @@ struct assistant GtkCellRenderer *fixed_renderer; }; + +/* The sheet_spec page of the assistant (only relevant for spreadsheet imports). */ +struct sheet_spec_page + { + GtkWidget *page; + }; + + /* The introduction page of the assistant. */ struct intro_page { @@ -113,6 +132,7 @@ struct import_assistant struct file file; struct assistant asst; struct intro_page intro; + struct sheet_spec_page sheet_spec; struct first_line_page first_line; struct separators_page separators; struct formats_page formats; diff --git a/src/ui/gui/text-data-import.ui b/src/ui/gui/text-data-import.ui index d8a33d118a..adc73e860d 100644 --- a/src/ui/gui/text-data-import.ui +++ b/src/ui/gui/text-data-import.ui @@ -666,4 +666,124 @@ The selected file contains N lines of text. Only the first M of these will be s 1 10 + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + Importing Textual Data + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Enter below the sheet number and the cell range which you wish to import. + True + + + 0 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + 2 + 2 + + + True + True + + + + 1 + 2 + + + + + + True + True + + + + 1 + 2 + 1 + 2 + + + + + + True + 1 + _Cells: + True + cell-range-entry + + + GTK_FILL + + + + + + True + 1 + _Sheet Index: + True + sheet-entry + + + 1 + 2 + GTK_FILL + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Cells to Import</b> + True + + + + + + + False + False + 1 + + + + + -- 2.30.2