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 sheet_spec_page *ssp = ia->sheet_spec;
85 struct spreadsheet_read_info sri;
86 struct spreadsheet_read_options opts;
89 file->file_name = choose_file (parent_window, &file->encoding);
90 if (file->file_name == NULL)
93 opts.sheet_name = NULL;
94 opts.cell_range = NULL;
97 sri.read_names = true;
100 if (ia->spreadsheet == NULL)
101 ia->spreadsheet = gnumeric_probe (file->file_name);
103 printf ("%s:%d %p\n", __FILE__, __LINE__, ia->spreadsheet);
105 if (ia->spreadsheet == NULL)
106 ia->spreadsheet = ods_probe (file->file_name);
108 if (! ia->spreadsheet)
111 struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
114 msg (ME, _("Could not open `%s': %s"),
115 file->file_name, strerror (errno));
119 ds_init_empty (&input);
120 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
121 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
124 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
125 || ds_length (&input) > MAX_LINE_LEN)
127 if (line_reader_eof (reader))
129 else if (line_reader_error (reader))
130 msg (ME, _("Error reading `%s': %s"),
131 file->file_name, strerror (line_reader_error (reader)));
133 msg (ME, _("Failed to read `%s', because it contains a line "
134 "over %d bytes long and therefore appears not to be "
136 file->file_name, MAX_LINE_LEN);
137 line_reader_close (reader);
143 ds_init_cstr (&file->lines[file->line_cnt],
144 recode_string ("UTF-8", line_reader_get_encoding (reader),
145 ds_cstr (&input), ds_length (&input)));
149 if (file->line_cnt == 0)
151 msg (ME, _("`%s' is empty."), file->file_name);
152 line_reader_close (reader);
157 /* Estimate the number of lines in the file. */
158 if (file->line_cnt < MAX_PREVIEW_LINES)
159 file->total_lines = file->line_cnt;
163 off_t position = line_reader_tell (reader);
164 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
165 file->total_lines = (double) file->line_cnt / position * s.st_size;
167 file->total_lines = 0;
170 line_reader_close (reader);
176 /* Frees IA's file substructure. */
178 destroy_file (struct import_assistant *ia)
180 struct file *f = &ia->file;
185 for (i = 0; i < f->line_cnt; i++)
186 ds_destroy (&f->lines[i]);
190 g_free (f->file_name);
191 g_free (f->encoding);
194 /* Obtains the file to read from the user. If successful, returns the name of
195 the file and stores the user's chosen encoding for the file into *ENCODINGP.
196 The caller must free each of these strings with g_free().
198 On failure, stores a null pointer and stores NULL in *ENCODINGP.
200 PARENT_WINDOW must be the window to use as the file chooser window's
203 choose_file (GtkWindow *parent_window, gchar **encodingp)
206 GtkFileFilter *filter = NULL;
208 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
210 GTK_FILE_CHOOSER_ACTION_OPEN,
211 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
212 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
215 g_object_set (dialog, "local-only", FALSE, NULL);
217 filter = gtk_file_filter_new ();
218 gtk_file_filter_set_name (filter, _("Text files"));
219 gtk_file_filter_add_mime_type (filter, "text/*");
220 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
222 filter = gtk_file_filter_new ();
223 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
224 gtk_file_filter_add_pattern (filter, "*.txt");
225 gtk_file_filter_add_pattern (filter, "*.TXT");
226 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
228 filter = gtk_file_filter_new ();
229 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
230 gtk_file_filter_add_mime_type (filter, "text/plain");
231 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
233 filter = gtk_file_filter_new ();
234 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
235 gtk_file_filter_add_mime_type (filter, "text/csv");
236 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
238 /* I've never encountered one of these, but it's listed here:
239 http://www.iana.org/assignments/media-types/text/tab-separated-values */
240 filter = gtk_file_filter_new ();
241 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
242 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
243 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
245 filter = gtk_file_filter_new ();
246 gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
247 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
248 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
250 filter = gtk_file_filter_new ();
251 gtk_file_filter_set_name (filter, _("OpenOffice.Org Spreadsheet Files"));
252 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
253 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
255 filter = gtk_file_filter_new ();
256 gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
257 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
258 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
259 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
262 gtk_file_chooser_set_extra_widget (
263 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
265 filter = gtk_file_filter_new ();
266 gtk_file_filter_set_name (filter, _("All Files"));
267 gtk_file_filter_add_pattern (filter, "*");
268 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
270 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
272 case GTK_RESPONSE_ACCEPT:
273 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
274 *encodingp = psppire_encoding_selector_get_encoding (
275 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
282 gtk_widget_destroy (dialog);