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;
86 file->file_name = choose_file (parent_window, &file->encoding);
87 if (file->file_name == NULL)
90 if (ia->spreadsheet == NULL)
91 ia->spreadsheet = gnumeric_probe (file->file_name, false);
93 if (ia->spreadsheet == NULL)
94 ia->spreadsheet = ods_probe (file->file_name, false);
96 if (ia->spreadsheet == NULL)
99 struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
102 msg (ME, _("Could not open `%s': %s"),
103 file->file_name, strerror (errno));
107 ds_init_empty (&input);
108 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
109 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
112 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
113 || ds_length (&input) > MAX_LINE_LEN)
115 if (line_reader_eof (reader))
117 else if (line_reader_error (reader))
118 msg (ME, _("Error reading `%s': %s"),
119 file->file_name, strerror (line_reader_error (reader)));
121 msg (ME, _("Failed to read `%s', because it contains a line "
122 "over %d bytes long and therefore appears not to be "
124 file->file_name, MAX_LINE_LEN);
125 line_reader_close (reader);
131 ds_init_cstr (&file->lines[file->line_cnt],
132 recode_string ("UTF-8", line_reader_get_encoding (reader),
133 ds_cstr (&input), ds_length (&input)));
137 if (file->line_cnt == 0)
139 msg (ME, _("`%s' is empty."), file->file_name);
140 line_reader_close (reader);
145 /* Estimate the number of lines in the file. */
146 if (file->line_cnt < MAX_PREVIEW_LINES)
147 file->total_lines = file->line_cnt;
151 off_t position = line_reader_tell (reader);
152 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
153 file->total_lines = (double) file->line_cnt / position * s.st_size;
155 file->total_lines = 0;
158 line_reader_close (reader);
164 /* Frees IA's file substructure. */
166 destroy_file (struct import_assistant *ia)
168 struct file *f = &ia->file;
173 for (i = 0; i < f->line_cnt; i++)
174 ds_destroy (&f->lines[i]);
178 g_free (f->file_name);
179 g_free (f->encoding);
182 /* Obtains the file to read from the user. If successful, returns the name of
183 the file and stores the user's chosen encoding for the file into *ENCODINGP.
184 The caller must free each of these strings with g_free().
186 On failure, stores a null pointer and stores NULL in *ENCODINGP.
188 PARENT_WINDOW must be the window to use as the file chooser window's
191 choose_file (GtkWindow *parent_window, gchar **encodingp)
194 GtkFileFilter *filter = NULL;
196 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
198 GTK_FILE_CHOOSER_ACTION_OPEN,
199 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
200 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
203 g_object_set (dialog, "local-only", FALSE, NULL);
205 filter = gtk_file_filter_new ();
206 gtk_file_filter_set_name (filter, _("Text Files"));
207 gtk_file_filter_add_mime_type (filter, "text/*");
208 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
210 filter = gtk_file_filter_new ();
211 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
212 gtk_file_filter_add_pattern (filter, "*.txt");
213 gtk_file_filter_add_pattern (filter, "*.TXT");
214 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
216 filter = gtk_file_filter_new ();
217 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
218 gtk_file_filter_add_mime_type (filter, "text/plain");
219 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
221 filter = gtk_file_filter_new ();
222 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
223 gtk_file_filter_add_mime_type (filter, "text/csv");
224 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
226 /* I've never encountered one of these, but it's listed here:
227 http://www.iana.org/assignments/media-types/text/tab-separated-values */
228 filter = gtk_file_filter_new ();
229 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
230 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
231 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
234 gtk_file_chooser_set_extra_widget (
235 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
237 filter = gtk_file_filter_new ();
238 gtk_file_filter_set_name (filter, _("All Files"));
239 gtk_file_filter_add_pattern (filter, "*");
240 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
242 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
244 case GTK_RESPONSE_ACCEPT:
245 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
246 *encodingp = psppire_encoding_selector_get_encoding (
247 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
254 gtk_widget_destroy (dialog);