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