helper: Move escape_underscores() here.
[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
1081   gtk_combo_box_entry_set_text_column (cb, 0);
1082 }
1083
1084 /* Initializes IA's separators substructure. */
1085 static void
1086 init_separators_page (struct import_assistant *ia)
1087 {
1088   GtkBuilder *builder = ia->asst.builder;
1089   struct separators_page *p = &ia->separators;
1090   size_t i;
1091
1092   choose_likely_separators (ia);
1093
1094   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Separators"),
1095                                    GTK_ASSISTANT_PAGE_CONTENT);
1096   p->custom_cb = get_widget_assert (builder, "custom-cb");
1097   p->custom_entry = get_widget_assert (builder, "custom-entry");
1098   p->quote_combo = get_widget_assert (builder, "quote-combo");
1099   p->quote_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (p->quote_combo)));
1100   p->quote_cb = get_widget_assert (builder, "quote-cb");
1101   p->escape_cb = get_widget_assert (builder, "escape");
1102
1103   set_separators (ia);
1104   set_quote_list (GTK_COMBO_BOX_ENTRY (p->quote_combo));
1105   p->fields_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "fields"));
1106   g_signal_connect (p->quote_combo, "changed",
1107                     G_CALLBACK (on_quote_combo_change), ia);
1108   g_signal_connect (p->quote_cb, "toggled",
1109                     G_CALLBACK (on_quote_cb_toggle), ia);
1110   g_signal_connect (p->custom_entry, "notify::text",
1111                     G_CALLBACK (on_separators_custom_entry_notify), ia);
1112   g_signal_connect (p->custom_cb, "toggled",
1113                     G_CALLBACK (on_separators_custom_cb_toggle), ia);
1114   for (i = 0; i < SEPARATOR_CNT; i++)
1115     g_signal_connect (get_widget_assert (builder, separators[i].name),
1116                       "toggled", G_CALLBACK (on_separator_toggle), ia);
1117   g_signal_connect (p->escape_cb, "toggled",
1118                     G_CALLBACK (on_separator_toggle), ia);
1119 }
1120
1121 /* Frees IA's separators substructure. */
1122 static void
1123 destroy_separators_page (struct import_assistant *ia)
1124 {
1125   struct separators_page *s = &ia->separators;
1126
1127   ds_destroy (&s->separators);
1128   ds_destroy (&s->quotes);
1129   clear_fields (ia);
1130 }
1131
1132 /* Called just before the separators page becomes visible in the
1133    assistant. */
1134 static void
1135 prepare_separators_page (struct import_assistant *ia)
1136 {
1137   revise_fields_preview (ia);
1138 }
1139
1140 /* Called when the Reset button is clicked on the separators
1141    page, resets the separators to the defaults. */
1142 static void
1143 reset_separators_page (struct import_assistant *ia)
1144 {
1145   choose_likely_separators (ia);
1146   set_separators (ia);
1147 }
1148
1149 /* Frees and clears the column data in IA's separators
1150    substructure. */
1151 static void
1152 clear_fields (struct import_assistant *ia)
1153 {
1154   struct separators_page *s = &ia->separators;
1155
1156   if (s->column_cnt > 0)
1157     {
1158       struct column *col;
1159       size_t row;
1160
1161       for (row = 0; row < ia->file.line_cnt; row++)
1162         {
1163           const struct string *line = &ia->file.lines[row];
1164           const char *line_start = ds_data (line);
1165           const char *line_end = ds_end (line);
1166
1167           for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
1168             {
1169               char *s = ss_data (col->contents[row]);
1170               if (!(s >= line_start && s <= line_end))
1171                 ss_dealloc (&col->contents[row]);
1172             }
1173         }
1174
1175       for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
1176         {
1177           free (col->name);
1178           free (col->contents);
1179         }
1180
1181       free (s->columns);
1182       s->columns = NULL;
1183       s->column_cnt = 0;
1184     }
1185 }
1186
1187 /* Breaks the file data in IA into columns based on the
1188    separators set in IA's separators substructure. */
1189 static void
1190 split_fields (struct import_assistant *ia)
1191 {
1192   struct separators_page *s = &ia->separators;
1193   size_t columns_allocated;
1194   bool space_sep;
1195   size_t row;
1196
1197   clear_fields (ia);
1198
1199   /* Is space in the set of separators? */
1200   space_sep = ss_find_byte (ds_ss (&s->separators), ' ') != SIZE_MAX;
1201
1202   /* Split all the lines, not just those from
1203      ia->first_line.skip_lines on, so that we split the line that
1204      contains variables names if ia->first_line.variable_names is
1205      true. */
1206   columns_allocated = 0;
1207   for (row = 0; row < ia->file.line_cnt; row++)
1208     {
1209       struct string *line = &ia->file.lines[row];
1210       struct substring text = ds_ss (line);
1211       size_t column_idx;
1212
1213       for (column_idx = 0; ; column_idx++)
1214         {
1215           struct substring field;
1216           struct column *column;
1217
1218           if (space_sep)
1219             ss_ltrim (&text, ss_cstr (" "));
1220           if (ss_is_empty (text))
1221             {
1222               if (column_idx != 0)
1223                 break;
1224               field = text;
1225             }
1226           else if (!ds_is_empty (&s->quotes)
1227                    && ds_find_byte (&s->quotes, text.string[0]) != SIZE_MAX)
1228             {
1229               int quote = ss_get_byte (&text);
1230               if (!s->escape)
1231                 ss_get_until (&text, quote, &field);
1232               else
1233                 {
1234                   struct string s;
1235                   int c;
1236
1237                   ds_init_empty (&s);
1238                   while ((c = ss_get_byte (&text)) != EOF)
1239                     if (c != quote)
1240                       ds_put_byte (&s, c);
1241                     else if (ss_match_byte (&text, quote))
1242                       ds_put_byte (&s, quote);
1243                     else
1244                       break;
1245                   field = ds_ss (&s);
1246                 }
1247             }
1248           else
1249             ss_get_bytes (&text, ss_cspan (text, ds_ss (&s->separators)),
1250                           &field);
1251
1252           if (column_idx >= s->column_cnt)
1253             {
1254               struct column *column;
1255
1256               if (s->column_cnt >= columns_allocated)
1257                 s->columns = x2nrealloc (s->columns, &columns_allocated,
1258                                          sizeof *s->columns);
1259               column = &s->columns[s->column_cnt++];
1260               column->name = NULL;
1261               column->width = 0;
1262               column->contents = xcalloc (ia->file.line_cnt,
1263                                           sizeof *column->contents);
1264             }
1265           column = &s->columns[column_idx];
1266           column->contents[row] = field;
1267           if (ss_length (field) > column->width)
1268             column->width = ss_length (field);
1269
1270           if (space_sep)
1271             ss_ltrim (&text, ss_cstr (" "));
1272           if (ss_is_empty (text))
1273             break;
1274           if (ss_find_byte (ds_ss (&s->separators), ss_first (text))
1275               != SIZE_MAX)
1276             ss_advance (&text, 1);
1277         }
1278     }
1279 }
1280
1281 /* Chooses a name for each column on the separators page */
1282 static void
1283 choose_column_names (struct import_assistant *ia)
1284 {
1285   const struct first_line_page *f = &ia->first_line;
1286   struct separators_page *s = &ia->separators;
1287   struct dictionary *dict;
1288   unsigned long int generated_name_count = 0;
1289   struct column *col;
1290   size_t name_row;
1291
1292   dict = dict_create (get_default_encoding ());
1293   name_row = f->variable_names && f->skip_lines ? f->skip_lines : 0;
1294   for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
1295     {
1296       char *hint, *name;
1297
1298       hint = name_row ? ss_xstrdup (col->contents[name_row - 1]) : NULL;
1299       name = dict_make_unique_var_name (dict, hint, &generated_name_count);
1300       free (hint);
1301
1302       col->name = name;
1303       dict_create_var_assert (dict, name, 0);
1304     }
1305   dict_destroy (dict);
1306 }
1307
1308 /* Picks the most likely separator and quote characters based on
1309    IA's file data. */
1310 static void
1311 choose_likely_separators (struct import_assistant *ia)
1312 {
1313   unsigned long int histogram[UCHAR_MAX + 1] = { 0 };
1314   size_t row;
1315
1316   /* Construct a histogram of all the characters used in the
1317      file. */
1318   for (row = 0; row < ia->file.line_cnt; row++)
1319     {
1320       struct substring line = ds_ss (&ia->file.lines[row]);
1321       size_t length = ss_length (line);
1322       size_t i;
1323       for (i = 0; i < length; i++)
1324         histogram[(unsigned char) line.string[i]]++;
1325     }
1326
1327   find_commonest_chars (histogram, "\"'", "", &ia->separators.quotes);
1328   find_commonest_chars (histogram, ",;:/|!\t-", ",",
1329                         &ia->separators.separators);
1330   ia->separators.escape = true;
1331 }
1332
1333 /* Chooses the most common character among those in TARGETS,
1334    based on the frequency data in HISTOGRAM, and stores it in
1335    RESULT.  If there is a tie for the most common character among
1336    those in TARGETS, the earliest character is chosen.  If none
1337    of the TARGETS appear at all, then DEF is used as a
1338    fallback. */
1339 static void
1340 find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
1341                       const char *targets, const char *def,
1342                       struct string *result)
1343 {
1344   unsigned char max = 0;
1345   unsigned long int max_count = 0;
1346
1347   for (; *targets != '\0'; targets++)
1348     {
1349       unsigned char c = *targets;
1350       unsigned long int count = histogram[c];
1351       if (count > max_count)
1352         {
1353           max = c;
1354           max_count = count;
1355         }
1356     }
1357   if (max_count > 0)
1358     {
1359       ds_clear (result);
1360       ds_put_byte (result, max);
1361     }
1362   else
1363     ds_assign_cstr (result, def);
1364 }
1365
1366 /* Revises the contents of the fields tree view based on the
1367    currently chosen set of separators. */
1368 static void
1369 revise_fields_preview (struct import_assistant *ia)
1370 {
1371   GtkWidget *w;
1372
1373   push_watch_cursor (ia);
1374
1375   w = GTK_WIDGET (ia->separators.fields_tree_view);
1376   gtk_widget_destroy (w);
1377   get_separators (ia);
1378   split_fields (ia);
1379   choose_column_names (ia);
1380   ia->separators.fields_tree_view = create_data_tree_view (
1381     true,
1382     GTK_CONTAINER (get_widget_assert (ia->asst.builder, "fields-scroller")),
1383     ia);
1384
1385   pop_watch_cursor (ia);
1386 }
1387
1388 /* Sets the widgets to match IA's separators substructure. */
1389 static void
1390 set_separators (struct import_assistant *ia)
1391 {
1392   struct separators_page *s = &ia->separators;
1393   unsigned int seps;
1394   struct string custom;
1395   bool any_custom;
1396   bool any_quotes;
1397   size_t i;
1398
1399   ds_init_empty (&custom);
1400   seps = 0;
1401   for (i = 0; i < ds_length (&s->separators); i++)
1402     {
1403       unsigned char c = ds_at (&s->separators, i);
1404       int j;
1405
1406       for (j = 0; j < SEPARATOR_CNT; j++)
1407         {
1408           const struct separator *s = &separators[j];
1409           if (s->c == c)
1410             {
1411               seps += 1u << j;
1412               goto next;
1413             }
1414         }
1415
1416       ds_put_byte (&custom, c);
1417     next:;
1418     }
1419
1420   for (i = 0; i < SEPARATOR_CNT; i++)
1421     {
1422       const struct separator *s = &separators[i];
1423       GtkWidget *button = get_widget_assert (ia->asst.builder, s->name);
1424       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
1425                                     (seps & (1u << i)) != 0);
1426     }
1427   any_custom = !ds_is_empty (&custom);
1428   gtk_entry_set_text (GTK_ENTRY (s->custom_entry), ds_cstr (&custom));
1429   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->custom_cb),
1430                                 any_custom);
1431   gtk_widget_set_sensitive (s->custom_entry, any_custom);
1432   ds_destroy (&custom);
1433
1434   any_quotes = !ds_is_empty (&s->quotes);
1435
1436   gtk_entry_set_text (s->quote_entry,
1437                       any_quotes ? ds_cstr (&s->quotes) : "\"");
1438   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->quote_cb),
1439                                 any_quotes);
1440   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->escape_cb),
1441                                 s->escape);
1442   gtk_widget_set_sensitive (s->quote_combo, any_quotes);
1443   gtk_widget_set_sensitive (s->escape_cb, any_quotes);
1444 }
1445
1446 /* Sets IA's separators substructure to match the widgets. */
1447 static void
1448 get_separators (struct import_assistant *ia)
1449 {
1450   struct separators_page *s = &ia->separators;
1451   int i;
1452
1453   ds_clear (&s->separators);
1454   for (i = 0; i < SEPARATOR_CNT; i++)
1455     {
1456       const struct separator *sep = &separators[i];
1457       GtkWidget *button = get_widget_assert (ia->asst.builder, sep->name);
1458       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
1459         ds_put_byte (&s->separators, sep->c);
1460     }
1461
1462   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->custom_cb)))
1463     ds_put_cstr (&s->separators,
1464                  gtk_entry_get_text (GTK_ENTRY (s->custom_entry)));
1465
1466   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->quote_cb)))
1467     {
1468       gchar *text = gtk_combo_box_get_active_text (
1469                       GTK_COMBO_BOX (s->quote_combo));
1470       ds_assign_cstr (&s->quotes, text);
1471       g_free (text);
1472     }
1473   else
1474     ds_clear (&s->quotes);
1475   s->escape = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->escape_cb));
1476 }
1477
1478 /* Called when the user changes the entry field for custom
1479    separators. */
1480 static void
1481 on_separators_custom_entry_notify (GObject *gobject UNUSED,
1482                                    GParamSpec *arg1 UNUSED,
1483                                    struct import_assistant *ia)
1484 {
1485   revise_fields_preview (ia);
1486 }
1487
1488 /* Called when the user toggles the checkbox that enables custom
1489    separators. */
1490 static void
1491 on_separators_custom_cb_toggle (GtkToggleButton *custom_cb,
1492                                 struct import_assistant *ia)
1493 {
1494   bool is_active = gtk_toggle_button_get_active (custom_cb);
1495   gtk_widget_set_sensitive (ia->separators.custom_entry, is_active);
1496   revise_fields_preview (ia);
1497 }
1498
1499 /* Called when the user changes the selection in the combo box
1500    that selects a quote character. */
1501 static void
1502 on_quote_combo_change (GtkComboBox *combo, struct import_assistant *ia)
1503 {
1504   revise_fields_preview (ia);
1505 }
1506
1507 /* Called when the user toggles the checkbox that enables
1508    quoting. */
1509 static void
1510 on_quote_cb_toggle (GtkToggleButton *quote_cb, struct import_assistant *ia)
1511 {
1512   bool is_active = gtk_toggle_button_get_active (quote_cb);
1513   gtk_widget_set_sensitive (ia->separators.quote_combo, is_active);
1514   gtk_widget_set_sensitive (ia->separators.escape_cb, is_active);
1515   revise_fields_preview (ia);
1516 }
1517
1518 /* Called when the user toggles one of the separators
1519    checkboxes. */
1520 static void
1521 on_separator_toggle (GtkToggleButton *toggle UNUSED,
1522                      struct import_assistant *ia)
1523 {
1524   revise_fields_preview (ia);
1525 }
1526
1527 /* Called to render one of the cells in the fields preview tree
1528    view. */
1529 static void
1530 render_input_cell (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1531                    GtkTreeModel *model, GtkTreeIter *iter,
1532                    gpointer ia_)
1533 {
1534   struct import_assistant *ia = ia_;
1535   struct substring field;
1536   size_t row;
1537   gint column;
1538
1539   column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
1540                                                "column-number"));
1541   row = empty_list_store_iter_to_row (iter) + ia->first_line.skip_lines;
1542   field = ia->separators.columns[column].contents[row];
1543   if (field.string != NULL)
1544     {
1545       GValue text = {0, };
1546       g_value_init (&text, G_TYPE_STRING);
1547       g_value_take_string (&text, ss_xstrdup (field));
1548       g_object_set_property (G_OBJECT (cell), "text", &text);
1549       g_value_unset (&text);
1550       g_object_set (cell, "background-set", FALSE, (void *) NULL);
1551     }
1552   else
1553     g_object_set (cell,
1554                   "text", "",
1555                   "background", "red",
1556                   "background-set", TRUE,
1557                   (void *) NULL);
1558 }
1559
1560 /* Called to render a tooltip on one of the cells in the fields
1561    preview tree view. */
1562 static gboolean
1563 on_query_input_tooltip (GtkWidget *widget, gint wx, gint wy,
1564                         gboolean keyboard_mode UNUSED,
1565                         GtkTooltip *tooltip, struct import_assistant *ia)
1566 {
1567   size_t row, column;
1568
1569   if (!get_tooltip_location (widget, wx, wy, ia, &row, &column))
1570     return FALSE;
1571
1572   if (ia->separators.columns[column].contents[row].string != NULL)
1573     return FALSE;
1574
1575   gtk_tooltip_set_text (tooltip,
1576                         _("This input line has too few separators "
1577                           "to fill in this field."));
1578   return TRUE;
1579 }
1580 \f
1581 /* The "formats" page of the assistant. */
1582
1583 static void on_variable_change (PsppireDict *dict, int idx,
1584                                 struct import_assistant *);
1585 static void clear_modified_vars (struct import_assistant *);
1586
1587 /* Initializes IA's formats substructure. */
1588 static void
1589 init_formats_page (struct import_assistant *ia)
1590 {
1591   GtkBuilder *builder = ia->asst.builder;
1592   struct formats_page *p = &ia->formats;
1593
1594   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Formats"),
1595                                    GTK_ASSISTANT_PAGE_CONFIRM);
1596   p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "data"));
1597   p->modified_vars = NULL;
1598   p->modified_var_cnt = 0;
1599   p->dict = NULL;
1600 }
1601
1602 /* Frees IA's formats substructure. */
1603 static void
1604 destroy_formats_page (struct import_assistant *ia)
1605 {
1606   struct formats_page *p = &ia->formats;
1607
1608   if (p->psppire_dict != NULL)
1609     {
1610       /* This destroys p->dict also. */
1611       g_object_unref (p->psppire_dict);
1612     }
1613   clear_modified_vars (ia);
1614 }
1615
1616 /* Called just before the formats page of the assistant is
1617    displayed. */
1618 static void
1619 prepare_formats_page (struct import_assistant *ia)
1620 {
1621   struct dictionary *dict;
1622   PsppireDict *psppire_dict;
1623   PsppireVarStore *var_store;
1624   GtkBin *vars_scroller;
1625   GtkWidget *old_var_sheet;
1626   PsppireVarSheet *var_sheet;
1627   struct separators_page *s = &ia->separators;
1628   struct formats_page *p = &ia->formats;
1629   struct fmt_guesser *fg;
1630   unsigned long int number = 0;
1631   size_t column_idx;
1632
1633   push_watch_cursor (ia);
1634
1635   dict = dict_create (get_default_encoding ());
1636   fg = fmt_guesser_create ();
1637   for (column_idx = 0; column_idx < s->column_cnt; column_idx++)
1638     {
1639       struct variable *modified_var;
1640
1641       modified_var = (column_idx < p->modified_var_cnt
1642                       ? p->modified_vars[column_idx] : NULL);
1643       if (modified_var == NULL)
1644         {
1645           struct column *column = &s->columns[column_idx];
1646           struct variable *var;
1647           struct fmt_spec format;
1648           char *name;
1649           size_t row;
1650
1651           /* Choose variable name. */
1652           name = dict_make_unique_var_name (dict, column->name, &number);
1653
1654           /* Choose variable format. */
1655           fmt_guesser_clear (fg);
1656           for (row = ia->first_line.skip_lines; row < ia->file.line_cnt; row++)
1657             fmt_guesser_add (fg, column->contents[row]);
1658           fmt_guesser_guess (fg, &format);
1659           fmt_fix_input (&format);
1660
1661           /* Create variable. */
1662           var = dict_create_var_assert (dict, name, fmt_var_width (&format));
1663           var_set_both_formats (var, &format);
1664
1665           free (name);
1666         }
1667       else
1668         {
1669           char *name;
1670
1671           name = dict_make_unique_var_name (dict, var_get_name (modified_var),
1672                                             &number);
1673           dict_clone_var_as_assert (dict, modified_var, name);
1674           free (name);
1675         }
1676     }
1677   fmt_guesser_destroy (fg);
1678
1679   psppire_dict = psppire_dict_new_from_dict (dict);
1680   g_signal_connect (psppire_dict, "variable_changed",
1681                     G_CALLBACK (on_variable_change), ia);
1682   ia->formats.dict = dict;
1683   ia->formats.psppire_dict = psppire_dict;
1684
1685   /* XXX: PsppireVarStore doesn't hold a reference to
1686      psppire_dict for now, but it should.  After it does, we
1687      should g_object_ref the psppire_dict here, since we also
1688      hold a reference via ia->formats.dict. */
1689   var_store = psppire_var_store_new (psppire_dict);
1690   g_object_set (var_store,
1691                 "format-type", PSPPIRE_VAR_STORE_INPUT_FORMATS,
1692                 (void *) NULL);
1693   var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
1694   g_object_set (var_sheet,
1695                 "model", var_store,
1696                 "may-create-vars", FALSE,
1697                 (void *) NULL);
1698
1699   vars_scroller = GTK_BIN (get_widget_assert (ia->asst.builder, "vars-scroller"));
1700   old_var_sheet = gtk_bin_get_child (vars_scroller);
1701   if (old_var_sheet != NULL)
1702     gtk_widget_destroy (old_var_sheet);
1703   gtk_container_add (GTK_CONTAINER (vars_scroller), GTK_WIDGET (var_sheet));
1704   gtk_widget_show (GTK_WIDGET (var_sheet));
1705
1706   gtk_widget_destroy (GTK_WIDGET (ia->formats.data_tree_view));
1707   ia->formats.data_tree_view = create_data_tree_view (
1708     false,
1709     GTK_CONTAINER (get_widget_assert (ia->asst.builder, "data-scroller")),
1710     ia);
1711
1712   pop_watch_cursor (ia);
1713 }
1714
1715 /* Clears the set of user-modified variables from IA's formats
1716    substructure.  This discards user modifications to variable
1717    formats, thereby causing formats to revert to their
1718    defaults.  */
1719 static void
1720 clear_modified_vars (struct import_assistant *ia)
1721 {
1722   struct formats_page *p = &ia->formats;
1723   size_t i;
1724
1725   for (i = 0; i < p->modified_var_cnt; i++)
1726     var_destroy (p->modified_vars[i]);
1727   free (p->modified_vars);
1728   p->modified_vars = NULL;
1729   p->modified_var_cnt = 0;
1730 }
1731
1732 /* Resets the formats page to its defaults, discarding user
1733    modifications. */
1734 static void
1735 reset_formats_page (struct import_assistant *ia)
1736 {
1737   clear_modified_vars (ia);
1738   prepare_formats_page (ia);
1739 }
1740
1741 /* Called when the user changes one of the variables in the
1742    dictionary. */
1743 static void
1744 on_variable_change (PsppireDict *dict, int dict_idx,
1745                     struct import_assistant *ia)
1746 {
1747   struct formats_page *p = &ia->formats;
1748   GtkTreeView *tv = ia->formats.data_tree_view;
1749   gint column_idx = dict_idx + 1;
1750
1751   push_watch_cursor (ia);
1752
1753   /* Remove previous column and replace with new column. */
1754   gtk_tree_view_remove_column (tv, gtk_tree_view_get_column (tv, column_idx));
1755   gtk_tree_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx),
1756                                column_idx);
1757
1758   /* Save a copy of the modified variable in modified_vars, so
1759      that its attributes will be preserved if we back up to the
1760      previous page with the Prev button and then come back
1761      here. */
1762   if (dict_idx >= p->modified_var_cnt)
1763     {
1764       size_t i;
1765       p->modified_vars = xnrealloc (p->modified_vars, dict_idx + 1,
1766                                     sizeof *p->modified_vars);
1767       for (i = 0; i <= dict_idx; i++)
1768         p->modified_vars[i] = NULL;
1769       p->modified_var_cnt = dict_idx + 1;
1770     }
1771   if (p->modified_vars[dict_idx])
1772     var_destroy (p->modified_vars[dict_idx]);
1773   p->modified_vars[dict_idx]
1774     = var_clone (psppire_dict_get_variable (dict, dict_idx));
1775
1776   pop_watch_cursor (ia);
1777 }
1778
1779 /* Parses the contents of the field at (ROW,COLUMN) according to
1780    its variable format.  If OUTPUTP is non-null, then *OUTPUTP
1781    receives the formatted output for that field (which must be
1782    freed with free).  If TOOLTIPP is non-null, then *TOOLTIPP
1783    receives a message suitable for use in a tooltip, if one is
1784    needed, or a null pointer otherwise.  Returns true if a
1785    tooltip message is needed, otherwise false. */
1786 static bool
1787 parse_field (struct import_assistant *ia,
1788              size_t row, size_t column,
1789              char **outputp, char **tooltipp)
1790 {
1791   struct substring field;
1792   union value val;
1793   struct variable *var;
1794   const struct fmt_spec *in;
1795   struct fmt_spec out;
1796   char *tooltip;
1797   bool ok;
1798
1799   field = ia->separators.columns[column].contents[row];
1800   var = dict_get_var (ia->formats.dict, column);
1801   value_init (&val, var_get_width (var));
1802   in = var_get_print_format (var);
1803   out = fmt_for_output_from_input (in);
1804   tooltip = NULL;
1805   if (field.string != NULL)
1806     {
1807       char *error;
1808
1809       error = data_in (field, C_ENCODING, in->type, &val, var_get_width (var),
1810                        dict_get_encoding (ia->formats.dict));
1811       if (error != NULL)
1812         {
1813           tooltip = xasprintf (_("Cannot parse field content `%.*s' as "
1814                                  "format %s: %s"),
1815                                (int) field.length, field.string,
1816                                fmt_name (in->type), error);
1817           free (error);
1818         }
1819     }
1820   else
1821     {
1822       tooltip = xstrdup (_("This input line has too few separators "
1823                            "to fill in this field."));
1824       value_set_missing (&val, var_get_width (var));
1825     }
1826   if (outputp != NULL)
1827     {
1828       *outputp = data_out (&val, dict_get_encoding (ia->formats.dict),  &out);
1829     }
1830   value_destroy (&val, var_get_width (var));
1831
1832   ok = tooltip == NULL;
1833   if (tooltipp != NULL)
1834     *tooltipp = tooltip;
1835   else
1836     free (tooltip);
1837   return ok;
1838 }
1839
1840 /* Called to render one of the cells in the data preview tree
1841    view. */
1842 static void
1843 render_output_cell (GtkTreeViewColumn *tree_column,
1844                     GtkCellRenderer *cell,
1845                     GtkTreeModel *model,
1846                     GtkTreeIter *iter,
1847                     gpointer ia_)
1848 {
1849   struct import_assistant *ia = ia_;
1850   char *output;
1851   GValue gvalue = { 0, };
1852   bool ok;
1853
1854   ok = parse_field (ia,
1855                     (empty_list_store_iter_to_row (iter)
1856                      + ia->first_line.skip_lines),
1857                     GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
1858                                                         "column-number")),
1859                     &output, NULL);
1860
1861   g_value_init (&gvalue, G_TYPE_STRING);
1862   g_value_take_string (&gvalue, output);
1863   g_object_set_property (G_OBJECT (cell), "text", &gvalue);
1864   g_value_unset (&gvalue);
1865
1866   if (ok)
1867     g_object_set (cell, "background-set", FALSE, (void *) NULL);
1868   else
1869     g_object_set (cell,
1870                   "background", "red",
1871                   "background-set", TRUE,
1872                   (void *) NULL);
1873 }
1874
1875 /* Called to render a tooltip for one of the cells in the data
1876    preview tree view. */
1877 static gboolean
1878 on_query_output_tooltip (GtkWidget *widget, gint wx, gint wy,
1879                         gboolean keyboard_mode UNUSED,
1880                         GtkTooltip *tooltip, struct import_assistant *ia)
1881 {
1882   size_t row, column;
1883   char *text;
1884
1885   if (!get_tooltip_location (widget, wx, wy, ia, &row, &column))
1886     return FALSE;
1887
1888   if (parse_field (ia, row, column, NULL, &text))
1889     return FALSE;
1890
1891   gtk_tooltip_set_text (tooltip, text);
1892   free (text);
1893   return TRUE;
1894 }
1895 \f
1896 /* Utility functions used by multiple pages of the assistant. */
1897
1898 static gboolean
1899 get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
1900                       const struct import_assistant *ia,
1901                       size_t *row, size_t *column)
1902 {
1903   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1904   gint bx, by;
1905   GtkTreePath *path;
1906   GtkTreeIter iter;
1907   GtkTreeViewColumn *tree_column;
1908   GtkTreeModel *tree_model;
1909   bool ok;
1910
1911   /* Check that WIDGET is really visible on the screen before we
1912      do anything else.  This is a bug fix for a sticky situation:
1913      when text_data_import_assistant() returns, it frees the data
1914      necessary to compose the tool tip message, but there may be
1915      a tool tip under preparation at that point (even if there is
1916      no visible tool tip) that will call back into us a little
1917      bit later.  Perhaps the correct solution to this problem is
1918      to make the data related to the tool tips part of a GObject
1919      that only gets destroyed when all references are released,
1920      but this solution appears to be effective too. */
1921   if (!gtk_widget_get_mapped (widget))
1922     return FALSE;
1923
1924   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
1925                                                      wx, wy, &bx, &by);
1926   if (!gtk_tree_view_get_path_at_pos (tree_view, bx, by,
1927                                       &path, &tree_column, NULL, NULL))
1928     return FALSE;
1929
1930   *column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
1931                                                 "column-number"));
1932
1933   tree_model = gtk_tree_view_get_model (tree_view);
1934   ok = gtk_tree_model_get_iter (tree_model, &iter, path);
1935   gtk_tree_path_free (path);
1936   if (!ok)
1937     return FALSE;
1938
1939   *row = empty_list_store_iter_to_row (&iter) + ia->first_line.skip_lines;
1940   return TRUE;
1941 }
1942
1943 static void
1944 make_tree_view (const struct import_assistant *ia,
1945                 size_t first_line,
1946                 GtkTreeView **tree_view)
1947 {
1948   GtkTreeModel *model;
1949
1950   *tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
1951   model = GTK_TREE_MODEL (psppire_empty_list_store_new (
1952                             ia->file.line_cnt - first_line));
1953   g_object_set_data (G_OBJECT (model), "lines", ia->file.lines + first_line);
1954   g_object_set_data (G_OBJECT (model), "first-line",
1955                      GINT_TO_POINTER (first_line));
1956   gtk_tree_view_set_model (*tree_view, model);
1957
1958   add_line_number_column (ia, *tree_view);
1959 }
1960
1961 static void
1962 render_line_number (GtkTreeViewColumn *tree_column,
1963                     GtkCellRenderer *cell,
1964                     GtkTreeModel *tree_model,
1965                     GtkTreeIter *iter,
1966                     gpointer data)
1967 {
1968   gint row = empty_list_store_iter_to_row (iter);
1969   char s[INT_BUFSIZE_BOUND (int)];
1970   int first_line;
1971
1972   first_line = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_model),
1973                                                    "first-line"));
1974   sprintf (s, "%d", first_line + row);
1975   g_object_set (cell, "text", s, NULL);
1976 }
1977
1978 static void
1979 add_line_number_column (const struct import_assistant *ia,
1980                         GtkTreeView *treeview)
1981 {
1982   GtkTreeViewColumn *column;
1983
1984   column = gtk_tree_view_column_new_with_attributes (
1985     _("Line"), ia->asst.prop_renderer, (void *) NULL);
1986   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
1987   gtk_tree_view_column_set_fixed_width (
1988     column, get_monospace_width (treeview, ia->asst.prop_renderer, 5));
1989   gtk_tree_view_column_set_resizable (column, TRUE);
1990   gtk_tree_view_column_set_cell_data_func (column, ia->asst.prop_renderer,
1991                                            render_line_number, NULL, NULL);
1992   gtk_tree_view_append_column (treeview, column);
1993 }
1994
1995 static gint
1996 get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
1997                      size_t char_cnt)
1998 {
1999   struct string s;
2000   gint width;
2001
2002   ds_init_empty (&s);
2003   ds_put_byte_multiple (&s, '0', char_cnt);
2004   ds_put_byte (&s, ' ');
2005   width = get_string_width (treeview, renderer, ds_cstr (&s));
2006   ds_destroy (&s);
2007
2008   return width;
2009 }
2010
2011 static gint
2012 get_string_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
2013                   const char *string)
2014 {
2015   gint width;
2016   g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
2017   gtk_cell_renderer_get_size (renderer, GTK_WIDGET (treeview),
2018                               NULL, NULL, NULL, &width, NULL);
2019   return width;
2020 }
2021
2022 static GtkTreeViewColumn *
2023 make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
2024                   bool input, gint dict_idx)
2025 {
2026   struct variable *var = NULL;
2027   struct column *column = NULL;
2028   size_t char_cnt;
2029   gint content_width, header_width;
2030   GtkTreeViewColumn *tree_column;
2031   char *name;
2032
2033   if (input)
2034     column = &ia->separators.columns[dict_idx];
2035   else
2036     var = dict_get_var (ia->formats.dict, dict_idx);
2037
2038   name = escape_underscores (input ? column->name : var_get_name (var));
2039   char_cnt = input ? column->width : var_get_print_format (var)->w;
2040   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
2041                                        char_cnt);
2042   header_width = get_string_width (tree_view, ia->asst.prop_renderer,
2043                                    name);
2044
2045   tree_column = gtk_tree_view_column_new ();
2046   g_object_set_data (G_OBJECT (tree_column), "column-number",
2047                      GINT_TO_POINTER (dict_idx));
2048   gtk_tree_view_column_set_title (tree_column, name);
2049   gtk_tree_view_column_pack_start (tree_column, ia->asst.fixed_renderer,
2050                                    FALSE);
2051   gtk_tree_view_column_set_cell_data_func (
2052     tree_column, ia->asst.fixed_renderer,
2053     input ? render_input_cell : render_output_cell, ia, NULL);
2054   gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_FIXED);
2055   gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
2056                                                           header_width));
2057
2058   free (name);
2059
2060   return tree_column;
2061 }
2062
2063 static GtkTreeView *
2064 create_data_tree_view (bool input, GtkContainer *parent,
2065                        struct import_assistant *ia)
2066 {
2067   GtkTreeView *tree_view;
2068   gint i;
2069
2070   make_tree_view (ia, ia->first_line.skip_lines, &tree_view);
2071   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view),
2072                                GTK_SELECTION_NONE);
2073
2074   for (i = 0; i < ia->separators.column_cnt; i++)
2075     gtk_tree_view_append_column (tree_view,
2076                                  make_data_column (ia, tree_view, input, i));
2077
2078   g_object_set (G_OBJECT (tree_view), "has-tooltip", TRUE, (void *) NULL);
2079   g_signal_connect (tree_view, "query-tooltip",
2080                     G_CALLBACK (input ? on_query_input_tooltip
2081                                 : on_query_output_tooltip), ia);
2082   gtk_tree_view_set_fixed_height_mode (tree_view, true);
2083
2084   gtk_container_add (parent, GTK_WIDGET (tree_view));
2085   gtk_widget_show (GTK_WIDGET (tree_view));
2086
2087   return tree_view;
2088 }
2089
2090 /* Increments the "watch cursor" level, setting the cursor for
2091    the assistant window to a watch face to indicate to the user
2092    that the ongoing operation may take some time. */
2093 static void
2094 push_watch_cursor (struct import_assistant *ia)
2095 {
2096   if (++ia->asst.watch_cursor == 1)
2097     {
2098       GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
2099       GdkDisplay *display = gtk_widget_get_display (widget);
2100       GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
2101       gdk_window_set_cursor (widget->window, cursor);
2102       gdk_cursor_unref (cursor);
2103       gdk_display_flush (display);
2104     }
2105 }
2106
2107 /* Decrements the "watch cursor" level.  If the level reaches
2108    zero, the cursor is reset to its default shape. */
2109 static void
2110 pop_watch_cursor (struct import_assistant *ia)
2111 {
2112   if (--ia->asst.watch_cursor == 0)
2113     {
2114       GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
2115       gdk_window_set_cursor (widget->window, NULL);
2116     }
2117 }