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