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/value-labels.h"
33 #include "language/data-io/data-parser.h"
34 #include "language/lexer/lexer.h"
35 #include "libpspp/assertion.h"
36 #include "libpspp/i18n.h"
37 #include "libpspp/line-reader.h"
38 #include "libpspp/message.h"
39 #include "ui/gui/checkbox-treeview.h"
40 #include "ui/gui/dialog-common.h"
41 #include "ui/gui/executor.h"
42 #include "ui/gui/helper.h"
43 #include "ui/gui/builder-wrapper.h"
44 #include "ui/gui/psppire-data-window.h"
45 #include "ui/gui/psppire-dialog.h"
46 #include "ui/gui/psppire-encoding-selector.h"
47 #include "ui/gui/psppire-empty-list-store.h"
48 #include "ui/gui/psppire-var-sheet.h"
49 #include "ui/gui/psppire-var-store.h"
50 #include "ui/gui/psppire-scanf.h"
51 #include "ui/syntax-gen.h"
54 #include "gl/intprops.h"
55 #include "gl/xalloc.h"
58 #define _(msgid) gettext (msgid)
59 #define N_(msgid) msgid
61 struct import_assistant;
63 /* Choosing a file and reading it. */
65 static char *choose_file (GtkWindow *parent_window, gchar **encodingp);
67 /* Obtains the file to import from the user and initializes IA's
68 file substructure. PARENT_WINDOW must be the window to use
69 as the file chooser window's parent.
71 Returns true if successful, false if the file name could not
72 be obtained or the file could not be read. */
74 init_file (struct import_assistant *ia, GtkWindow *parent_window)
76 struct file *file = &ia->file;
77 enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
78 enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
79 struct line_reader *reader;
82 file->file_name = choose_file (parent_window, &file->encoding);
83 if (file->file_name == NULL)
86 reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
89 msg (ME, _("Could not open `%s': %s"),
90 file->file_name, strerror (errno));
94 ds_init_empty (&input);
95 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
96 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
99 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
100 || ds_length (&input) > MAX_LINE_LEN)
102 if (line_reader_eof (reader))
104 else if (line_reader_error (reader))
105 msg (ME, _("Error reading `%s': %s"),
106 file->file_name, strerror (line_reader_error (reader)));
108 msg (ME, _("Failed to read `%s', because it contains a line "
109 "over %d bytes long and therefore appears not to be "
111 file->file_name, MAX_LINE_LEN);
112 line_reader_close (reader);
118 ds_init_cstr (&file->lines[file->line_cnt],
119 recode_string ("UTF-8", line_reader_get_encoding (reader),
120 ds_cstr (&input), ds_length (&input)));
124 if (file->line_cnt == 0)
126 msg (ME, _("`%s' is empty."), file->file_name);
127 line_reader_close (reader);
132 /* Estimate the number of lines in the file. */
133 if (file->line_cnt < MAX_PREVIEW_LINES)
134 file->total_lines = file->line_cnt;
138 off_t position = line_reader_tell (reader);
139 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
140 file->total_lines = (double) file->line_cnt / position * s.st_size;
142 file->total_lines = 0;
145 line_reader_close (reader);
150 /* Frees IA's file substructure. */
152 destroy_file (struct import_assistant *ia)
154 struct file *f = &ia->file;
157 for (i = 0; i < f->line_cnt; i++)
158 ds_destroy (&f->lines[i]);
160 g_free (f->file_name);
161 g_free (f->encoding);
164 /* Obtains the file to read from the user. If successful, returns the name of
165 the file and stores the user's chosen encoding for the file into *ENCODINGP.
166 The caller must free each of these strings with g_free().
168 On failure, stores a null pointer and stores NULL in *ENCODINGP.
170 PARENT_WINDOW must be the window to use as the file chooser window's
173 choose_file (GtkWindow *parent_window, gchar **encodingp)
176 GtkFileFilter *filter = NULL;
178 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
180 GTK_FILE_CHOOSER_ACTION_OPEN,
181 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
182 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
185 g_object_set (dialog, "local-only", FALSE, NULL);
187 filter = gtk_file_filter_new ();
188 gtk_file_filter_set_name (filter, _("Text files"));
189 gtk_file_filter_add_mime_type (filter, "text/*");
190 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
192 filter = gtk_file_filter_new ();
193 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
194 gtk_file_filter_add_pattern (filter, "*.txt");
195 gtk_file_filter_add_pattern (filter, "*.TXT");
196 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
198 filter = gtk_file_filter_new ();
199 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
200 gtk_file_filter_add_mime_type (filter, "text/plain");
201 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
203 filter = gtk_file_filter_new ();
204 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
205 gtk_file_filter_add_mime_type (filter, "text/csv");
206 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
208 /* I've never encountered one of these, but it's listed here:
209 http://www.iana.org/assignments/media-types/text/tab-separated-values */
210 filter = gtk_file_filter_new ();
211 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
212 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
213 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
215 gtk_file_chooser_set_extra_widget (
216 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
218 filter = gtk_file_filter_new ();
219 gtk_file_filter_set_name (filter, _("All Files"));
220 gtk_file_filter_add_pattern (filter, "*");
221 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
223 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
225 case GTK_RESPONSE_ACCEPT:
226 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
227 *encodingp = psppire_encoding_selector_get_encoding (
228 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
235 gtk_widget_destroy (dialog);