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_info sri;
85 struct spreadsheet_read_options opts;
88 file->file_name = choose_file (parent_window, &file->encoding);
89 if (file->file_name == NULL)
92 opts.sheet_name = NULL;
93 opts.cell_range = NULL;
96 sri.read_names = true;
99 if (ia->spreadsheet == NULL)
100 ia->spreadsheet = gnumeric_probe (file->file_name);
102 if (ia->spreadsheet == NULL)
103 ia->spreadsheet = ods_probe (file->file_name);
105 printf ("%s:%d %p\n", __FILE__, __LINE__, ia->spreadsheet);
107 if (ia->spreadsheet == NULL)
110 struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
113 msg (ME, _("Could not open `%s': %s"),
114 file->file_name, strerror (errno));
118 ds_init_empty (&input);
119 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
120 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
123 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
124 || ds_length (&input) > MAX_LINE_LEN)
126 if (line_reader_eof (reader))
128 else if (line_reader_error (reader))
129 msg (ME, _("Error reading `%s': %s"),
130 file->file_name, strerror (line_reader_error (reader)));
132 msg (ME, _("Failed to read `%s', because it contains a line "
133 "over %d bytes long and therefore appears not to be "
135 file->file_name, MAX_LINE_LEN);
136 line_reader_close (reader);
142 ds_init_cstr (&file->lines[file->line_cnt],
143 recode_string ("UTF-8", line_reader_get_encoding (reader),
144 ds_cstr (&input), ds_length (&input)));
148 if (file->line_cnt == 0)
150 msg (ME, _("`%s' is empty."), file->file_name);
151 line_reader_close (reader);
156 /* Estimate the number of lines in the file. */
157 if (file->line_cnt < MAX_PREVIEW_LINES)
158 file->total_lines = file->line_cnt;
162 off_t position = line_reader_tell (reader);
163 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
164 file->total_lines = (double) file->line_cnt / position * s.st_size;
166 file->total_lines = 0;
169 line_reader_close (reader);
175 /* Frees IA's file substructure. */
177 destroy_file (struct import_assistant *ia)
179 struct file *f = &ia->file;
184 for (i = 0; i < f->line_cnt; i++)
185 ds_destroy (&f->lines[i]);
189 g_free (f->file_name);
190 g_free (f->encoding);
193 /* Obtains the file to read from the user. If successful, returns the name of
194 the file and stores the user's chosen encoding for the file into *ENCODINGP.
195 The caller must free each of these strings with g_free().
197 On failure, stores a null pointer and stores NULL in *ENCODINGP.
199 PARENT_WINDOW must be the window to use as the file chooser window's
202 choose_file (GtkWindow *parent_window, gchar **encodingp)
205 GtkFileFilter *filter = NULL;
207 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
209 GTK_FILE_CHOOSER_ACTION_OPEN,
210 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
211 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
214 g_object_set (dialog, "local-only", FALSE, NULL);
216 filter = gtk_file_filter_new ();
217 gtk_file_filter_set_name (filter, _("Text files"));
218 gtk_file_filter_add_mime_type (filter, "text/*");
219 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
221 filter = gtk_file_filter_new ();
222 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
223 gtk_file_filter_add_pattern (filter, "*.txt");
224 gtk_file_filter_add_pattern (filter, "*.TXT");
225 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
227 filter = gtk_file_filter_new ();
228 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
229 gtk_file_filter_add_mime_type (filter, "text/plain");
230 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
232 filter = gtk_file_filter_new ();
233 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
234 gtk_file_filter_add_mime_type (filter, "text/csv");
235 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
237 /* I've never encountered one of these, but it's listed here:
238 http://www.iana.org/assignments/media-types/text/tab-separated-values */
239 filter = gtk_file_filter_new ();
240 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
241 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
242 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
244 filter = gtk_file_filter_new ();
245 gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
246 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
247 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
249 filter = gtk_file_filter_new ();
250 gtk_file_filter_set_name (filter, _("OpenOffice.Org Spreadsheet Files"));
251 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
252 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
254 filter = gtk_file_filter_new ();
255 gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
256 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
257 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
258 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
261 gtk_file_chooser_set_extra_widget (
262 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
264 filter = gtk_file_filter_new ();
265 gtk_file_filter_set_name (filter, _("All Files"));
266 gtk_file_filter_add_pattern (filter, "*");
267 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
269 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
271 case GTK_RESPONSE_ACCEPT:
272 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
273 *encodingp = psppire_encoding_selector_get_encoding (
274 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
281 gtk_widget_destroy (dialog);