Whitespace changes only
[pspp] / src / ui / gui / page-file.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013  Free Software Foundation
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "ui/gui/text-data-import-dialog.h"
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <gtk/gtk.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27
28 #include "data/data-in.h"
29 #include "data/data-out.h"
30 #include "data/format-guesser.h"
31 #include "data/casereader.h"
32 #include "data/gnumeric-reader.h"
33 #include "data/ods-reader.h"
34 #include "data/spreadsheet-reader.h"
35 #include "data/value-labels.h"
36 #include "language/data-io/data-parser.h"
37 #include "language/lexer/lexer.h"
38 #include "libpspp/assertion.h"
39 #include "libpspp/i18n.h"
40 #include "libpspp/line-reader.h"
41 #include "libpspp/message.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-scanf.h"
52 #include "ui/syntax-gen.h"
53
54 #include "gl/intprops.h"
55 #include "gl/xalloc.h"
56
57 #include "gettext.h"
58 #define _(msgid) gettext (msgid)
59 #define N_(msgid) msgid
60
61 struct import_assistant;
62
63 /* Choose a file */
64 static char *choose_file (GtkWindow *parent_window, gchar **encodingp);
65
66
67
68
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.
72
73    Returns true if successful, false if the file name could not
74    be obtained or the file could not be read. */
75 bool
76 init_file (struct import_assistant *ia, GtkWindow *parent_window)
77 {
78   enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
79   struct file *file = &ia->file;
80
81   file->lines = NULL;
82   file->file_name = choose_file (parent_window, &file->encoding);
83   if (file->file_name == NULL)
84     return false;
85
86   if (ia->spreadsheet == NULL)
87     ia->spreadsheet = gnumeric_probe (file->file_name, false);
88
89   if (ia->spreadsheet == NULL)
90     ia->spreadsheet = ods_probe (file->file_name, false);
91
92   if (ia->spreadsheet == NULL)
93     {
94     struct string input;
95     struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
96     if (reader == NULL)
97       {
98         msg_error (errno, _("Could not open `%s'"),
99              file->file_name);
100         return false;
101       }
102
103     ds_init_empty (&input);
104     file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
105     for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
106       {
107         ds_clear (&input);
108         if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
109             || ds_length (&input) > MAX_LINE_LEN)
110           {
111             if (line_reader_eof (reader))
112               break;
113             else if (line_reader_error (reader))
114               msg (ME, _("Error reading `%s': %s"),
115                    file->file_name, strerror (line_reader_error (reader)));
116             else
117               msg (ME, _("Failed to read `%s', because it contains a line "
118                          "over %d bytes long and therefore appears not to be "
119                          "a text file."),
120                    file->file_name, MAX_LINE_LEN);
121             line_reader_close (reader);
122             destroy_file (ia);
123             ds_destroy (&input);
124             return false;
125           }
126
127         ds_init_cstr (&file->lines[file->line_cnt],
128                       recode_string ("UTF-8", line_reader_get_encoding (reader),
129                                      ds_cstr (&input), ds_length (&input)));
130       }
131     ds_destroy (&input);
132
133     if (file->line_cnt == 0)
134       {
135         msg (ME, _("`%s' is empty."), file->file_name);
136         line_reader_close (reader);
137         destroy_file (ia);
138         return false;
139       }
140
141
142     /* Estimate the number of lines in the file. */
143     if (file->line_cnt < MAX_PREVIEW_LINES)
144       {
145         file->total_lines = file->line_cnt;
146         file->total_is_exact = true;
147       }
148     else
149       {
150         struct stat s;
151         off_t position = line_reader_tell (reader);
152         if (fstat (line_reader_fileno (reader), &s) == 0 && position > 0)
153           {
154             file->total_lines = (double) file->line_cnt / position * s.st_size;
155             file->total_is_exact = false;
156           }
157         else
158           {
159           file->total_lines = 0;
160           file->total_is_exact = true;
161           }
162       }
163
164     line_reader_close (reader);
165   }
166
167   return true;
168 }
169
170 /* Frees IA's file substructure. */
171 void
172 destroy_file (struct import_assistant *ia)
173 {
174   struct file *f = &ia->file;
175   size_t i;
176
177   if (f->lines)
178     {
179       for (i = 0; i < f->line_cnt; i++)
180         ds_destroy (&f->lines[i]);
181       free (f->lines);
182     }
183
184   g_free (f->file_name);
185   g_free (f->encoding);
186 }
187
188 /* Obtains the file to read from the user.  If successful, returns the name of
189    the file and stores the user's chosen encoding for the file into *ENCODINGP.
190    The caller must free each of these strings with g_free().
191
192    On failure, stores a null pointer and stores NULL in *ENCODINGP.
193
194    PARENT_WINDOW must be the window to use as the file chooser window's
195    parent. */
196 static char *
197 choose_file (GtkWindow *parent_window, gchar **encodingp)
198 {
199   char *file_name;
200   GtkFileFilter *filter = NULL;
201
202   GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
203                                         parent_window,
204                                         GTK_FILE_CHOOSER_ACTION_OPEN,
205                                         _("Cancel"), GTK_RESPONSE_CANCEL,
206                                         _("Open"), GTK_RESPONSE_ACCEPT,
207                                         NULL);
208
209   g_object_set (dialog, "local-only", FALSE, NULL);
210
211   filter = gtk_file_filter_new ();
212   gtk_file_filter_set_name (filter, _("Text Files"));
213   gtk_file_filter_add_mime_type (filter, "text/*");
214   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
215
216   filter = gtk_file_filter_new ();
217   gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
218   gtk_file_filter_add_pattern (filter, "*.txt");
219   gtk_file_filter_add_pattern (filter, "*.TXT");
220   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
221
222   filter = gtk_file_filter_new ();
223   gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
224   gtk_file_filter_add_mime_type (filter, "text/plain");
225   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
226
227   filter = gtk_file_filter_new ();
228   gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
229   gtk_file_filter_add_mime_type (filter, "text/csv");
230   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
231
232   /* I've never encountered one of these, but it's listed here:
233      http://www.iana.org/assignments/media-types/text/tab-separated-values  */
234   filter = gtk_file_filter_new ();
235   gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
236   gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
237   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
238
239   filter = gtk_file_filter_new ();
240   gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
241   gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
242   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
243
244   filter = gtk_file_filter_new ();
245   gtk_file_filter_set_name (filter, _("OpenDocument Spreadsheet Files"));
246   gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
247   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
248
249   filter = gtk_file_filter_new ();
250   gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
251   gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
252   gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
253   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
254
255   gtk_file_chooser_set_extra_widget (
256     GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
257
258   filter = gtk_file_filter_new ();
259   gtk_file_filter_set_name (filter, _("All Files"));
260   gtk_file_filter_add_pattern (filter, "*");
261   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
262
263   switch (gtk_dialog_run (GTK_DIALOG (dialog)))
264     {
265     case GTK_RESPONSE_ACCEPT:
266       file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
267       *encodingp = psppire_encoding_selector_get_encoding (
268         gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
269       break;
270     default:
271       file_name = NULL;
272       *encodingp = NULL;
273       break;
274     }
275   gtk_widget_destroy (dialog);
276
277   return file_name;
278 }