Fixed many warnings
[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-contrib/psppire-sheet.h>
24 #include <gtk/gtk.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <sys/stat.h>
28
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"
56
57 #include "gl/error.h"
58 #include "gl/intprops.h"
59 #include "gl/xalloc.h"
60
61 #include "gettext.h"
62 #define _(msgid) gettext (msgid)
63 #define N_(msgid) msgid
64
65 struct import_assistant;
66
67 /* Choose a file */
68 static char *choose_file (GtkWindow *parent_window, gchar **encodingp);
69
70
71
72
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.
76
77    Returns true if successful, false if the file name could not
78    be obtained or the file could not be read. */
79 bool
80 init_file (struct import_assistant *ia, GtkWindow *parent_window)
81 {
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;
86
87   file->lines = NULL;
88   file->file_name = choose_file (parent_window, &file->encoding);
89   if (file->file_name == NULL)
90     return false;
91
92   opts.sheet_name = NULL;
93   opts.cell_range = NULL;
94   opts.sheet_index = 1;
95
96   sri.read_names = true;
97   sri.asw = -1;
98
99   if (ia->spreadsheet == NULL)
100     ia->spreadsheet = gnumeric_probe (file->file_name);
101
102   if (ia->spreadsheet == NULL)
103     ia->spreadsheet = ods_probe (file->file_name);
104
105   printf ("%s:%d %p\n", __FILE__, __LINE__, ia->spreadsheet);
106   
107   if (ia->spreadsheet == NULL)
108     {
109     struct string input;
110     struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
111     if (reader == NULL)
112       {
113         msg (ME, _("Could not open `%s': %s"),
114              file->file_name, strerror (errno));
115         return false;
116       }
117
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++)
121       {
122         ds_clear (&input);
123         if (!line_reader_read (reader, &input, MAX_LINE_LEN + 1)
124             || ds_length (&input) > MAX_LINE_LEN)
125           {
126             if (line_reader_eof (reader))
127               break;
128             else if (line_reader_error (reader))
129               msg (ME, _("Error reading `%s': %s"),
130                    file->file_name, strerror (line_reader_error (reader)));
131             else
132               msg (ME, _("Failed to read `%s', because it contains a line "
133                          "over %d bytes long and therefore appears not to be "
134                          "a text file."),
135                    file->file_name, MAX_LINE_LEN);
136             line_reader_close (reader);
137             destroy_file (ia);
138             ds_destroy (&input);
139             return false;
140           }
141
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)));
145       }
146     ds_destroy (&input);
147
148     if (file->line_cnt == 0)
149       {
150         msg (ME, _("`%s' is empty."), file->file_name);
151         line_reader_close (reader);
152         destroy_file (ia);
153         return false;
154       }
155
156     /* Estimate the number of lines in the file. */
157     if (file->line_cnt < MAX_PREVIEW_LINES)
158       file->total_lines = file->line_cnt;
159     else
160       {
161         struct stat s;
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;
165         else
166           file->total_lines = 0;
167       }
168
169     line_reader_close (reader);
170   }
171
172   return true;
173 }
174
175 /* Frees IA's file substructure. */
176 void
177 destroy_file (struct import_assistant *ia)
178 {
179   struct file *f = &ia->file;
180   size_t i;
181
182   if (f->lines)
183     {
184       for (i = 0; i < f->line_cnt; i++)
185         ds_destroy (&f->lines[i]);
186       free (f->lines);
187     }
188
189   g_free (f->file_name);
190   g_free (f->encoding);
191 }
192
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().
196
197    On failure, stores a null pointer and stores NULL in *ENCODINGP.
198
199    PARENT_WINDOW must be the window to use as the file chooser window's
200    parent. */
201 static char *
202 choose_file (GtkWindow *parent_window, gchar **encodingp)
203 {
204   char *file_name;
205   GtkFileFilter *filter = NULL;
206
207   GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
208                                         parent_window,
209                                         GTK_FILE_CHOOSER_ACTION_OPEN,
210                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
211                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
212                                         NULL);
213
214   g_object_set (dialog, "local-only", FALSE, NULL);
215
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);
220
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);
226
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);
231
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);
236
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);
243
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);
248
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);
253
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);
259
260
261   gtk_file_chooser_set_extra_widget (
262     GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
263
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);
268
269   switch (gtk_dialog_run (GTK_DIALOG (dialog)))
270     {
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)));
275       break;
276     default:
277       file_name = NULL;
278       *encodingp = NULL;
279       break;
280     }
281   gtk_widget_destroy (dialog);
282
283   return file_name;
284 }