7c9603d69d4f37c20fff0e518282676a622d6047
[pspp] / src / ui / gui / text-data-import-dialog.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 2009, 2010, 2011, 2012  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 <gtk-contrib/psppire-sheet.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/value-labels.h"
32 #include "language/data-io/data-parser.h"
33 #include "language/lexer/lexer.h"
34 #include "libpspp/assertion.h"
35 #include "libpspp/i18n.h"
36 #include "libpspp/message.h"
37 #include "ui/gui/checkbox-treeview.h"
38 #include "ui/gui/dialog-common.h"
39 #include "ui/gui/executor.h"
40 #include "ui/gui/helper.h"
41 #include "ui/gui/builder-wrapper.h"
42 #include "ui/gui/psppire-data-window.h"
43 #include "ui/gui/psppire-dialog.h"
44 #include "ui/gui/psppire-var-sheet.h"
45 #include "ui/gui/psppire-var-store.h"
46 #include "ui/gui/psppire-scanf.h"
47 #include "ui/syntax-gen.h"
48
49 #include "gl/error.h"
50 #include "gl/xalloc.h"
51
52 #include "gettext.h"
53 #define _(msgid) gettext (msgid)
54 #define N_(msgid) msgid
55
56
57 /* TextImportModel, a GtkTreeModel used by the text data import
58    dialog. */
59 enum
60   {
61     TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER, /* 1-based line number in file */
62     TEXT_IMPORT_MODEL_COLUMN_LINE,        /* The line from the file. */
63   };
64 typedef struct TextImportModel TextImportModel;
65 typedef struct TextImportModelClass TextImportModelClass;
66
67 TextImportModel *text_import_model_new (struct string *lines, size_t line_cnt,
68                                         size_t first_line);
69 gint text_import_model_iter_to_row (const GtkTreeIter *);
70
71 struct import_assistant;
72
73 /* The file to be imported. */
74 struct file
75   {
76     char *file_name;        /* File name. */
77     unsigned long int total_lines; /* Number of lines in file. */
78     bool total_is_exact;    /* Is total_lines exact (or an estimate)? */
79
80     /* The first several lines of the file. */
81     struct string *lines;
82     size_t line_cnt;
83   };
84 static bool init_file (struct import_assistant *, GtkWindow *parent);
85 static void destroy_file (struct import_assistant *);
86
87 /* The main body of the GTK+ assistant and related data. */
88 struct assistant
89   {
90     GtkBuilder *builder;
91     GtkAssistant *assistant;
92     GMainLoop *main_loop;
93     GtkWidget *paste_button;
94     GtkWidget *reset_button;
95     int response;
96     int watch_cursor;
97
98     GtkCellRenderer *prop_renderer;
99     GtkCellRenderer *fixed_renderer;
100   };
101 static void init_assistant (struct import_assistant *, GtkWindow *);
102 static void destroy_assistant (struct import_assistant *);
103 static GtkWidget *add_page_to_assistant (struct import_assistant *,
104                                          GtkWidget *page,
105                                          GtkAssistantPageType);
106
107 /* The introduction page of the assistant. */
108 struct intro_page
109   {
110     GtkWidget *page;
111     GtkWidget *all_cases_button;
112     GtkWidget *n_cases_button;
113     GtkWidget *n_cases_spin;
114     GtkWidget *percent_button;
115     GtkWidget *percent_spin;
116   };
117 static void init_intro_page (struct import_assistant *);
118 static void reset_intro_page (struct import_assistant *);
119
120 /* Page where the user chooses the first line of data. */
121 struct first_line_page
122   {
123     int skip_lines;    /* Number of initial lines to skip? */
124     bool variable_names; /* Variable names above first line of data? */
125
126     GtkWidget *page;
127     GtkTreeView *tree_view;
128     GtkWidget *variable_names_cb;
129   };
130 static void init_first_line_page (struct import_assistant *);
131 static void reset_first_line_page (struct import_assistant *);
132
133 /* Page where the user chooses field separators. */
134 struct separators_page
135   {
136     /* How to break lines into columns. */
137     struct string separators;   /* Field separators. */
138     struct string quotes;       /* Quote characters. */
139     bool escape;                /* Doubled quotes yield a quote mark? */
140
141     /* The columns produced thereby. */
142     struct column *columns;     /* Information about each column. */
143     size_t column_cnt;          /* Number of columns. */
144
145     GtkWidget *page;
146     GtkWidget *custom_cb;
147     GtkWidget *custom_entry;
148     GtkWidget *quote_cb;
149     GtkWidget *quote_combo;
150     GtkEntry *quote_entry;
151     GtkWidget *escape_cb;
152     GtkTreeView *fields_tree_view;
153   };
154 /* The columns that the separators divide the data into. */
155 struct column
156   {
157     /* Variable name for this column.  This is the variable name
158        used on the separators page; it can be overridden by the
159        user on the formats page. */
160     char *name;
161
162     /* Maximum length of any row in this column. */
163     size_t width;
164
165     /* Contents of this column: contents[row] is the contents for
166        the given row.
167
168        A null substring indicates a missing column for that row
169        (because the line contains an insufficient number of
170        separators).
171
172        contents[] elements may be substrings of the lines[]
173        strings that represent the whole lines of the file, to
174        save memory.  Other elements are dynamically allocated
175        with ss_alloc_substring. */
176     struct substring *contents;
177   };
178 static void init_separators_page (struct import_assistant *);
179 static void destroy_separators_page (struct import_assistant *);
180 static void prepare_separators_page (struct import_assistant *);
181 static void reset_separators_page (struct import_assistant *);
182
183 /* Page where the user verifies and adjusts input formats. */
184 struct formats_page
185   {
186     struct dictionary *dict;
187
188     GtkWidget *page;
189     GtkTreeView *data_tree_view;
190     PsppireDict *psppire_dict;
191     struct variable **modified_vars;
192     size_t modified_var_cnt;
193   };
194 static void init_formats_page (struct import_assistant *);
195 static void destroy_formats_page (struct import_assistant *);
196 static void prepare_formats_page (struct import_assistant *);
197 static void reset_formats_page (struct import_assistant *);
198
199 struct import_assistant
200   {
201     struct file file;
202     struct assistant asst;
203     struct intro_page intro;
204     struct first_line_page first_line;
205     struct separators_page separators;
206     struct formats_page formats;
207   };
208
209 static void apply_dict (const struct dictionary *, struct string *);
210 static char *generate_syntax (const struct import_assistant *);
211
212 static gboolean get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
213                                       const struct import_assistant *,
214                                       size_t *row, size_t *column);
215 static void make_tree_view (const struct import_assistant *ia,
216                             size_t first_line,
217                             GtkTreeView **tree_view);
218 static void add_line_number_column (const struct import_assistant *,
219                                     GtkTreeView *);
220 static gint get_monospace_width (GtkTreeView *, GtkCellRenderer *,
221                                  size_t char_cnt);
222 static gint get_string_width (GtkTreeView *, GtkCellRenderer *,
223                               const char *string);
224 static GtkTreeViewColumn *make_data_column (struct import_assistant *,
225                                             GtkTreeView *, bool input,
226                                             gint column_idx);
227 static GtkTreeView *create_data_tree_view (bool input, GtkContainer *parent,
228                                            struct import_assistant *);
229 static char *escape_underscores (const char *in);
230 static void push_watch_cursor (struct import_assistant *);
231 static void pop_watch_cursor (struct import_assistant *);
232
233 /* Pops up the Text Data Import assistant. */
234 void
235 text_data_import_assistant (PsppireDataWindow *dw)
236 {
237   GtkWindow *parent_window = GTK_WINDOW (dw);
238   struct import_assistant *ia;
239
240   ia = xzalloc (sizeof *ia);
241   if (!init_file (ia, parent_window))
242     {
243       free (ia);
244       return;
245     }
246
247   init_assistant (ia, parent_window);
248   init_intro_page (ia);
249   init_first_line_page (ia);
250   init_separators_page (ia);
251   init_formats_page (ia);
252
253   gtk_widget_show_all (GTK_WIDGET (ia->asst.assistant));
254
255   ia->asst.main_loop = g_main_loop_new (NULL, false);
256   g_main_loop_run (ia->asst.main_loop);
257   g_main_loop_unref (ia->asst.main_loop);
258
259   switch (ia->asst.response)
260     {
261     case GTK_RESPONSE_APPLY:
262       free (execute_syntax_string (dw, generate_syntax (ia)));
263       break;
264     case PSPPIRE_RESPONSE_PASTE:
265       free (paste_syntax_to_window (generate_syntax (ia)));
266       break;
267     default:
268       break;
269     }
270
271   destroy_formats_page (ia);
272   destroy_separators_page (ia);
273   destroy_assistant (ia);
274   destroy_file (ia);
275   free (ia);
276 }
277
278 /* Emits PSPP syntax to S that applies the dictionary attributes
279    (such as missing values and value labels) of the variables in
280    DICT.  */
281 static void
282 apply_dict (const struct dictionary *dict, struct string *s)
283 {
284   size_t var_cnt = dict_get_var_cnt (dict);
285   size_t i;
286
287   for (i = 0; i < var_cnt; i++)
288     {
289       struct variable *var = dict_get_var (dict, i);
290       const char *name = var_get_name (var);
291       enum val_type type = var_get_type (var);
292       int width = var_get_width (var);
293       enum measure measure = var_get_measure (var);
294       enum alignment alignment = var_get_alignment (var);
295       const struct fmt_spec *format = var_get_print_format (var);
296
297       if (var_has_missing_values (var))
298         {
299           const struct missing_values *mv = var_get_missing_values (var);
300           size_t j;
301
302           syntax_gen_pspp (s, "MISSING VALUES %ss (", name);
303           for (j = 0; j < mv_n_values (mv); j++)
304             {
305               if (j)
306                 ds_put_cstr (s, ", ");
307               syntax_gen_value (s, mv_get_value (mv, j), width, format);
308             }
309
310           if (mv_has_range (mv))
311             {
312               double low, high;
313               if (mv_has_value (mv))
314                 ds_put_cstr (s, ", ");
315               mv_get_range (mv, &low, &high);
316               syntax_gen_num_range (s, low, high, format);
317             }
318           ds_put_cstr (s, ").\n");
319         }
320       if (var_has_value_labels (var))
321         {
322           const struct val_labs *vls = var_get_value_labels (var);
323           const struct val_lab **labels = val_labs_sorted (vls);
324           size_t n_labels = val_labs_count (vls);
325           size_t i;
326
327           syntax_gen_pspp (s, "VALUE LABELS %ss", name);
328           for (i = 0; i < n_labels; i++)
329             {
330               const struct val_lab *vl = labels[i];
331               ds_put_cstr (s, "\n  ");
332               syntax_gen_value (s, &vl->value, width, format);
333               ds_put_byte (s, ' ');
334               syntax_gen_string (s, ss_cstr (val_lab_get_escaped_label (vl)));
335             }
336           free (labels);
337           ds_put_cstr (s, ".\n");
338         }
339       if (var_has_label (var))
340         syntax_gen_pspp (s, "VARIABLE LABELS %ss %sq.\n",
341                          name, var_get_label (var));
342       if (measure != var_default_measure (type))
343         syntax_gen_pspp (s, "VARIABLE LEVEL %ss (%ss).\n",
344                          name,
345                          (measure == MEASURE_NOMINAL ? "NOMINAL"
346                           : measure == MEASURE_ORDINAL ? "ORDINAL"
347                           : "SCALE"));
348       if (alignment != var_default_alignment (type))
349         syntax_gen_pspp (s, "VARIABLE ALIGNMENT %ss (%ss).\n",
350                          name,
351                          (alignment == ALIGN_LEFT ? "LEFT"
352                           : alignment == ALIGN_CENTRE ? "CENTER"
353                           : "RIGHT"));
354       if (var_get_display_width (var) != var_default_display_width (width))
355         syntax_gen_pspp (s, "VARIABLE WIDTH %ss (%d).\n",
356                          name, var_get_display_width (var));
357     }
358 }
359
360 /* Generates and returns PSPP syntax to execute the import
361    operation described by IA.  The caller must free the syntax
362    with free(). */
363 static char *
364 generate_syntax (const struct import_assistant *ia)
365 {
366   struct string s = DS_EMPTY_INITIALIZER;
367   size_t var_cnt;
368   size_t i;
369
370   syntax_gen_pspp (&s,
371                    "GET DATA\n"
372                    "  /TYPE=TXT\n"
373                    "  /FILE=%sq\n",
374                    ia->file.file_name);
375   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
376                                       ia->intro.n_cases_button)))
377     ds_put_format (&s, "  /IMPORTCASES=FIRST %d\n",
378                    gtk_spin_button_get_value_as_int (
379                      GTK_SPIN_BUTTON (ia->intro.n_cases_spin)));
380   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
381                                            ia->intro.percent_button)))
382     ds_put_format (&s, "  /IMPORTCASES=PERCENT %d\n",
383                    gtk_spin_button_get_value_as_int (
384                      GTK_SPIN_BUTTON (ia->intro.percent_spin)));
385   else
386     ds_put_cstr (&s, "  /IMPORTCASES=ALL\n");
387   ds_put_cstr (&s,
388                "  /ARRANGEMENT=DELIMITED\n"
389                "  /DELCASE=LINE\n");
390   if (ia->first_line.skip_lines > 0)
391     ds_put_format (&s, "  /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
392   ds_put_cstr (&s, "  /DELIMITERS=\"");
393   if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
394     ds_put_cstr (&s, "\\t");
395   if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
396     ds_put_cstr (&s, "\\\\");
397   for (i = 0; i < ds_length (&ia->separators.separators); i++)
398     {
399       char c = ds_at (&ia->separators.separators, i);
400       if (c == '"')
401         ds_put_cstr (&s, "\"\"");
402       else if (c != '\t' && c != '\\')
403         ds_put_byte (&s, c);
404     }
405   ds_put_cstr (&s, "\"\n");
406   if (!ds_is_empty (&ia->separators.quotes))
407     syntax_gen_pspp (&s, "  /QUALIFIER=%sq\n", ds_cstr (&ia->separators.quotes));
408   if (!ds_is_empty (&ia->separators.quotes) && ia->separators.escape)
409     ds_put_cstr (&s, "  /ESCAPE\n");
410   ds_put_cstr (&s, "  /VARIABLES=\n");
411
412   var_cnt = dict_get_var_cnt (ia->formats.dict);
413   for (i = 0; i < var_cnt; i++)
414     {
415       struct variable *var = dict_get_var (ia->formats.dict, i);
416       char format_string[FMT_STRING_LEN_MAX + 1];
417       fmt_to_string (var_get_print_format (var), format_string);
418       ds_put_format (&s, "    %s %s%s\n",
419                      var_get_name (var), format_string,
420                      i == var_cnt - 1 ? "." : "");
421     }
422
423   apply_dict (ia->formats.dict, &s);
424
425   return ds_cstr (&s);
426 }
427 \f
428 /* Choosing a file and reading it. */
429
430 static char *choose_file (GtkWindow *parent_window);
431
432 /* Obtains the file to import from the user and initializes IA's
433    file substructure.  PARENT_WINDOW must be the window to use
434    as the file chooser window's parent.
435
436    Returns true if successful, false if the file name could not
437    be obtained or the file could not be read. */
438 static bool
439 init_file (struct import_assistant *ia, GtkWindow *parent_window)
440 {
441   struct file *file = &ia->file;
442   enum { MAX_PREVIEW_LINES = 1000 }; /* Max number of lines to read. */
443   enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
444   FILE *stream;
445
446   file->file_name = choose_file (parent_window);
447   if (file->file_name == NULL)
448     return false;
449
450   stream = fopen (file->file_name, "r");
451   if (stream == NULL)
452     {
453       msg (ME, _("Could not open `%s': %s"),
454            file->file_name, strerror (errno));
455       return false;
456     }
457
458   file->lines = xnmalloc (MAX_PREVIEW_LINES, sizeof *file->lines);
459   for (; file->line_cnt < MAX_PREVIEW_LINES; file->line_cnt++)
460     {
461       struct string *line = &file->lines[file->line_cnt];
462
463       ds_init_empty (line);
464       if (!ds_read_line (line, stream, MAX_LINE_LEN))
465         {
466           if (feof (stream))
467             break;
468           else if (ferror (stream))
469             msg (ME, _("Error reading `%s': %s"),
470                  file->file_name, strerror (errno));
471           else
472             msg (ME, _("Failed to read `%s', because it contains a line "
473                        "over %d bytes long and therefore appears not to be "
474                        "a text file."),
475                  file->file_name, MAX_LINE_LEN);
476           fclose (stream);
477           destroy_file (ia);
478           return false;
479         }
480       ds_chomp_byte (line, '\n');
481       ds_chomp_byte (line, '\r');
482     }
483
484   if (file->line_cnt == 0)
485     {
486       msg (ME, _("`%s' is empty."), file->file_name);
487       fclose (stream);
488       destroy_file (ia);
489       return false;
490     }
491
492   /* Estimate the number of lines in the file. */
493   if (file->line_cnt < MAX_PREVIEW_LINES)
494     file->total_lines = file->line_cnt;
495   else
496     {
497       struct stat s;
498       off_t position = ftello (stream);
499       if (fstat (fileno (stream), &s) == 0 && position > 0)
500         file->total_lines = (double) file->line_cnt / position * s.st_size;
501       else
502         file->total_lines = 0;
503     }
504
505   return true;
506 }
507
508 /* Frees IA's file substructure. */
509 static void
510 destroy_file (struct import_assistant *ia)
511 {
512   struct file *f = &ia->file;
513   size_t i;
514
515   for (i = 0; i < f->line_cnt; i++)
516     ds_destroy (&f->lines[i]);
517   free (f->lines);
518   g_free (f->file_name);
519 }
520
521 /* Obtains the file to read from the user and returns the name of
522    the file as a string that must be freed with g_free if
523    successful, otherwise a null pointer.  PARENT_WINDOW must be
524    the window to use as the file chooser window's parent. */
525 static char *
526 choose_file (GtkWindow *parent_window)
527 {
528   char *file_name;
529   GtkFileFilter *filter = NULL;
530
531   GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Import Delimited Text Data"),
532                                         parent_window,
533                                         GTK_FILE_CHOOSER_ACTION_OPEN,
534                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
535                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
536                                         NULL);
537
538   g_object_set (dialog, "local-only", FALSE, NULL);
539
540   filter = gtk_file_filter_new ();
541   gtk_file_filter_set_name (filter, _("Text files"));
542   gtk_file_filter_add_mime_type (filter, "text/*");
543   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
544
545   filter = gtk_file_filter_new ();
546   gtk_file_filter_set_name (filter, _("Text (*.txt) Files"));
547   gtk_file_filter_add_pattern (filter, "*.txt");
548   gtk_file_filter_add_pattern (filter, "*.TXT");
549   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
550
551   filter = gtk_file_filter_new ();
552   gtk_file_filter_set_name (filter, _("Plain Text (ASCII) Files"));
553   gtk_file_filter_add_mime_type (filter, "text/plain");
554   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
555
556   filter = gtk_file_filter_new ();
557   gtk_file_filter_set_name (filter, _("Comma Separated Value Files"));
558   gtk_file_filter_add_mime_type (filter, "text/csv");
559   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
560
561   /* I've never encountered one of these, but it's listed here:
562      http://www.iana.org/assignments/media-types/text/tab-separated-values  */
563   filter = gtk_file_filter_new ();
564   gtk_file_filter_set_name (filter, _("Tab Separated Value Files"));
565   gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
566   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
567
568   filter = gtk_file_filter_new ();
569   gtk_file_filter_set_name (filter, _("All Files"));
570   gtk_file_filter_add_pattern (filter, "*");
571   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
572
573   switch (gtk_dialog_run (GTK_DIALOG (dialog)))
574     {
575     case GTK_RESPONSE_ACCEPT:
576       file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
577       break;
578     default:
579       file_name = NULL;
580       break;
581     }
582   gtk_widget_destroy (dialog);
583
584   return file_name;
585 }
586 \f
587 /* Assistant. */
588
589 static void close_assistant (struct import_assistant *, int response);
590 static void on_prepare (GtkAssistant *assistant, GtkWidget *page,
591                         struct import_assistant *);
592 static void on_cancel (GtkAssistant *assistant, struct import_assistant *);
593 static void on_close (GtkAssistant *assistant, struct import_assistant *);
594 static void on_paste (GtkButton *button, struct import_assistant *);
595 static void on_reset (GtkButton *button, struct import_assistant *);
596 static void close_assistant (struct import_assistant *, int response);
597
598 /* Initializes IA's asst substructure.  PARENT_WINDOW must be the
599    window to use as the assistant window's parent.  */
600 static void
601 init_assistant (struct import_assistant *ia, GtkWindow *parent_window)
602 {
603   struct assistant *a = &ia->asst;
604
605   a->builder = builder_new ("text-data-import.ui");
606   a->assistant = GTK_ASSISTANT (gtk_assistant_new ());
607   g_signal_connect (a->assistant, "prepare", G_CALLBACK (on_prepare), ia);
608   g_signal_connect (a->assistant, "cancel", G_CALLBACK (on_cancel), ia);
609   g_signal_connect (a->assistant, "close", G_CALLBACK (on_close), ia);
610   a->paste_button = gtk_button_new_from_stock (GTK_STOCK_PASTE);
611   gtk_assistant_add_action_widget (a->assistant, a->paste_button);
612   g_signal_connect (a->paste_button, "clicked", G_CALLBACK (on_paste), ia);
613   a->reset_button = gtk_button_new_from_stock ("pspp-stock-reset");
614   gtk_assistant_add_action_widget (a->assistant, a->reset_button);
615   g_signal_connect (a->reset_button, "clicked", G_CALLBACK (on_reset), ia);
616   gtk_window_set_title (GTK_WINDOW (a->assistant),
617                         _("Importing Delimited Text Data"));
618   gtk_window_set_transient_for (GTK_WINDOW (a->assistant), parent_window);
619   gtk_window_set_icon_name (GTK_WINDOW (a->assistant), "pspp");
620
621   a->prop_renderer = gtk_cell_renderer_text_new ();
622   g_object_ref_sink (a->prop_renderer);
623   a->fixed_renderer = gtk_cell_renderer_text_new ();
624   g_object_ref_sink (a->fixed_renderer);
625   g_object_set (G_OBJECT (a->fixed_renderer),
626                 "family", "Monospace",
627                 (void *) NULL);
628 }
629
630 /* Frees IA's asst substructure. */
631 static void
632 destroy_assistant (struct import_assistant *ia)
633 {
634   struct assistant *a = &ia->asst;
635
636   g_object_unref (a->prop_renderer);
637   g_object_unref (a->fixed_renderer);
638   g_object_unref (a->builder);
639 }
640
641 /* Appends a page of the given TYPE, with PAGE as its content, to
642    the GtkAssistant encapsulated by IA.  Returns the GtkWidget
643    that represents the page. */
644 static GtkWidget *
645 add_page_to_assistant (struct import_assistant *ia,
646                        GtkWidget *page, GtkAssistantPageType type)
647 {
648   const char *title;
649   char *title_copy;
650   GtkWidget *content;
651
652   title = gtk_window_get_title (GTK_WINDOW (page));
653   title_copy = xstrdup (title ? title : "");
654
655   content = gtk_bin_get_child (GTK_BIN (page));
656   assert (content);
657   g_object_ref (content);
658   gtk_container_remove (GTK_CONTAINER (page), content);
659
660   gtk_widget_destroy (page);
661
662   gtk_assistant_append_page (ia->asst.assistant, content);
663   gtk_assistant_set_page_type (ia->asst.assistant, content, type);
664   gtk_assistant_set_page_title (ia->asst.assistant, content, title_copy);
665   gtk_assistant_set_page_complete (ia->asst.assistant, content, true);
666
667   free (title_copy);
668
669   return content;
670 }
671
672 /* Called just before PAGE is displayed as the current page of
673    ASSISTANT, this updates IA content according to the new
674    page. */
675 static void
676 on_prepare (GtkAssistant *assistant, GtkWidget *page,
677             struct import_assistant *ia)
678 {
679
680   if (gtk_assistant_get_page_type (assistant, page)
681       == GTK_ASSISTANT_PAGE_CONFIRM)
682     gtk_widget_grab_focus (assistant->apply);
683   else
684     gtk_widget_grab_focus (assistant->forward);
685
686   if (page == ia->separators.page)
687     prepare_separators_page (ia);
688   else if (page == ia->formats.page)
689     prepare_formats_page (ia);
690
691   gtk_widget_show (ia->asst.reset_button);
692   if (page == ia->formats.page)
693     gtk_widget_show (ia->asst.paste_button);
694   else
695     gtk_widget_hide (ia->asst.paste_button);
696 }
697
698 /* Called when the Cancel button in the assistant is clicked. */
699 static void
700 on_cancel (GtkAssistant *assistant, struct import_assistant *ia)
701 {
702   close_assistant (ia, GTK_RESPONSE_CANCEL);
703 }
704
705 /* Called when the Apply button on the last page of the assistant
706    is clicked. */
707 static void
708 on_close (GtkAssistant *assistant, struct import_assistant *ia)
709 {
710   close_assistant (ia, GTK_RESPONSE_APPLY);
711 }
712
713 /* Called when the Paste button on the last page of the assistant
714    is clicked. */
715 static void
716 on_paste (GtkButton *button, struct import_assistant *ia)
717 {
718   close_assistant (ia, PSPPIRE_RESPONSE_PASTE);
719 }
720
721 /* Called when the Reset button is clicked. */
722 static void
723 on_reset (GtkButton *button, struct import_assistant *ia)
724 {
725   gint page_num = gtk_assistant_get_current_page (ia->asst.assistant);
726   GtkWidget *page = gtk_assistant_get_nth_page (ia->asst.assistant, page_num);
727
728   if (page == ia->intro.page)
729     reset_intro_page (ia);
730   else if (page == ia->first_line.page)
731     reset_first_line_page (ia);
732   else if (page == ia->separators.page)
733     reset_separators_page (ia);
734   else if (page == ia->formats.page)
735     reset_formats_page (ia);
736 }
737
738 /* Causes the assistant to close, returning RESPONSE for
739    interpretation by text_data_import_assistant. */
740 static void
741 close_assistant (struct import_assistant *ia, int response)
742 {
743   ia->asst.response = response;
744   g_main_loop_quit (ia->asst.main_loop);
745   gtk_widget_hide (GTK_WIDGET (ia->asst.assistant));
746 }
747 \f
748 /* The "intro" page of the assistant. */
749
750 static void on_intro_amount_changed (struct import_assistant *);
751
752 /* Initializes IA's intro substructure. */
753 static void
754 init_intro_page (struct import_assistant *ia)
755 {
756   GtkBuilder *builder = ia->asst.builder;
757   struct intro_page *p = &ia->intro;
758   struct string s;
759   GtkWidget *hbox_n_cases ;
760   GtkWidget *hbox_percent ;
761   GtkWidget *table ;
762
763
764   p->n_cases_spin = gtk_spin_button_new_with_range (0, INT_MAX, 100);
765
766   hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &p->n_cases_spin);
767
768   table  = get_widget_assert (builder, "button-table");
769
770   gtk_table_attach_defaults (GTK_TABLE (table), hbox_n_cases,
771                     1, 2,
772                     1, 2);
773
774   p->percent_spin = gtk_spin_button_new_with_range (0, 100, 10);
775
776   hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), &p->percent_spin);
777
778   gtk_table_attach_defaults (GTK_TABLE (table), hbox_percent,
779                              1, 2,
780                              2, 3);
781
782   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Intro"),
783                                    GTK_ASSISTANT_PAGE_INTRO);
784
785   p->all_cases_button = get_widget_assert (builder, "import-all-cases");
786
787   p->n_cases_button = get_widget_assert (builder, "import-n-cases");
788
789   p->percent_button = get_widget_assert (builder, "import-percent");
790
791   g_signal_connect_swapped (p->all_cases_button, "toggled",
792                     G_CALLBACK (on_intro_amount_changed), ia);
793   g_signal_connect_swapped (p->n_cases_button, "toggled",
794                     G_CALLBACK (on_intro_amount_changed), ia);
795   g_signal_connect_swapped (p->percent_button, "toggled",
796                     G_CALLBACK (on_intro_amount_changed), ia);
797
798   on_intro_amount_changed (ia);
799
800   ds_init_empty (&s);
801   ds_put_cstr (&s, _("This assistant will guide you through the process of "
802                      "importing data into PSPP from a text file with one line "
803                      "per case,  in which fields are separated by tabs, "
804                      "commas, or other delimiters.\n\n"));
805   if (ia->file.total_is_exact)
806     ds_put_format (
807       &s, ngettext ("The selected file contains %zu line of text.  ",
808                     "The selected file contains %zu lines of text.  ",
809                     ia->file.line_cnt),
810       ia->file.line_cnt);
811   else if (ia->file.total_lines > 0)
812     {
813       ds_put_format (
814         &s, ngettext (
815           "The selected file contains approximately %lu line of text.  ",
816           "The selected file contains approximately %lu lines of text.  ",
817           ia->file.total_lines),
818         ia->file.total_lines);
819       ds_put_format (
820         &s, ngettext (
821           "Only the first %zu line of the file will be shown for "
822           "preview purposes in the following screens.  ",
823           "Only the first %zu lines of the file will be shown for "
824           "preview purposes in the following screens.  ",
825           ia->file.line_cnt),
826         ia->file.line_cnt);
827     }
828   ds_put_cstr (&s, _("You may choose below how much of the file should "
829                      "actually be imported."));
830   gtk_label_set_text (GTK_LABEL (get_widget_assert (builder, "intro-label")),
831                       ds_cstr (&s));
832   ds_destroy (&s);
833 }
834
835 /* Resets IA's intro page to its initial state. */
836 static void
837 reset_intro_page (struct import_assistant *ia)
838 {
839   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->intro.all_cases_button),
840                                 true);
841 }
842
843 /* Called when one of the radio buttons is clicked. */
844 static void
845 on_intro_amount_changed (struct import_assistant *ia)
846 {
847   struct intro_page *p = &ia->intro;
848
849   gtk_widget_set_sensitive (p->n_cases_spin,
850                             gtk_toggle_button_get_active (
851                               GTK_TOGGLE_BUTTON (p->n_cases_button)));
852
853   gtk_widget_set_sensitive (p->percent_spin,
854                             gtk_toggle_button_get_active (
855                               GTK_TOGGLE_BUTTON (p->percent_button)));
856 }
857 \f
858 /* The "first line" page of the assistant. */
859
860 static GtkTreeView *create_lines_tree_view (GtkContainer *parent_window,
861                                             struct import_assistant *);
862 static void on_first_line_change (GtkTreeSelection *,
863                                   struct import_assistant *);
864 static void on_variable_names_cb_toggle (GtkToggleButton *,
865                                          struct import_assistant *);
866 static void set_first_line (struct import_assistant *);
867 static void get_first_line (struct import_assistant *);
868
869 /* Initializes IA's first_line substructure. */
870 static void
871 init_first_line_page (struct import_assistant *ia)
872 {
873   struct first_line_page *p = &ia->first_line;
874   GtkBuilder *builder = ia->asst.builder;
875
876   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "FirstLine"),
877                                    GTK_ASSISTANT_PAGE_CONTENT);
878   gtk_widget_destroy (get_widget_assert (builder, "first-line"));
879   p->tree_view = create_lines_tree_view (
880     GTK_CONTAINER (get_widget_assert (builder, "first-line-scroller")), ia);
881   p->variable_names_cb = get_widget_assert (builder, "variable-names");
882   gtk_tree_selection_set_mode (
883     gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)),
884     GTK_SELECTION_BROWSE);
885   set_first_line (ia);
886   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)),
887                     "changed", G_CALLBACK (on_first_line_change), ia);
888   g_signal_connect (p->variable_names_cb, "toggled",
889                     G_CALLBACK (on_variable_names_cb_toggle), ia);
890 }
891
892 /* Resets the first_line page to its initial content. */
893 static void
894 reset_first_line_page (struct import_assistant *ia)
895 {
896   ia->first_line.skip_lines = 0;
897   ia->first_line.variable_names = false;
898   set_first_line (ia);
899 }
900
901 /* Creates and returns a tree view that contains each of the
902    lines in IA's file as a row. */
903 static GtkTreeView *
904 create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
905 {
906   GtkTreeView *tree_view;
907   GtkTreeViewColumn *column;
908   size_t max_line_length;
909   gint content_width, header_width;
910   size_t i;
911   const gchar *title = _("Text");
912
913   make_tree_view (ia, 0, &tree_view);
914
915   column = gtk_tree_view_column_new_with_attributes 
916     (
917      title, ia->asst.fixed_renderer,
918      "text", TEXT_IMPORT_MODEL_COLUMN_LINE,
919      (void *) NULL
920      );
921   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
922
923   max_line_length = 0;
924   for (i = 0; i < ia->file.line_cnt; i++)
925     {
926       size_t w = ds_length (&ia->file.lines[i]);
927       max_line_length = MAX (max_line_length, w);
928     }
929
930   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
931                                        max_line_length);
932   header_width = get_string_width (tree_view, ia->asst.prop_renderer, title);
933   gtk_tree_view_column_set_fixed_width (column, MAX (content_width,
934                                                      header_width));
935   gtk_tree_view_append_column (tree_view, column);
936
937   gtk_tree_view_set_fixed_height_mode (tree_view, true);
938
939   gtk_container_add (parent, GTK_WIDGET (tree_view));
940   gtk_widget_show (GTK_WIDGET (tree_view));
941
942   return tree_view;
943 }
944
945 /* Called when the line selected in the first_line tree view
946    changes. */
947 static void
948 on_first_line_change (GtkTreeSelection *selection UNUSED,
949                       struct import_assistant *ia)
950 {
951   get_first_line (ia);
952 }
953
954 /* Called when the checkbox that indicates whether variable
955    names are in the row above the first line is toggled. */
956 static void
957 on_variable_names_cb_toggle (GtkToggleButton *variable_names_cb UNUSED,
958                              struct import_assistant *ia)
959 {
960   get_first_line (ia);
961 }
962
963 /* Sets the widgets to match IA's first_line substructure. */
964 static void
965 set_first_line (struct import_assistant *ia)
966 {
967   GtkTreePath *path;
968
969   path = gtk_tree_path_new_from_indices (ia->first_line.skip_lines, -1);
970   gtk_tree_view_set_cursor (GTK_TREE_VIEW (ia->first_line.tree_view),
971                             path, NULL, false);
972   gtk_tree_path_free (path);
973
974   gtk_toggle_button_set_active (
975     GTK_TOGGLE_BUTTON (ia->first_line.variable_names_cb),
976     ia->first_line.variable_names);
977   gtk_widget_set_sensitive (ia->first_line.variable_names_cb,
978                             ia->first_line.skip_lines > 0);
979 }
980
981 /* Sets IA's first_line substructure to match the widgets. */
982 static void
983 get_first_line (struct import_assistant *ia)
984 {
985   GtkTreeSelection *selection;
986   GtkTreeIter iter;
987   GtkTreeModel *model;
988
989   selection = gtk_tree_view_get_selection (ia->first_line.tree_view);
990   if (gtk_tree_selection_get_selected (selection, &model, &iter))
991     {
992       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
993       int row = gtk_tree_path_get_indices (path)[0];
994       gtk_tree_path_free (path);
995
996       ia->first_line.skip_lines = row;
997       ia->first_line.variable_names =
998         (ia->first_line.skip_lines > 0
999          && gtk_toggle_button_get_active (
1000            GTK_TOGGLE_BUTTON (ia->first_line.variable_names_cb)));
1001     }
1002   gtk_widget_set_sensitive (ia->first_line.variable_names_cb,
1003                             ia->first_line.skip_lines > 0);
1004 }
1005 \f
1006 /* The "separators" page of the assistant. */
1007
1008 static void revise_fields_preview (struct import_assistant *ia);
1009 static void choose_likely_separators (struct import_assistant *ia);
1010 static void find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
1011                                   const char *targets, const char *def,
1012                                   struct string *result);
1013 static void clear_fields (struct import_assistant *ia);
1014 static void revise_fields_preview (struct import_assistant *);
1015 static void set_separators (struct import_assistant *);
1016 static void get_separators (struct import_assistant *);
1017 static void on_separators_custom_entry_notify (GObject *UNUSED,
1018                                                GParamSpec *UNUSED,
1019                                                struct import_assistant *);
1020 static void on_separators_custom_cb_toggle (GtkToggleButton *custom_cb,
1021                                             struct import_assistant *);
1022 static void on_quote_combo_change (GtkComboBox *combo,
1023                                    struct import_assistant *);
1024 static void on_quote_cb_toggle (GtkToggleButton *quote_cb,
1025                                 struct import_assistant *);
1026 static void on_separator_toggle (GtkToggleButton *, struct import_assistant *);
1027 static void render_input_cell (GtkTreeViewColumn *tree_column,
1028                                GtkCellRenderer *cell,
1029                                GtkTreeModel *model, GtkTreeIter *iter,
1030                                gpointer ia);
1031 static gboolean on_query_input_tooltip (GtkWidget *widget, gint wx, gint wy,
1032                                         gboolean keyboard_mode UNUSED,
1033                                         GtkTooltip *tooltip,
1034                                         struct import_assistant *);
1035
1036 /* A common field separator and its identifying name. */
1037 struct separator
1038   {
1039     const char *name;           /* Name (for use with get_widget_assert). */
1040     int c;                      /* Separator character. */
1041   };
1042
1043 /* All the separators in the dialog box. */
1044 static const struct separator separators[] =
1045   {
1046     {"space", ' '},
1047     {"tab", '\t'},
1048     {"bang", '!'},
1049     {"colon", ':'},
1050     {"comma", ','},
1051     {"hyphen", '-'},
1052     {"pipe", '|'},
1053     {"semicolon", ';'},
1054     {"slash", '/'},
1055   };
1056 #define SEPARATOR_CNT (sizeof separators / sizeof *separators)
1057
1058 static void
1059 set_quote_list (GtkComboBoxEntry *cb)
1060 {
1061   GtkListStore *list =  gtk_list_store_new (1, G_TYPE_STRING);
1062   GtkTreeIter iter;
1063   gint i;
1064   const gchar *seperator[3] = {"'\"", "\'", "\""};
1065
1066   for (i = 0; i < 3; i++)
1067     {
1068       const gchar *s = seperator[i];
1069
1070       /* Add a new row to the model */
1071       gtk_list_store_append (list, &iter);
1072       gtk_list_store_set (list, &iter,
1073                           0, s,
1074                           -1);
1075
1076     }
1077
1078   gtk_combo_box_set_model (GTK_COMBO_BOX (cb), GTK_TREE_MODEL (list));
1079
1080   gtk_combo_box_entry_set_text_column (cb, 0);
1081 }
1082
1083 /* Initializes IA's separators substructure. */
1084 static void
1085 init_separators_page (struct import_assistant *ia)
1086 {
1087   GtkBuilder *builder = ia->asst.builder;
1088   struct separators_page *p = &ia->separators;
1089   size_t i;
1090
1091   choose_likely_separators (ia);
1092
1093   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Separators"),
1094                                    GTK_ASSISTANT_PAGE_CONTENT);
1095   p->custom_cb = get_widget_assert (builder, "custom-cb");
1096   p->custom_entry = get_widget_assert (builder, "custom-entry");
1097   p->quote_combo = get_widget_assert (builder, "quote-combo");
1098   p->quote_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (p->quote_combo)));
1099   p->quote_cb = get_widget_assert (builder, "quote-cb");
1100   p->escape_cb = get_widget_assert (builder, "escape");
1101
1102   set_separators (ia);
1103   set_quote_list (GTK_COMBO_BOX_ENTRY (p->quote_combo));
1104   p->fields_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "fields"));
1105   g_signal_connect (p->quote_combo, "changed",
1106                     G_CALLBACK (on_quote_combo_change), ia);
1107   g_signal_connect (p->quote_cb, "toggled",
1108                     G_CALLBACK (on_quote_cb_toggle), ia);
1109   g_signal_connect (p->custom_entry, "notify::text",
1110                     G_CALLBACK (on_separators_custom_entry_notify), ia);
1111   g_signal_connect (p->custom_cb, "toggled",
1112                     G_CALLBACK (on_separators_custom_cb_toggle), ia);
1113   for (i = 0; i < SEPARATOR_CNT; i++)
1114     g_signal_connect (get_widget_assert (builder, separators[i].name),
1115                       "toggled", G_CALLBACK (on_separator_toggle), ia);
1116   g_signal_connect (p->escape_cb, "toggled",
1117                     G_CALLBACK (on_separator_toggle), ia);
1118 }
1119
1120 /* Frees IA's separators substructure. */
1121 static void
1122 destroy_separators_page (struct import_assistant *ia)
1123 {
1124   struct separators_page *s = &ia->separators;
1125
1126   ds_destroy (&s->separators);
1127   ds_destroy (&s->quotes);
1128   clear_fields (ia);
1129 }
1130
1131 /* Called just before the separators page becomes visible in the
1132    assistant. */
1133 static void
1134 prepare_separators_page (struct import_assistant *ia)
1135 {
1136   revise_fields_preview (ia);
1137 }
1138
1139 /* Called when the Reset button is clicked on the separators
1140    page, resets the separators to the defaults. */
1141 static void
1142 reset_separators_page (struct import_assistant *ia)
1143 {
1144   choose_likely_separators (ia);
1145   set_separators (ia);
1146 }
1147
1148 /* Frees and clears the column data in IA's separators
1149    substructure. */
1150 static void
1151 clear_fields (struct import_assistant *ia)
1152 {
1153   struct separators_page *s = &ia->separators;
1154
1155   if (s->column_cnt > 0)
1156     {
1157       struct column *col;
1158       size_t row;
1159
1160       for (row = 0; row < ia->file.line_cnt; row++)
1161         {
1162           const struct string *line = &ia->file.lines[row];
1163           const char *line_start = ds_data (line);
1164           const char *line_end = ds_end (line);
1165
1166           for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
1167             {
1168               char *s = ss_data (col->contents[row]);
1169               if (!(s >= line_start && s <= line_end))
1170                 ss_dealloc (&col->contents[row]);
1171             }
1172         }
1173
1174       for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
1175         {
1176           free (col->name);
1177           free (col->contents);
1178         }
1179
1180       free (s->columns);
1181       s->columns = NULL;
1182       s->column_cnt = 0;
1183     }
1184 }
1185
1186 /* Breaks the file data in IA into columns based on the
1187    separators set in IA's separators substructure. */
1188 static void
1189 split_fields (struct import_assistant *ia)
1190 {
1191   struct separators_page *s = &ia->separators;
1192   size_t columns_allocated;
1193   bool space_sep;
1194   size_t row;
1195
1196   clear_fields (ia);
1197
1198   /* Is space in the set of separators? */
1199   space_sep = ss_find_byte (ds_ss (&s->separators), ' ') != SIZE_MAX;
1200
1201   /* Split all the lines, not just those from
1202      ia->first_line.skip_lines on, so that we split the line that
1203      contains variables names if ia->first_line.variable_names is
1204      true. */
1205   columns_allocated = 0;
1206   for (row = 0; row < ia->file.line_cnt; row++)
1207     {
1208       struct string *line = &ia->file.lines[row];
1209       struct substring text = ds_ss (line);
1210       size_t column_idx;
1211
1212       for (column_idx = 0; ; column_idx++)
1213         {
1214           struct substring field;
1215           struct column *column;
1216
1217           if (space_sep)
1218             ss_ltrim (&text, ss_cstr (" "));
1219           if (ss_is_empty (text))
1220             {
1221               if (column_idx != 0)
1222                 break;
1223               field = text;
1224             }
1225           else if (!ds_is_empty (&s->quotes)
1226                    && ds_find_byte (&s->quotes, text.string[0]) != SIZE_MAX)
1227             {
1228               int quote = ss_get_byte (&text);
1229               if (!s->escape)
1230                 ss_get_until (&text, quote, &field);
1231               else
1232                 {
1233                   struct string s;
1234                   int c;
1235
1236                   ds_init_empty (&s);
1237                   while ((c = ss_get_byte (&text)) != EOF)
1238                     if (c != quote)
1239                       ds_put_byte (&s, c);
1240                     else if (ss_match_byte (&text, quote))
1241                       ds_put_byte (&s, quote);
1242                     else
1243                       break;
1244                   field = ds_ss (&s);
1245                 }
1246             }
1247           else
1248             ss_get_bytes (&text, ss_cspan (text, ds_ss (&s->separators)),
1249                           &field);
1250
1251           if (column_idx >= s->column_cnt)
1252             {
1253               struct column *column;
1254
1255               if (s->column_cnt >= columns_allocated)
1256                 s->columns = x2nrealloc (s->columns, &columns_allocated,
1257                                          sizeof *s->columns);
1258               column = &s->columns[s->column_cnt++];
1259               column->name = NULL;
1260               column->width = 0;
1261               column->contents = xcalloc (ia->file.line_cnt,
1262                                           sizeof *column->contents);
1263             }
1264           column = &s->columns[column_idx];
1265           column->contents[row] = field;
1266           if (ss_length (field) > column->width)
1267             column->width = ss_length (field);
1268
1269           if (space_sep)
1270             ss_ltrim (&text, ss_cstr (" "));
1271           if (ss_is_empty (text))
1272             break;
1273           if (ss_find_byte (ds_ss (&s->separators), ss_first (text))
1274               != SIZE_MAX)
1275             ss_advance (&text, 1);
1276         }
1277     }
1278 }
1279
1280 /* Chooses a name for each column on the separators page */
1281 static void
1282 choose_column_names (struct import_assistant *ia)
1283 {
1284   const struct first_line_page *f = &ia->first_line;
1285   struct separators_page *s = &ia->separators;
1286   struct dictionary *dict;
1287   unsigned long int generated_name_count = 0;
1288   struct column *col;
1289   size_t name_row;
1290
1291   dict = dict_create (get_default_encoding ());
1292   name_row = f->variable_names && f->skip_lines ? f->skip_lines : 0;
1293   for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
1294     {
1295       char *hint, *name;
1296
1297       hint = name_row ? ss_xstrdup (col->contents[name_row - 1]) : NULL;
1298       name = dict_make_unique_var_name (dict, hint, &generated_name_count);
1299       free (hint);
1300
1301       col->name = name;
1302       dict_create_var_assert (dict, name, 0);
1303     }
1304   dict_destroy (dict);
1305 }
1306
1307 /* Picks the most likely separator and quote characters based on
1308    IA's file data. */
1309 static void
1310 choose_likely_separators (struct import_assistant *ia)
1311 {
1312   unsigned long int histogram[UCHAR_MAX + 1] = { 0 };
1313   size_t row;
1314
1315   /* Construct a histogram of all the characters used in the
1316      file. */
1317   for (row = 0; row < ia->file.line_cnt; row++)
1318     {
1319       struct substring line = ds_ss (&ia->file.lines[row]);
1320       size_t length = ss_length (line);
1321       size_t i;
1322       for (i = 0; i < length; i++)
1323         histogram[(unsigned char) line.string[i]]++;
1324     }
1325
1326   find_commonest_chars (histogram, "\"'", "", &ia->separators.quotes);
1327   find_commonest_chars (histogram, ",;:/|!\t-", ",",
1328                         &ia->separators.separators);
1329   ia->separators.escape = true;
1330 }
1331
1332 /* Chooses the most common character among those in TARGETS,
1333    based on the frequency data in HISTOGRAM, and stores it in
1334    RESULT.  If there is a tie for the most common character among
1335    those in TARGETS, the earliest character is chosen.  If none
1336    of the TARGETS appear at all, then DEF is used as a
1337    fallback. */
1338 static void
1339 find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
1340                       const char *targets, const char *def,
1341                       struct string *result)
1342 {
1343   unsigned char max = 0;
1344   unsigned long int max_count = 0;
1345
1346   for (; *targets != '\0'; targets++)
1347     {
1348       unsigned char c = *targets;
1349       unsigned long int count = histogram[c];
1350       if (count > max_count)
1351         {
1352           max = c;
1353           max_count = count;
1354         }
1355     }
1356   if (max_count > 0)
1357     {
1358       ds_clear (result);
1359       ds_put_byte (result, max);
1360     }
1361   else
1362     ds_assign_cstr (result, def);
1363 }
1364
1365 /* Revises the contents of the fields tree view based on the
1366    currently chosen set of separators. */
1367 static void
1368 revise_fields_preview (struct import_assistant *ia)
1369 {
1370   GtkWidget *w;
1371
1372   push_watch_cursor (ia);
1373
1374   w = GTK_WIDGET (ia->separators.fields_tree_view);
1375   gtk_widget_destroy (w);
1376   get_separators (ia);
1377   split_fields (ia);
1378   choose_column_names (ia);
1379   ia->separators.fields_tree_view = create_data_tree_view (
1380     true,
1381     GTK_CONTAINER (get_widget_assert (ia->asst.builder, "fields-scroller")),
1382     ia);
1383
1384   pop_watch_cursor (ia);
1385 }
1386
1387 /* Sets the widgets to match IA's separators substructure. */
1388 static void
1389 set_separators (struct import_assistant *ia)
1390 {
1391   struct separators_page *s = &ia->separators;
1392   unsigned int seps;
1393   struct string custom;
1394   bool any_custom;
1395   bool any_quotes;
1396   size_t i;
1397
1398   ds_init_empty (&custom);
1399   seps = 0;
1400   for (i = 0; i < ds_length (&s->separators); i++)
1401     {
1402       unsigned char c = ds_at (&s->separators, i);
1403       int j;
1404
1405       for (j = 0; j < SEPARATOR_CNT; j++)
1406         {
1407           const struct separator *s = &separators[j];
1408           if (s->c == c)
1409             {
1410               seps += 1u << j;
1411               goto next;
1412             }
1413         }
1414
1415       ds_put_byte (&custom, c);
1416     next:;
1417     }
1418
1419   for (i = 0; i < SEPARATOR_CNT; i++)
1420     {
1421       const struct separator *s = &separators[i];
1422       GtkWidget *button = get_widget_assert (ia->asst.builder, s->name);
1423       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
1424                                     (seps & (1u << i)) != 0);
1425     }
1426   any_custom = !ds_is_empty (&custom);
1427   gtk_entry_set_text (GTK_ENTRY (s->custom_entry), ds_cstr (&custom));
1428   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->custom_cb),
1429                                 any_custom);
1430   gtk_widget_set_sensitive (s->custom_entry, any_custom);
1431   ds_destroy (&custom);
1432
1433   any_quotes = !ds_is_empty (&s->quotes);
1434
1435   gtk_entry_set_text (s->quote_entry,
1436                       any_quotes ? ds_cstr (&s->quotes) : "\"");
1437   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->quote_cb),
1438                                 any_quotes);
1439   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->escape_cb),
1440                                 s->escape);
1441   gtk_widget_set_sensitive (s->quote_combo, any_quotes);
1442   gtk_widget_set_sensitive (s->escape_cb, any_quotes);
1443 }
1444
1445 /* Sets IA's separators substructure to match the widgets. */
1446 static void
1447 get_separators (struct import_assistant *ia)
1448 {
1449   struct separators_page *s = &ia->separators;
1450   int i;
1451
1452   ds_clear (&s->separators);
1453   for (i = 0; i < SEPARATOR_CNT; i++)
1454     {
1455       const struct separator *sep = &separators[i];
1456       GtkWidget *button = get_widget_assert (ia->asst.builder, sep->name);
1457       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
1458         ds_put_byte (&s->separators, sep->c);
1459     }
1460
1461   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->custom_cb)))
1462     ds_put_cstr (&s->separators,
1463                  gtk_entry_get_text (GTK_ENTRY (s->custom_entry)));
1464
1465   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->quote_cb)))
1466     {
1467       gchar *text = gtk_combo_box_get_active_text (
1468                       GTK_COMBO_BOX (s->quote_combo));
1469       ds_assign_cstr (&s->quotes, text);
1470       g_free (text);
1471     }
1472   else
1473     ds_clear (&s->quotes);
1474   s->escape = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->escape_cb));
1475 }
1476
1477 /* Called when the user changes the entry field for custom
1478    separators. */
1479 static void
1480 on_separators_custom_entry_notify (GObject *gobject UNUSED,
1481                                    GParamSpec *arg1 UNUSED,
1482                                    struct import_assistant *ia)
1483 {
1484   revise_fields_preview (ia);
1485 }
1486
1487 /* Called when the user toggles the checkbox that enables custom
1488    separators. */
1489 static void
1490 on_separators_custom_cb_toggle (GtkToggleButton *custom_cb,
1491                                 struct import_assistant *ia)
1492 {
1493   bool is_active = gtk_toggle_button_get_active (custom_cb);
1494   gtk_widget_set_sensitive (ia->separators.custom_entry, is_active);
1495   revise_fields_preview (ia);
1496 }
1497
1498 /* Called when the user changes the selection in the combo box
1499    that selects a quote character. */
1500 static void
1501 on_quote_combo_change (GtkComboBox *combo, struct import_assistant *ia)
1502 {
1503   revise_fields_preview (ia);
1504 }
1505
1506 /* Called when the user toggles the checkbox that enables
1507    quoting. */
1508 static void
1509 on_quote_cb_toggle (GtkToggleButton *quote_cb, struct import_assistant *ia)
1510 {
1511   bool is_active = gtk_toggle_button_get_active (quote_cb);
1512   gtk_widget_set_sensitive (ia->separators.quote_combo, is_active);
1513   gtk_widget_set_sensitive (ia->separators.escape_cb, is_active);
1514   revise_fields_preview (ia);
1515 }
1516
1517 /* Called when the user toggles one of the separators
1518    checkboxes. */
1519 static void
1520 on_separator_toggle (GtkToggleButton *toggle UNUSED,
1521                      struct import_assistant *ia)
1522 {
1523   revise_fields_preview (ia);
1524 }
1525
1526 /* Called to render one of the cells in the fields preview tree
1527    view. */
1528 static void
1529 render_input_cell (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1530                    GtkTreeModel *model, GtkTreeIter *iter,
1531                    gpointer ia_)
1532 {
1533   struct import_assistant *ia = ia_;
1534   struct substring field;
1535   size_t row;
1536   gint column;
1537
1538   column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
1539                                                "column-number"));
1540   row = text_import_model_iter_to_row (iter) + ia->first_line.skip_lines;
1541   field = ia->separators.columns[column].contents[row];
1542   if (field.string != NULL)
1543     {
1544       GValue text = {0, };
1545       g_value_init (&text, G_TYPE_STRING);
1546       g_value_take_string (&text, ss_xstrdup (field));
1547       g_object_set_property (G_OBJECT (cell), "text", &text);
1548       g_value_unset (&text);
1549       g_object_set (cell, "background-set", FALSE, (void *) NULL);
1550     }
1551   else
1552     g_object_set (cell,
1553                   "text", "",
1554                   "background", "red",
1555                   "background-set", TRUE,
1556                   (void *) NULL);
1557 }
1558
1559 /* Called to render a tooltip on one of the cells in the fields
1560    preview tree view. */
1561 static gboolean
1562 on_query_input_tooltip (GtkWidget *widget, gint wx, gint wy,
1563                         gboolean keyboard_mode UNUSED,
1564                         GtkTooltip *tooltip, struct import_assistant *ia)
1565 {
1566   size_t row, column;
1567
1568   if (!get_tooltip_location (widget, wx, wy, ia, &row, &column))
1569     return FALSE;
1570
1571   if (ia->separators.columns[column].contents[row].string != NULL)
1572     return FALSE;
1573
1574   gtk_tooltip_set_text (tooltip,
1575                         _("This input line has too few separators "
1576                           "to fill in this field."));
1577   return TRUE;
1578 }
1579 \f
1580 /* The "formats" page of the assistant. */
1581
1582 static void on_variable_change (PsppireDict *dict, int idx,
1583                                 struct import_assistant *);
1584 static void clear_modified_vars (struct import_assistant *);
1585
1586 /* Initializes IA's formats substructure. */
1587 static void
1588 init_formats_page (struct import_assistant *ia)
1589 {
1590   GtkBuilder *builder = ia->asst.builder;
1591   struct formats_page *p = &ia->formats;
1592
1593   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Formats"),
1594                                    GTK_ASSISTANT_PAGE_CONFIRM);
1595   p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "data"));
1596   p->modified_vars = NULL;
1597   p->modified_var_cnt = 0;
1598   p->dict = NULL;
1599 }
1600
1601 /* Frees IA's formats substructure. */
1602 static void
1603 destroy_formats_page (struct import_assistant *ia)
1604 {
1605   struct formats_page *p = &ia->formats;
1606
1607   if (p->psppire_dict != NULL)
1608     {
1609       /* This destroys p->dict also. */
1610       g_object_unref (p->psppire_dict);
1611     }
1612   clear_modified_vars (ia);
1613 }
1614
1615 /* Called just before the formats page of the assistant is
1616    displayed. */
1617 static void
1618 prepare_formats_page (struct import_assistant *ia)
1619 {
1620   struct dictionary *dict;
1621   PsppireDict *psppire_dict;
1622   PsppireVarStore *var_store;
1623   GtkBin *vars_scroller;
1624   GtkWidget *old_var_sheet;
1625   PsppireVarSheet *var_sheet;
1626   struct separators_page *s = &ia->separators;
1627   struct formats_page *p = &ia->formats;
1628   struct fmt_guesser *fg;
1629   unsigned long int number = 0;
1630   size_t column_idx;
1631
1632   push_watch_cursor (ia);
1633
1634   dict = dict_create (get_default_encoding ());
1635   fg = fmt_guesser_create ();
1636   for (column_idx = 0; column_idx < s->column_cnt; column_idx++)
1637     {
1638       struct variable *modified_var;
1639
1640       modified_var = (column_idx < p->modified_var_cnt
1641                       ? p->modified_vars[column_idx] : NULL);
1642       if (modified_var == NULL)
1643         {
1644           struct column *column = &s->columns[column_idx];
1645           struct variable *var;
1646           struct fmt_spec format;
1647           char *name;
1648           size_t row;
1649
1650           /* Choose variable name. */
1651           name = dict_make_unique_var_name (dict, column->name, &number);
1652
1653           /* Choose variable format. */
1654           fmt_guesser_clear (fg);
1655           for (row = ia->first_line.skip_lines; row < ia->file.line_cnt; row++)
1656             fmt_guesser_add (fg, column->contents[row]);
1657           fmt_guesser_guess (fg, &format);
1658           fmt_fix_input (&format);
1659
1660           /* Create variable. */
1661           var = dict_create_var_assert (dict, name, fmt_var_width (&format));
1662           var_set_both_formats (var, &format);
1663
1664           free (name);
1665         }
1666       else
1667         {
1668           char *name;
1669
1670           name = dict_make_unique_var_name (dict, var_get_name (modified_var),
1671                                             &number);
1672           dict_clone_var_as_assert (dict, modified_var, name);
1673           free (name);
1674         }
1675     }
1676   fmt_guesser_destroy (fg);
1677
1678   psppire_dict = psppire_dict_new_from_dict (dict);
1679   g_signal_connect (psppire_dict, "variable_changed",
1680                     G_CALLBACK (on_variable_change), ia);
1681   ia->formats.dict = dict;
1682   ia->formats.psppire_dict = psppire_dict;
1683
1684   /* XXX: PsppireVarStore doesn't hold a reference to
1685      psppire_dict for now, but it should.  After it does, we
1686      should g_object_ref the psppire_dict here, since we also
1687      hold a reference via ia->formats.dict. */
1688   var_store = psppire_var_store_new (psppire_dict);
1689   g_object_set (var_store,
1690                 "format-type", PSPPIRE_VAR_STORE_INPUT_FORMATS,
1691                 (void *) NULL);
1692   var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
1693   g_object_set (var_sheet,
1694                 "model", var_store,
1695                 "may-create-vars", FALSE,
1696                 (void *) NULL);
1697
1698   vars_scroller = GTK_BIN (get_widget_assert (ia->asst.builder, "vars-scroller"));
1699   old_var_sheet = gtk_bin_get_child (vars_scroller);
1700   if (old_var_sheet != NULL)
1701     gtk_widget_destroy (old_var_sheet);
1702   gtk_container_add (GTK_CONTAINER (vars_scroller), GTK_WIDGET (var_sheet));
1703   gtk_widget_show (GTK_WIDGET (var_sheet));
1704
1705   gtk_widget_destroy (GTK_WIDGET (ia->formats.data_tree_view));
1706   ia->formats.data_tree_view = create_data_tree_view (
1707     false,
1708     GTK_CONTAINER (get_widget_assert (ia->asst.builder, "data-scroller")),
1709     ia);
1710
1711   pop_watch_cursor (ia);
1712 }
1713
1714 /* Clears the set of user-modified variables from IA's formats
1715    substructure.  This discards user modifications to variable
1716    formats, thereby causing formats to revert to their
1717    defaults.  */
1718 static void
1719 clear_modified_vars (struct import_assistant *ia)
1720 {
1721   struct formats_page *p = &ia->formats;
1722   size_t i;
1723
1724   for (i = 0; i < p->modified_var_cnt; i++)
1725     var_destroy (p->modified_vars[i]);
1726   free (p->modified_vars);
1727   p->modified_vars = NULL;
1728   p->modified_var_cnt = 0;
1729 }
1730
1731 /* Resets the formats page to its defaults, discarding user
1732    modifications. */
1733 static void
1734 reset_formats_page (struct import_assistant *ia)
1735 {
1736   clear_modified_vars (ia);
1737   prepare_formats_page (ia);
1738 }
1739
1740 /* Called when the user changes one of the variables in the
1741    dictionary. */
1742 static void
1743 on_variable_change (PsppireDict *dict, int dict_idx,
1744                     struct import_assistant *ia)
1745 {
1746   struct formats_page *p = &ia->formats;
1747   GtkTreeView *tv = ia->formats.data_tree_view;
1748   gint column_idx = dict_idx + 1;
1749
1750   push_watch_cursor (ia);
1751
1752   /* Remove previous column and replace with new column. */
1753   gtk_tree_view_remove_column (tv, gtk_tree_view_get_column (tv, column_idx));
1754   gtk_tree_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx),
1755                                column_idx);
1756
1757   /* Save a copy of the modified variable in modified_vars, so
1758      that its attributes will be preserved if we back up to the
1759      previous page with the Prev button and then come back
1760      here. */
1761   if (dict_idx >= p->modified_var_cnt)
1762     {
1763       size_t i;
1764       p->modified_vars = xnrealloc (p->modified_vars, dict_idx + 1,
1765                                     sizeof *p->modified_vars);
1766       for (i = 0; i <= dict_idx; i++)
1767         p->modified_vars[i] = NULL;
1768       p->modified_var_cnt = dict_idx + 1;
1769     }
1770   if (p->modified_vars[dict_idx])
1771     var_destroy (p->modified_vars[dict_idx]);
1772   p->modified_vars[dict_idx]
1773     = var_clone (psppire_dict_get_variable (dict, dict_idx));
1774
1775   pop_watch_cursor (ia);
1776 }
1777
1778 /* Parses the contents of the field at (ROW,COLUMN) according to
1779    its variable format.  If OUTPUTP is non-null, then *OUTPUTP
1780    receives the formatted output for that field (which must be
1781    freed with free).  If TOOLTIPP is non-null, then *TOOLTIPP
1782    receives a message suitable for use in a tooltip, if one is
1783    needed, or a null pointer otherwise.  Returns true if a
1784    tooltip message is needed, otherwise false. */
1785 static bool
1786 parse_field (struct import_assistant *ia,
1787              size_t row, size_t column,
1788              char **outputp, char **tooltipp)
1789 {
1790   struct substring field;
1791   union value val;
1792   struct variable *var;
1793   const struct fmt_spec *in;
1794   struct fmt_spec out;
1795   char *tooltip;
1796   bool ok;
1797
1798   field = ia->separators.columns[column].contents[row];
1799   var = dict_get_var (ia->formats.dict, column);
1800   value_init (&val, var_get_width (var));
1801   in = var_get_print_format (var);
1802   out = fmt_for_output_from_input (in);
1803   tooltip = NULL;
1804   if (field.string != NULL)
1805     {
1806       char *error;
1807
1808       error = data_in (field, C_ENCODING, in->type, &val, var_get_width (var),
1809                        dict_get_encoding (ia->formats.dict));
1810       if (error != NULL)
1811         {
1812           tooltip = xasprintf (_("Cannot parse field content `%.*s' as "
1813                                  "format %s: %s"),
1814                                (int) field.length, field.string,
1815                                fmt_name (in->type), error);
1816           free (error);
1817         }
1818     }
1819   else
1820     {
1821       tooltip = xstrdup (_("This input line has too few separators "
1822                            "to fill in this field."));
1823       value_set_missing (&val, var_get_width (var));
1824     }
1825   if (outputp != NULL)
1826     {
1827       *outputp = data_out (&val, dict_get_encoding (ia->formats.dict),  &out);
1828     }
1829   value_destroy (&val, var_get_width (var));
1830
1831   ok = tooltip == NULL;
1832   if (tooltipp != NULL)
1833     *tooltipp = tooltip;
1834   else
1835     free (tooltip);
1836   return ok;
1837 }
1838
1839 /* Called to render one of the cells in the data preview tree
1840    view. */
1841 static void
1842 render_output_cell (GtkTreeViewColumn *tree_column,
1843                     GtkCellRenderer *cell,
1844                     GtkTreeModel *model,
1845                     GtkTreeIter *iter,
1846                     gpointer ia_)
1847 {
1848   struct import_assistant *ia = ia_;
1849   char *output;
1850   GValue gvalue = { 0, };
1851   bool ok;
1852
1853   ok = parse_field (ia,
1854                     (text_import_model_iter_to_row (iter)
1855                      + ia->first_line.skip_lines),
1856                     GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
1857                                                         "column-number")),
1858                     &output, NULL);
1859
1860   g_value_init (&gvalue, G_TYPE_STRING);
1861   g_value_take_string (&gvalue, output);
1862   g_object_set_property (G_OBJECT (cell), "text", &gvalue);
1863   g_value_unset (&gvalue);
1864
1865   if (ok)
1866     g_object_set (cell, "background-set", FALSE, (void *) NULL);
1867   else
1868     g_object_set (cell,
1869                   "background", "red",
1870                   "background-set", TRUE,
1871                   (void *) NULL);
1872 }
1873
1874 /* Called to render a tooltip for one of the cells in the data
1875    preview tree view. */
1876 static gboolean
1877 on_query_output_tooltip (GtkWidget *widget, gint wx, gint wy,
1878                         gboolean keyboard_mode UNUSED,
1879                         GtkTooltip *tooltip, struct import_assistant *ia)
1880 {
1881   size_t row, column;
1882   char *text;
1883
1884   if (!get_tooltip_location (widget, wx, wy, ia, &row, &column))
1885     return FALSE;
1886
1887   if (parse_field (ia, row, column, NULL, &text))
1888     return FALSE;
1889
1890   gtk_tooltip_set_text (tooltip, text);
1891   free (text);
1892   return TRUE;
1893 }
1894 \f
1895 /* Utility functions used by multiple pages of the assistant. */
1896
1897 static gboolean
1898 get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
1899                       const struct import_assistant *ia,
1900                       size_t *row, size_t *column)
1901 {
1902   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1903   gint bx, by;
1904   GtkTreePath *path;
1905   GtkTreeIter iter;
1906   GtkTreeViewColumn *tree_column;
1907   GtkTreeModel *tree_model;
1908   bool ok;
1909
1910   /* Check that WIDGET is really visible on the screen before we
1911      do anything else.  This is a bug fix for a sticky situation:
1912      when text_data_import_assistant() returns, it frees the data
1913      necessary to compose the tool tip message, but there may be
1914      a tool tip under preparation at that point (even if there is
1915      no visible tool tip) that will call back into us a little
1916      bit later.  Perhaps the correct solution to this problem is
1917      to make the data related to the tool tips part of a GObject
1918      that only gets destroyed when all references are released,
1919      but this solution appears to be effective too. */
1920   if (!gtk_widget_get_mapped (widget))
1921     return FALSE;
1922
1923   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
1924                                                      wx, wy, &bx, &by);
1925   if (!gtk_tree_view_get_path_at_pos (tree_view, bx, by,
1926                                       &path, &tree_column, NULL, NULL))
1927     return FALSE;
1928
1929   *column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
1930                                                 "column-number"));
1931
1932   tree_model = gtk_tree_view_get_model (tree_view);
1933   ok = gtk_tree_model_get_iter (tree_model, &iter, path);
1934   gtk_tree_path_free (path);
1935   if (!ok)
1936     return FALSE;
1937
1938   *row = text_import_model_iter_to_row (&iter) + ia->first_line.skip_lines;
1939   return TRUE;
1940 }
1941
1942 static void
1943 make_tree_view (const struct import_assistant *ia,
1944                 size_t first_line,
1945                 GtkTreeView **tree_view)
1946 {
1947   GtkTreeModel *model;
1948
1949   *tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
1950   model = GTK_TREE_MODEL (text_import_model_new (
1951                             ia->file.lines + first_line,
1952                             ia->file.line_cnt - first_line, first_line));
1953   gtk_tree_view_set_model (*tree_view, model);
1954
1955   add_line_number_column (ia, *tree_view);
1956 }
1957
1958 static void
1959 add_line_number_column (const struct import_assistant *ia,
1960                         GtkTreeView *treeview)
1961 {
1962   GtkTreeViewColumn *column;
1963
1964   column = gtk_tree_view_column_new_with_attributes (
1965                                                      _("Line"), ia->asst.prop_renderer,
1966     "text", TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER,
1967     (void *) NULL);
1968   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
1969   gtk_tree_view_column_set_fixed_width (
1970     column, get_monospace_width (treeview, ia->asst.prop_renderer, 5));
1971   gtk_tree_view_append_column (treeview, column);
1972 }
1973
1974 static gint
1975 get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
1976                      size_t char_cnt)
1977 {
1978   struct string s;
1979   gint width;
1980
1981   ds_init_empty (&s);
1982   ds_put_byte_multiple (&s, '0', char_cnt);
1983   ds_put_byte (&s, ' ');
1984   width = get_string_width (treeview, renderer, ds_cstr (&s));
1985   ds_destroy (&s);
1986
1987   return width;
1988 }
1989
1990 static gint
1991 get_string_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
1992                   const char *string)
1993 {
1994   gint width;
1995   g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
1996   gtk_cell_renderer_get_size (renderer, GTK_WIDGET (treeview),
1997                               NULL, NULL, NULL, &width, NULL);
1998   return width;
1999 }
2000
2001 static GtkTreeViewColumn *
2002 make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
2003                   bool input, gint dict_idx)
2004 {
2005   struct variable *var = NULL;
2006   struct column *column = NULL;
2007   size_t char_cnt;
2008   gint content_width, header_width;
2009   GtkTreeViewColumn *tree_column;
2010   char *name;
2011
2012   if (input)
2013     column = &ia->separators.columns[dict_idx];
2014   else
2015     var = dict_get_var (ia->formats.dict, dict_idx);
2016
2017   name = escape_underscores (input ? column->name : var_get_name (var));
2018   char_cnt = input ? column->width : var_get_print_format (var)->w;
2019   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
2020                                        char_cnt);
2021   header_width = get_string_width (tree_view, ia->asst.prop_renderer,
2022                                    name);
2023
2024   tree_column = gtk_tree_view_column_new ();
2025   g_object_set_data (G_OBJECT (tree_column), "column-number",
2026                      GINT_TO_POINTER (dict_idx));
2027   gtk_tree_view_column_set_title (tree_column, name);
2028   gtk_tree_view_column_pack_start (tree_column, ia->asst.fixed_renderer,
2029                                    FALSE);
2030   gtk_tree_view_column_set_cell_data_func (
2031     tree_column, ia->asst.fixed_renderer,
2032     input ? render_input_cell : render_output_cell, ia, NULL);
2033   gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_FIXED);
2034   gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
2035                                                           header_width));
2036
2037   free (name);
2038
2039   return tree_column;
2040 }
2041
2042 static GtkTreeView *
2043 create_data_tree_view (bool input, GtkContainer *parent,
2044                        struct import_assistant *ia)
2045 {
2046   GtkTreeView *tree_view;
2047   gint i;
2048
2049   make_tree_view (ia, ia->first_line.skip_lines, &tree_view);
2050   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view),
2051                                GTK_SELECTION_NONE);
2052
2053   for (i = 0; i < ia->separators.column_cnt; i++)
2054     gtk_tree_view_append_column (tree_view,
2055                                  make_data_column (ia, tree_view, input, i));
2056
2057   g_object_set (G_OBJECT (tree_view), "has-tooltip", TRUE, (void *) NULL);
2058   g_signal_connect (tree_view, "query-tooltip",
2059                     G_CALLBACK (input ? on_query_input_tooltip
2060                                 : on_query_output_tooltip), ia);
2061   gtk_tree_view_set_fixed_height_mode (tree_view, true);
2062
2063   gtk_container_add (parent, GTK_WIDGET (tree_view));
2064   gtk_widget_show (GTK_WIDGET (tree_view));
2065
2066   return tree_view;
2067 }
2068
2069 static char *
2070 escape_underscores (const char *in)
2071 {
2072   char *out = xmalloc (2 * strlen (in) + 1);
2073   char *p;
2074
2075   p = out;
2076   for (; *in != '\0'; in++)
2077     {
2078       if (*in == '_')
2079         *p++ = '_';
2080       *p++ = *in;
2081     }
2082   *p = '\0';
2083
2084   return out;
2085 }
2086 \f
2087 /* TextImportModel, a GtkTreeModel implementation used by some
2088    pages of the assistant. */
2089
2090 #define G_TYPE_TEXT_IMPORT_MODEL (text_import_model_get_type ())
2091 #define TEXT_IMPORT_MODEL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_TEXT_IMPORT_MODEL, TextImportModel))
2092 #define TEXT_IMPORT_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_TEXT_IMPORT_MODEL, TextImportModelClass))
2093 #define IS_TEXT_IMPORT_MODEL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_TEXT_IMPORT_MODEL))
2094 #define IS_TEXT_IMPORT_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_TEXT_IMPORT_MODEL))
2095 #define TEXT_IMPORT_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_TEXT_IMPORT_MODEL, TextImportModelClass))
2096
2097 /* Random number used in 'stamp' member of GtkTreeIter. */
2098 #define TREE_MODEL_STAMP 0x7efd67d3
2099
2100 struct TextImportModel
2101 {
2102   GObject             parent;
2103   struct string *lines;
2104   size_t line_cnt;
2105   size_t first_line;
2106 };
2107
2108 struct TextImportModelClass
2109 {
2110   GObjectClass parent_class;
2111 };
2112
2113 GType text_import_model_get_type (void);
2114 static void text_import_model_tree_model_init (gpointer iface, gpointer data);
2115
2116 GType
2117 text_import_model_get_type (void)
2118 {
2119   static GType object_type = 0;
2120
2121   if (!object_type)
2122     {
2123       static const GTypeInfo object_info = {
2124         sizeof (TextImportModelClass),
2125         (GBaseInitFunc) NULL,
2126         (GBaseFinalizeFunc) NULL,
2127         NULL,   /* class_init */
2128         NULL,   /* class_finalize */
2129         NULL,   /* class_data */
2130         sizeof (TextImportModel),
2131         0,      /* n_preallocs */
2132         NULL,   /* instance_init */
2133       };
2134
2135       static const GInterfaceInfo tree_model_info = {
2136         text_import_model_tree_model_init,
2137         NULL,
2138         NULL
2139       };
2140
2141       object_type = g_type_register_static (G_TYPE_OBJECT,
2142                                             "TextImportModel",
2143                                             &object_info, 0);
2144
2145       g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
2146                                    &tree_model_info);
2147
2148
2149     }
2150
2151   return object_type;
2152 }
2153
2154
2155 /* Creates and returns a new TextImportModel that contains the
2156    LINE_CNT lines in LINES.  The lines before FIRST_LINE in LINES
2157    are not part of the model, but they are included in the line
2158    numbers in the TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER column.
2159
2160    The caller retains responsibility for freeing LINES and must
2161    ensure that its lifetime and that of the strings that it
2162    contains exceeds that of the TextImportModel. */
2163 TextImportModel *
2164 text_import_model_new (struct string *lines, size_t line_cnt,
2165                        size_t first_line)
2166 {
2167   TextImportModel *new_text_import_model
2168     = g_object_new (G_TYPE_TEXT_IMPORT_MODEL, NULL);
2169   new_text_import_model->lines = lines;
2170   new_text_import_model->line_cnt = line_cnt;
2171   new_text_import_model->first_line = first_line;
2172   return new_text_import_model;
2173 }
2174
2175
2176 static gboolean
2177 tree_model_iter_has_child  (GtkTreeModel *tree_model,
2178                             GtkTreeIter  *iter)
2179 {
2180   return FALSE;
2181 }
2182
2183 static gboolean
2184 tree_model_iter_parent (GtkTreeModel *tree_model,
2185                         GtkTreeIter *iter,
2186                         GtkTreeIter *child)
2187 {
2188   return TRUE;
2189 }
2190
2191 static GtkTreeModelFlags
2192 tree_model_get_flags (GtkTreeModel *model)
2193 {
2194   g_return_val_if_fail (IS_TEXT_IMPORT_MODEL (model), (GtkTreeModelFlags) 0);
2195
2196   return GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST;
2197 }
2198
2199
2200 static gint
2201 tree_model_n_columns (GtkTreeModel *model)
2202 {
2203   return 2;
2204 }
2205
2206 static GType
2207 tree_model_column_type (GtkTreeModel *model, gint index)
2208 {
2209   return (index == TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER ? G_TYPE_INT
2210           : index == TEXT_IMPORT_MODEL_COLUMN_LINE ? G_TYPE_STRING
2211           : -1);
2212 }
2213
2214 static gboolean
2215 init_iter (TextImportModel *list, gint idx, GtkTreeIter *iter)
2216 {
2217   if (idx < 0 || idx >= list->line_cnt)
2218     {
2219       iter->stamp = 0;
2220       iter->user_data = GINT_TO_POINTER (-1);
2221       return FALSE;
2222     }
2223   else
2224     {
2225       iter->stamp = TREE_MODEL_STAMP;
2226       iter->user_data = GINT_TO_POINTER (idx);
2227       return TRUE;
2228     }
2229 }
2230
2231 static gboolean
2232 tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
2233 {
2234   gint *indices, depth;
2235
2236   TextImportModel *list = TEXT_IMPORT_MODEL (model);
2237
2238   g_return_val_if_fail (path, FALSE);
2239
2240   indices = gtk_tree_path_get_indices (path);
2241   depth = gtk_tree_path_get_depth (path);
2242
2243   g_return_val_if_fail (depth == 1, FALSE);
2244
2245   return init_iter (list, indices[0], iter);
2246 }
2247
2248
2249 static gboolean
2250 tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
2251 {
2252   TextImportModel *list = TEXT_IMPORT_MODEL (model);
2253   gint idx;
2254
2255   assert (iter->stamp == TREE_MODEL_STAMP);
2256
2257   idx = GPOINTER_TO_INT (iter->user_data);
2258   return init_iter (list, idx == -1 ? -1 : idx + 1, iter);
2259 }
2260
2261 static GtkTreePath *
2262 tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
2263 {
2264   GtkTreePath *path;
2265
2266   g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE);
2267
2268   path = gtk_tree_path_new ();
2269   gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data));
2270
2271   return path;
2272 }
2273
2274 static void
2275 tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
2276                       gint column, GValue *value)
2277 {
2278   TextImportModel *list = TEXT_IMPORT_MODEL (model);
2279   gint idx;
2280
2281   g_return_if_fail (iter->stamp == TREE_MODEL_STAMP);
2282
2283   idx = GPOINTER_TO_INT (iter->user_data);
2284   assert (idx >= 0 && idx < list->line_cnt);
2285
2286   if (column == 0)
2287     {
2288       g_value_init (value, G_TYPE_INT);
2289       g_value_set_int (value, idx + list->first_line + 1);
2290     }
2291   else
2292     {
2293       g_value_init (value, G_TYPE_STRING);
2294       g_value_set_static_string (value, ds_cstr (&list->lines[idx]));
2295     }
2296 }
2297
2298 static gboolean
2299 tree_model_iter_children (GtkTreeModel *tree_model,
2300                           GtkTreeIter *iter,
2301                           GtkTreeIter *parent)
2302 {
2303   return FALSE;
2304 }
2305
2306 static gint
2307 tree_model_n_children (GtkTreeModel *model, GtkTreeIter  *iter)
2308 {
2309   TextImportModel *list = TEXT_IMPORT_MODEL (model);
2310
2311   return iter == NULL ? list->line_cnt : 0;
2312 }
2313
2314 static gboolean
2315 tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
2316                       GtkTreeIter *parent, gint n)
2317 {
2318   TextImportModel *list = TEXT_IMPORT_MODEL (model);
2319   g_return_val_if_fail (IS_TEXT_IMPORT_MODEL (model), FALSE);
2320
2321   if (parent)
2322     return FALSE;
2323   return init_iter (list, n, iter);
2324 }
2325
2326 static void
2327 text_import_model_tree_model_init (gpointer iface_, gpointer data UNUSED)
2328 {
2329   GtkTreeModelIface *iface = (GtkTreeModelIface *) iface_;
2330
2331   iface->get_flags = tree_model_get_flags;
2332   iface->get_n_columns = tree_model_n_columns;
2333   iface->get_column_type = tree_model_column_type;
2334   iface->get_iter = tree_model_get_iter;
2335   iface->iter_next = tree_model_iter_next;
2336   iface->get_path = tree_model_get_path;
2337   iface->get_value = tree_model_get_value;
2338
2339   iface->iter_children = tree_model_iter_children;
2340   iface->iter_has_child = tree_model_iter_has_child;
2341   iface->iter_n_children = tree_model_n_children;
2342   iface->iter_nth_child = tree_model_nth_child;
2343   iface->iter_parent = tree_model_iter_parent;
2344 }
2345
2346 gint
2347 text_import_model_iter_to_row (const GtkTreeIter *iter)
2348 {
2349   assert (iter->stamp == TREE_MODEL_STAMP);
2350   return GPOINTER_TO_INT (iter->user_data);
2351 }
2352
2353 /* Increments the "watch cursor" level, setting the cursor for
2354    the assistant window to a watch face to indicate to the user
2355    that the ongoing operation may take some time. */
2356 static void
2357 push_watch_cursor (struct import_assistant *ia)
2358 {
2359   if (++ia->asst.watch_cursor == 1)
2360     {
2361       GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
2362       GdkDisplay *display = gtk_widget_get_display (widget);
2363       GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
2364       gdk_window_set_cursor (widget->window, cursor);
2365       gdk_cursor_unref (cursor);
2366       gdk_display_flush (display);
2367     }
2368 }
2369
2370 /* Decrements the "watch cursor" level.  If the level reaches
2371    zero, the cursor is reset to its default shape. */
2372 static void
2373 pop_watch_cursor (struct import_assistant *ia)
2374 {
2375   if (--ia->asst.watch_cursor == 0)
2376     {
2377       GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
2378       gdk_window_set_cursor (widget->window, NULL);
2379     }
2380 }