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);
73 /* Obtains the file to import from the user and initializes IA's
74 file substructure. PARENT_WINDOW must be the window to use
75 as the file chooser window's parent.
77 Returns true if successful, false if the file name could not
78 be obtained or the file could not be read. */
80 init_file (struct import_assistant *ia, GtkWindow *parent_window)
82 enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
83 struct file *file = &ia->file;
84 struct spreadsheet_read_options opts;
87 file->file_name = choose_file (parent_window, &file->encoding);
88 if (file->file_name == NULL)
91 opts.sheet_name = NULL;
92 opts.cell_range = NULL;
95 opts.read_names = true;
98 printf ("%s:%d %p\n", __FILE__, __LINE__, ia->spreadsheet);
100 if (ia->spreadsheet == NULL)
101 ia->spreadsheet = gnumeric_probe (file->file_name, false);
103 printf ("%s:%d %p\n", __FILE__, __LINE__, ia->spreadsheet);
105 if (ia->spreadsheet == NULL)
106 ia->spreadsheet = ods_probe (file->file_name, false);
108 printf ("%s:%d %p\n", __FILE__, __LINE__, ia->spreadsheet);
110 if (ia->spreadsheet == NULL)
113 struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
116 msg (ME, _("Could not open `%s': %s"),
117 file->file_name, strerror (errno));
121 ds_init_empty (&input);
122 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
123 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
126 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
127 || ds_length (&input) > MAX_LINE_LEN)
129 if (line_reader_eof (reader))
131 else if (line_reader_error (reader))
132 msg (ME, _("Error reading `%s': %s"),
133 file->file_name, strerror (line_reader_error (reader)));
135 msg (ME, _("Failed to read `%s', because it contains a line "
136 "over %d bytes long and therefore appears not to be "
138 file->file_name, MAX_LINE_LEN);
139 line_reader_close (reader);
145 ds_init_cstr (&file->lines[file->line_cnt],
146 recode_string ("UTF-8", line_reader_get_encoding (reader),
147 ds_cstr (&input), ds_length (&input)));
151 if (file->line_cnt == 0)
153 msg (ME, _("`%s' is empty."), file->file_name);
154 line_reader_close (reader);
159 /* Estimate the number of lines in the file. */
160 if (file->line_cnt < MAX_PREVIEW_LINES)
161 file->total_lines = file->line_cnt;
165 off_t position = line_reader_tell (reader);
166 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
167 file->total_lines = (double) file->line_cnt / position * s.st_size;
169 file->total_lines = 0;
172 line_reader_close (reader);
178 /* Frees IA's file substructure. */
180 destroy_file (struct import_assistant *ia)
182 struct file *f = &ia->file;
187 for (i = 0; i < f->line_cnt; i++)
188 ds_destroy (&f->lines[i]);
192 g_free (f->file_name);
193 g_free (f->encoding);
196 /* Obtains the file to read from the user. If successful, returns the name of
197 the file and stores the user's chosen encoding for the file into *ENCODINGP.
198 The caller must free each of these strings with g_free().
200 On failure, stores a null pointer and stores NULL in *ENCODINGP.
202 PARENT_WINDOW must be the window to use as the file chooser window's
205 choose_file (GtkWindow *parent_window, gchar **encodingp)
208 GtkFileFilter *filter = NULL;
210 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
212 GTK_FILE_CHOOSER_ACTION_OPEN,
213 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
214 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
217 g_object_set (dialog, "local-only", FALSE, NULL);
219 filter = gtk_file_filter_new ();
220 gtk_file_filter_set_name (filter, _("Text files"));
221 gtk_file_filter_add_mime_type (filter, "text/*");
222 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
224 filter = gtk_file_filter_new ();
225 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
226 gtk_file_filter_add_pattern (filter, "*.txt");
227 gtk_file_filter_add_pattern (filter, "*.TXT");
228 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
230 filter = gtk_file_filter_new ();
231 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
232 gtk_file_filter_add_mime_type (filter, "text/plain");
233 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
235 filter = gtk_file_filter_new ();
236 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
237 gtk_file_filter_add_mime_type (filter, "text/csv");
238 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
240 /* I've never encountered one of these, but it's listed here:
241 http://www.iana.org/assignments/media-types/text/tab-separated-values */
242 filter = gtk_file_filter_new ();
243 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
244 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
245 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
247 filter = gtk_file_filter_new ();
248 gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
249 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
250 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
252 filter = gtk_file_filter_new ();
253 gtk_file_filter_set_name (filter, _("OpenDocument Spreadsheet Files"));
254 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
255 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
257 filter = gtk_file_filter_new ();
258 gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
259 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
260 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
261 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
264 gtk_file_chooser_set_extra_widget (
265 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
267 filter = gtk_file_filter_new ();
268 gtk_file_filter_set_name (filter, _("All Files"));
269 gtk_file_filter_add_pattern (filter, "*");
270 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
272 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
274 case GTK_RESPONSE_ACCEPT:
275 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
276 *encodingp = psppire_encoding_selector_get_encoding (
277 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
284 gtk_widget_destroy (dialog);