1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "ui/gui/text-data-import-dialog.h"
23 #include <gtk-contrib/psppire-sheet.h>
29 #include "data/data-in.h"
30 #include "data/data-out.h"
31 #include "data/format-guesser.h"
32 #include "data/casereader.h"
33 #include "data/gnumeric-reader.h"
34 #include "data/ods-reader.h"
35 #include "data/spreadsheet-reader.h"
36 #include "data/value-labels.h"
37 #include "language/data-io/data-parser.h"
38 #include "language/lexer/lexer.h"
39 #include "libpspp/assertion.h"
40 #include "libpspp/i18n.h"
41 #include "libpspp/line-reader.h"
42 #include "libpspp/message.h"
43 #include "ui/gui/checkbox-treeview.h"
44 #include "ui/gui/dialog-common.h"
45 #include "ui/gui/executor.h"
46 #include "ui/gui/helper.h"
47 #include "ui/gui/builder-wrapper.h"
48 #include "ui/gui/psppire-data-window.h"
49 #include "ui/gui/psppire-dialog.h"
50 #include "ui/gui/psppire-encoding-selector.h"
51 #include "ui/gui/psppire-empty-list-store.h"
52 #include "ui/gui/psppire-var-sheet.h"
53 #include "ui/gui/psppire-var-store.h"
54 #include "ui/gui/psppire-scanf.h"
55 #include "ui/syntax-gen.h"
58 #include "gl/intprops.h"
59 #include "gl/xalloc.h"
62 #define _(msgid) gettext (msgid)
63 #define N_(msgid) msgid
65 struct import_assistant;
68 static char *choose_file (GtkWindow *parent_window, gchar **encodingp);
69 enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
73 Update IA according to the contents of DICT and CREADER.
74 CREADER will be destroyed by this function.
77 update_assistant (struct import_assistant *ia)
79 struct sheet_spec_page *ssp = &ia->sheet_spec;
81 struct file *file = &ia->file;
82 struct separators_page *sepp = &ia->separators;
90 sepp->column_cnt = dict_get_var_cnt (ssp->dict);
91 sepp->columns = xcalloc (sepp->column_cnt, sizeof (*sepp->columns));
92 for (col = 0; col < sepp->column_cnt ; ++col)
94 const struct variable *var = dict_get_var (ssp->dict, col);
95 sepp->columns[col].name = xstrdup (var_get_name (var));
96 sepp->columns[col].contents = NULL;
99 for (; (c = casereader_read (ssp->reader)) != NULL; case_unref (c))
102 for (col = 0; col < sepp->column_cnt ; ++col)
105 const struct variable *var = dict_get_var (ssp->dict, col);
107 sepp->columns[col].contents = xrealloc (sepp->columns[col].contents,
108 sizeof (struct substring) * rows);
110 ss = data_out (case_data (c, var), dict_get_encoding (ssp->dict),
111 var_get_print_format (var));
113 sepp->columns[col].contents[rows - 1] = ss_cstr (ss);
116 if (rows > MAX_PREVIEW_LINES)
124 file->line_cnt = rows;
128 /* Obtains the file to import from the user and initializes IA's
129 file substructure. PARENT_WINDOW must be the window to use
130 as the file chooser window's parent.
132 Returns true if successful, false if the file name could not
133 be obtained or the file could not be read. */
135 init_file (struct import_assistant *ia, GtkWindow *parent_window)
137 enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
138 struct file *file = &ia->file;
139 struct sheet_spec_page *ssp = &ia->sheet_spec;
140 struct spreadsheet_read_info sri;
141 struct spreadsheet_read_options opts;
144 file->file_name = choose_file (parent_window, &file->encoding);
145 if (file->file_name == NULL)
148 opts.sheet_name = NULL;
149 opts.cell_range = NULL;
150 opts.sheet_index = 1;
152 sri.file_name = file->file_name;
153 sri.read_names = true;
156 if (ssp->spreadsheet == NULL)
157 ssp->spreadsheet = gnumeric_probe (sri.file_name);
159 printf ("%s:%d %p %d\n", __FILE__, __LINE__, ssp->spreadsheet, ssp->spreadsheet->type);
161 if (ssp->spreadsheet == NULL)
162 ssp->spreadsheet = ods_probe (sri.file_name);
164 printf ("%s:%d %p %d\n", __FILE__, __LINE__, ssp->spreadsheet, ssp->spreadsheet->type);
166 if (ssp->spreadsheet)
169 // update_assistant (ia);
173 printf ("%s:%d %p\n", __FILE__, __LINE__, ssp->spreadsheet);
176 struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
179 msg (ME, _("Could not open `%s': %s"),
180 file->file_name, strerror (errno));
184 ds_init_empty (&input);
185 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
186 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
189 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
190 || ds_length (&input) > MAX_LINE_LEN)
192 if (line_reader_eof (reader))
194 else if (line_reader_error (reader))
195 msg (ME, _("Error reading `%s': %s"),
196 file->file_name, strerror (line_reader_error (reader)));
198 msg (ME, _("Failed to read `%s', because it contains a line "
199 "over %d bytes long and therefore appears not to be "
201 file->file_name, MAX_LINE_LEN);
202 line_reader_close (reader);
208 ds_init_cstr (&file->lines[file->line_cnt],
209 recode_string ("UTF-8", line_reader_get_encoding (reader),
210 ds_cstr (&input), ds_length (&input)));
214 if (file->line_cnt == 0)
216 msg (ME, _("`%s' is empty."), file->file_name);
217 line_reader_close (reader);
222 /* Estimate the number of lines in the file. */
223 if (file->line_cnt < MAX_PREVIEW_LINES)
224 file->total_lines = file->line_cnt;
228 off_t position = line_reader_tell (reader);
229 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
230 file->total_lines = (double) file->line_cnt / position * s.st_size;
232 file->total_lines = 0;
235 line_reader_close (reader);
241 /* Frees IA's file substructure. */
243 destroy_file (struct import_assistant *ia)
245 struct file *f = &ia->file;
250 for (i = 0; i < f->line_cnt; i++)
251 ds_destroy (&f->lines[i]);
255 g_free (f->file_name);
256 g_free (f->encoding);
259 /* Obtains the file to read from the user. If successful, returns the name of
260 the file and stores the user's chosen encoding for the file into *ENCODINGP.
261 The caller must free each of these strings with g_free().
263 On failure, stores a null pointer and stores NULL in *ENCODINGP.
265 PARENT_WINDOW must be the window to use as the file chooser window's
268 choose_file (GtkWindow *parent_window, gchar **encodingp)
271 GtkFileFilter *filter = NULL;
273 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
275 GTK_FILE_CHOOSER_ACTION_OPEN,
276 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
277 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
280 g_object_set (dialog, "local-only", FALSE, NULL);
282 filter = gtk_file_filter_new ();
283 gtk_file_filter_set_name (filter, _("Text files"));
284 gtk_file_filter_add_mime_type (filter, "text/*");
285 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
287 filter = gtk_file_filter_new ();
288 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
289 gtk_file_filter_add_pattern (filter, "*.txt");
290 gtk_file_filter_add_pattern (filter, "*.TXT");
291 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
293 filter = gtk_file_filter_new ();
294 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
295 gtk_file_filter_add_mime_type (filter, "text/plain");
296 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
298 filter = gtk_file_filter_new ();
299 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
300 gtk_file_filter_add_mime_type (filter, "text/csv");
301 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
303 /* I've never encountered one of these, but it's listed here:
304 http://www.iana.org/assignments/media-types/text/tab-separated-values */
305 filter = gtk_file_filter_new ();
306 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
307 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
308 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
310 filter = gtk_file_filter_new ();
311 gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
312 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
313 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
315 filter = gtk_file_filter_new ();
316 gtk_file_filter_set_name (filter, _("OpenOffice.Org Spreadsheet Files"));
317 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
318 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
320 filter = gtk_file_filter_new ();
321 gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
322 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
323 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
324 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
327 gtk_file_chooser_set_extra_widget (
328 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
330 filter = gtk_file_filter_new ();
331 gtk_file_filter_set_name (filter, _("All Files"));
332 gtk_file_filter_add_pattern (filter, "*");
333 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
335 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
337 case GTK_RESPONSE_ACCEPT:
338 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
339 *encodingp = psppire_encoding_selector_get_encoding (
340 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
347 gtk_widget_destroy (dialog);