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/gnumeric-reader.h"
33 #include "data/spreadsheet-reader.h"
34 #include "data/value-labels.h"
35 #include "language/data-io/data-parser.h"
36 #include "language/lexer/lexer.h"
37 #include "libpspp/assertion.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/line-reader.h"
40 #include "libpspp/message.h"
41 #include "ui/gui/checkbox-treeview.h"
42 #include "ui/gui/dialog-common.h"
43 #include "ui/gui/executor.h"
44 #include "ui/gui/helper.h"
45 #include "ui/gui/builder-wrapper.h"
46 #include "ui/gui/psppire-data-window.h"
47 #include "ui/gui/psppire-dialog.h"
48 #include "ui/gui/psppire-encoding-selector.h"
49 #include "ui/gui/psppire-empty-list-store.h"
50 #include "ui/gui/psppire-var-sheet.h"
51 #include "ui/gui/psppire-var-store.h"
52 #include "ui/gui/psppire-scanf.h"
53 #include "ui/syntax-gen.h"
56 #include "gl/intprops.h"
57 #include "gl/xalloc.h"
60 #define _(msgid) gettext (msgid)
61 #define N_(msgid) msgid
63 struct import_assistant;
65 /* Choosing a file and reading it. */
67 static char *choose_file (GtkWindow *parent_window, gchar **encodingp);
69 /* Obtains the file to import from the user and initializes IA's
70 file substructure. PARENT_WINDOW must be the window to use
71 as the file chooser window's parent.
73 Returns true if successful, false if the file name could not
74 be obtained or the file could not be read. */
76 init_file (struct import_assistant *ia, GtkWindow *parent_window)
78 struct file *file = &ia->file;
79 file->file_name = choose_file (parent_window, &file->encoding);
80 if (file->file_name == NULL)
83 struct dictionary *dict = NULL;
84 struct spreadsheet_read_info sri;
86 sri.sheet_name = NULL;
87 sri.file_name = file->file_name;
88 sri.cell_range = NULL;
90 sri.read_names = true;
93 struct casereader *creader = gnumeric_open_reader (&sri, &dict);
94 printf ("%s:%d %s\n", __FILE__, __LINE__, sri.file_name);
95 ia->file.type = FTYPE_SPREADSHEET;
99 enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
100 enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
103 struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
106 msg (ME, _("Could not open `%s': %s"),
107 file->file_name, strerror (errno));
111 ds_init_empty (&input);
112 file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
113 for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
116 if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
117 || ds_length (&input) > MAX_LINE_LEN)
119 if (line_reader_eof (reader))
121 else if (line_reader_error (reader))
122 msg (ME, _("Error reading `%s': %s"),
123 file->file_name, strerror (line_reader_error (reader)));
125 msg (ME, _("Failed to read `%s', because it contains a line "
126 "over %d bytes long and therefore appears not to be "
128 file->file_name, MAX_LINE_LEN);
129 line_reader_close (reader);
135 ds_init_cstr (&file->lines[file->line_cnt],
136 recode_string ("UTF-8", line_reader_get_encoding (reader),
137 ds_cstr (&input), ds_length (&input)));
141 if (file->line_cnt == 0)
143 msg (ME, _("`%s' is empty."), file->file_name);
144 line_reader_close (reader);
149 /* Estimate the number of lines in the file. */
150 if (file->line_cnt < MAX_PREVIEW_LINES)
151 file->total_lines = file->line_cnt;
155 off_t position = line_reader_tell (reader);
156 if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
157 file->total_lines = (double) file->line_cnt / position * s.st_size;
159 file->total_lines = 0;
162 line_reader_close (reader);
163 ia->file.type = FTYPE_TEXT;
169 /* Frees IA's file substructure. */
171 destroy_file (struct import_assistant *ia)
173 struct file *f = &ia->file;
176 for (i = 0; i < f->line_cnt; i++)
177 ds_destroy (&f->lines[i]);
179 g_free (f->file_name);
180 g_free (f->encoding);
183 /* Obtains the file to read from the user. If successful, returns the name of
184 the file and stores the user's chosen encoding for the file into *ENCODINGP.
185 The caller must free each of these strings with g_free().
187 On failure, stores a null pointer and stores NULL in *ENCODINGP.
189 PARENT_WINDOW must be the window to use as the file chooser window's
192 choose_file (GtkWindow *parent_window, gchar **encodingp)
195 GtkFileFilter *filter = NULL;
197 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
199 GTK_FILE_CHOOSER_ACTION_OPEN,
200 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
201 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
204 g_object_set (dialog, "local-only", FALSE, NULL);
206 filter = gtk_file_filter_new ();
207 gtk_file_filter_set_name (filter, _("Text files"));
208 gtk_file_filter_add_mime_type (filter, "text/*");
209 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
211 filter = gtk_file_filter_new ();
212 gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
213 gtk_file_filter_add_pattern (filter, "*.txt");
214 gtk_file_filter_add_pattern (filter, "*.TXT");
215 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
217 filter = gtk_file_filter_new ();
218 gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
219 gtk_file_filter_add_mime_type (filter, "text/plain");
220 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
222 filter = gtk_file_filter_new ();
223 gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
224 gtk_file_filter_add_mime_type (filter, "text/csv");
225 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
227 /* I've never encountered one of these, but it's listed here:
228 http://www.iana.org/assignments/media-types/text/tab-separated-values */
229 filter = gtk_file_filter_new ();
230 gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
231 gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
232 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
234 filter = gtk_file_filter_new ();
235 gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
236 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
237 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
239 filter = gtk_file_filter_new ();
240 gtk_file_filter_set_name (filter, _("OpenOffice.Org Spreadsheet Files"));
241 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
242 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
244 filter = gtk_file_filter_new ();
245 gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
246 gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
247 gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
248 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
251 gtk_file_chooser_set_extra_widget (
252 GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
254 filter = gtk_file_filter_new ();
255 gtk_file_filter_set_name (filter, _("All Files"));
256 gtk_file_filter_add_pattern (filter, "*");
257 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
259 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
261 case GTK_RESPONSE_ACCEPT:
262 file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
263 *encodingp = psppire_encoding_selector_get_encoding (
264 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
271 gtk_widget_destroy (dialog);