str: Rename ss_chomp() to ss_chomp_byte(), ds_chomp() to ds_chomp_byte().
[pspp-builds.git] / src / ui / gui / text-data-import-dialog.c
index 6e6999e8255224507c8b76678fda477188d41e71..534cec9e0884450bc4a3bfc49200c9b0d428ef15 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 
-#include <gtk/gtk.h>
-
-
-
-#include "checkbox-treeview.h"
-#include "descriptives-dialog.h"
+#include "ui/gui/text-data-import-dialog.h"
 
 #include <errno.h>
-
 #include <gtk-contrib/psppire-sheet.h>
+#include <gtk/gtk.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include <data/data-in.h>
-#include <data/data-out.h>
-#include <data/format-guesser.h>
-#include <data/value-labels.h>
-#include <language/data-io/data-parser.h>
-#include <language/syntax-string-source.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <ui/syntax-gen.h>
-#include <ui/gui/psppire-data-window.h>
-#include <ui/gui/dialog-common.h>
-#include <ui/gui/helper.h>
-#include <ui/gui/psppire-dialog.h>
-#include <ui/gui/psppire-var-sheet.h>
-#include <ui/gui/psppire-var-store.h>
-#include <ui/gui/helper.h>
-
-#include "error.h"
-#include "xalloc.h"
+#include "data/data-in.h"
+#include "data/data-out.h"
+#include "data/format-guesser.h"
+#include "data/value-labels.h"
+#include "language/data-io/data-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "ui/gui/checkbox-treeview.h"
+#include "ui/gui/descriptives-dialog.h"
+#include "ui/gui/dialog-common.h"
+#include "ui/gui/executor.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog.h"
+#include "ui/gui/psppire-var-sheet.h"
+#include "ui/gui/psppire-var-store.h"
+#include "ui/gui/widget-io.h"
+#include "ui/syntax-gen.h"
+
+#include "gl/error.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 
-#if !GTK_CHECK_VERSION (2, 10, 0)
-
-void
-text_data_import_assistant (GObject *o, gpointer de_)
-{
-  struct data_editor *de = de_;
-
-  GtkWidget *dialog =
-    gtk_message_dialog_new  (GTK_WINDOW (de),
-                            GTK_DIALOG_MODAL,
-                            GTK_MESSAGE_WARNING,
-                            GTK_BUTTONS_CLOSE,
-                            _("The text import assistant has not been "
-                              "compiled into this build of PSPPIRE, because "
-                              "GTK+ version 2.10.0 or later was not available."));
-
-  gtk_dialog_run (GTK_DIALOG (dialog));
-
-  gtk_widget_destroy (dialog);
-}
-
-#else
-
 /* TextImportModel, a GtkTreeModel used by the text data import
    dialog. */
 enum
@@ -250,16 +226,14 @@ static GtkTreeViewColumn *make_data_column (struct import_assistant *,
                                             gint column_idx);
 static GtkTreeView *create_data_tree_view (bool input, GtkContainer *parent,
                                            struct import_assistant *);
-static void escape_underscores (const char *in, char *out);
+static char *escape_underscores (const char *in);
 static void push_watch_cursor (struct import_assistant *);
 static void pop_watch_cursor (struct import_assistant *);
 
 /* Pops up the Text Data Import assistant. */
 void
-text_data_import_assistant (GObject *o, gpointer de_)
+text_data_import_assistant (GtkWindow *parent_window)
 {
-  struct data_editor *de = de_;
-  GtkWindow *parent_window = GTK_WINDOW (de);
   struct import_assistant *ia;
 
   ia = xzalloc (sizeof *ia);
@@ -284,18 +258,10 @@ text_data_import_assistant (GObject *o, gpointer de_)
   switch (ia->asst.response)
     {
     case GTK_RESPONSE_APPLY:
-      {
-       char *syntax = generate_syntax (ia);
-       execute_syntax (create_syntax_string_source (syntax));
-       free (syntax);
-      }
+      free (execute_syntax_string (generate_syntax (ia)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       char *syntax = generate_syntax (ia);
-        paste_syntax_in_new_window (syntax);
-       free (syntax);
-      }
+      free (paste_syntax_to_window (generate_syntax (ia)));
       break;
     default:
       break;
@@ -335,11 +301,9 @@ apply_dict (const struct dictionary *dict, struct string *s)
           syntax_gen_pspp (s, "MISSING VALUES %ss (", name);
           for (j = 0; j < mv_n_values (mv); j++)
             {
-              union value value;
               if (j)
                 ds_put_cstr (s, ", ");
-              mv_get_value (mv, &value, j);
-              syntax_gen_value (s, &value, width, format);
+              syntax_gen_value (s, mv_get_value (mv, j), width, format);
             }
 
           if (mv_has_range (mv))
@@ -355,18 +319,20 @@ apply_dict (const struct dictionary *dict, struct string *s)
       if (var_has_value_labels (var))
         {
           const struct val_labs *vls = var_get_value_labels (var);
-          struct val_labs_iterator *iter;
-          struct val_lab *vl;
+          const struct val_lab **labels = val_labs_sorted (vls);
+          size_t n_labels = val_labs_count (vls);
+          size_t i;
 
           syntax_gen_pspp (s, "VALUE LABELS %ss", name);
-          for (vl = val_labs_first_sorted (vls, &iter); vl != NULL;
-               vl = val_labs_next (vls, &iter))
+          for (i = 0; i < n_labels; i++)
             {
+              const struct val_lab *vl = labels[i];
               ds_put_cstr (s, "\n  ");
               syntax_gen_value (s, &vl->value, width, format);
-              ds_put_char (s, ' ');
-              syntax_gen_string (s, ss_cstr (vl->label));
+              ds_put_byte (s, ' ');
+              syntax_gen_string (s, ss_cstr (val_lab_get_label (vl)));
             }
+          free (labels);
           ds_put_cstr (s, ".\n");
         }
       if (var_has_label (var))
@@ -423,9 +389,9 @@ generate_syntax (const struct import_assistant *ia)
   if (ia->first_line.skip_lines > 0)
     ds_put_format (&s, "  /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
   ds_put_cstr (&s, "  /DELIMITERS=\"");
-  if (ds_find_char (&ia->separators.separators, '\t') != SIZE_MAX)
+  if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
     ds_put_cstr (&s, "\\t");
-  if (ds_find_char (&ia->separators.separators, '\\') != SIZE_MAX)
+  if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
     ds_put_cstr (&s, "\\\\");
   for (i = 0; i < ds_length (&ia->separators.separators); i++)
     {
@@ -433,7 +399,7 @@ generate_syntax (const struct import_assistant *ia)
       if (c == '"')
         ds_put_cstr (&s, "\"\"");
       else if (c != '\t' && c != '\\')
-        ds_put_char (&s, c);
+        ds_put_byte (&s, c);
     }
   ds_put_cstr (&s, "\"\n");
   if (!ds_is_empty (&ia->separators.quotes))
@@ -483,7 +449,7 @@ init_file (struct import_assistant *ia, GtkWindow *parent_window)
   stream = fopen (file->file_name, "r");
   if (stream == NULL)
     {
-      msg (ME, _("Could not open \"%s\": %s"),
+      msg (ME, _("Could not open `%s': %s"),
            file->file_name, strerror (errno));
       return false;
     }
@@ -499,10 +465,10 @@ init_file (struct import_assistant *ia, GtkWindow *parent_window)
           if (feof (stream))
             break;
           else if (ferror (stream))
-            msg (ME, _("Error reading \"%s\": %s"),
+            msg (ME, _("Error reading `%s': %s"),
                  file->file_name, strerror (errno));
           else
-            msg (ME, _("Failed to read \"%s\", because it contains a line "
+            msg (ME, _("Failed to read `%s', because it contains a line "
                        "over %d bytes long and therefore appears not to be "
                        "a text file."),
                  file->file_name, MAX_LINE_LEN);
@@ -510,13 +476,13 @@ init_file (struct import_assistant *ia, GtkWindow *parent_window)
           destroy_file (ia);
           return false;
         }
-      ds_chomp (line, '\n');
-      ds_chomp (line, '\r');
+      ds_chomp_byte (line, '\n');
+      ds_chomp_byte (line, '\r');
     }
 
   if (file->line_cnt == 0)
     {
-      msg (ME, _("\"%s\" is empty."), file->file_name);
+      msg (ME, _("`%s' is empty."), file->file_name);
       fclose (stream);
       destroy_file (ia);
       return false;
@@ -614,6 +580,7 @@ init_assistant (struct import_assistant *ia, GtkWindow *parent_window)
   gtk_window_set_title (GTK_WINDOW (a->assistant),
                         _("Importing Delimited Text Data"));
   gtk_window_set_transient_for (GTK_WINDOW (a->assistant), parent_window);
+  gtk_window_set_icon_name (GTK_WINDOW (a->assistant), "psppicon");
 
   a->prop_renderer = gtk_cell_renderer_text_new ();
   g_object_ref_sink (a->prop_renderer);
@@ -673,6 +640,13 @@ static void
 on_prepare (GtkAssistant *assistant, GtkWidget *page,
             struct import_assistant *ia)
 {
+
+  if (gtk_assistant_get_page_type (assistant, page)
+      == GTK_ASSISTANT_PAGE_CONFIRM)
+    gtk_widget_grab_focus (assistant->apply);
+  else
+    gtk_widget_grab_focus (assistant->forward);
+
   if (page == ia->separators.page)
     prepare_separators_page (ia);
   else if (page == ia->formats.page)
@@ -737,8 +711,7 @@ close_assistant (struct import_assistant *ia, int response)
 \f
 /* The "intro" page of the assistant. */
 
-static void on_intro_amount_changed (GtkToggleButton *button,
-                                     struct import_assistant *);
+static void on_intro_amount_changed (struct import_assistant *);
 
 /* Initializes IA's intro substructure. */
 static void
@@ -747,21 +720,47 @@ init_intro_page (struct import_assistant *ia)
   GtkBuilder *builder = ia->asst.builder;
   struct intro_page *p = &ia->intro;
   struct string s;
+  GtkWidget *hbox_n_cases ;
+  GtkWidget *hbox_percent ;
+  GtkWidget *table ;
+
+
+  p->n_cases_spin = gtk_spin_button_new_with_range (0, INT_MAX, 100);
+
+  hbox_n_cases = widget_scanf (_("Only the first %4d cases"), &p->n_cases_spin);
+
+  table  = get_widget_assert (builder, "button-table");
+
+  gtk_table_attach_defaults (GTK_TABLE (table), hbox_n_cases,
+                   1, 2,
+                   1, 2);
+
+  p->percent_spin = gtk_spin_button_new_with_range (0, 100, 10);
+
+  hbox_percent = widget_scanf (_("Only the first %3d %% of file (approximately)"), &p->percent_spin);
+
+  gtk_table_attach_defaults (GTK_TABLE (table), hbox_percent,
+                            1, 2,
+                            2, 3);
 
   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Intro"),
                                    GTK_ASSISTANT_PAGE_INTRO);
+
   p->all_cases_button = get_widget_assert (builder, "import-all-cases");
+
   p->n_cases_button = get_widget_assert (builder, "import-n-cases");
-  p->n_cases_spin = get_widget_assert (builder, "n-cases-spin");
+
   p->percent_button = get_widget_assert (builder, "import-percent");
-  p->percent_spin = get_widget_assert (builder, "percent-spin");
-  g_signal_connect (p->all_cases_button, "toggled",
+
+  g_signal_connect_swapped (p->all_cases_button, "toggled",
                     G_CALLBACK (on_intro_amount_changed), ia);
-  g_signal_connect (p->n_cases_button, "toggled",
+  g_signal_connect_swapped (p->n_cases_button, "toggled",
                     G_CALLBACK (on_intro_amount_changed), ia);
-  g_signal_connect (p->percent_button, "toggled",
+  g_signal_connect_swapped (p->percent_button, "toggled",
                     G_CALLBACK (on_intro_amount_changed), ia);
 
+  on_intro_amount_changed (ia);
+
   ds_init_empty (&s);
   ds_put_cstr (&s, _("This assistant will guide you through the process of "
                      "importing data into PSPP from a text file with one line "
@@ -807,8 +806,7 @@ reset_intro_page (struct import_assistant *ia)
 
 /* Called when one of the radio buttons is clicked. */
 static void
-on_intro_amount_changed (GtkToggleButton *button UNUSED,
-                         struct import_assistant *ia)
+on_intro_amount_changed (struct import_assistant *ia)
 {
   struct intro_page *p = &ia->intro;
 
@@ -816,7 +814,7 @@ on_intro_amount_changed (GtkToggleButton *button UNUSED,
                             gtk_toggle_button_get_active (
                               GTK_TOGGLE_BUTTON (p->n_cases_button)));
 
-  gtk_widget_set_sensitive (ia->intro.percent_spin,
+  gtk_widget_set_sensitive (p->percent_spin,
                             gtk_toggle_button_get_active (
                               GTK_TOGGLE_BUTTON (p->percent_button)));
 }
@@ -874,13 +872,16 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
   size_t max_line_length;
   gint content_width, header_width;
   size_t i;
+  gchar *title = _("Text");
 
   make_tree_view (ia, 0, &tree_view);
 
-  column = gtk_tree_view_column_new_with_attributes (
-    "Text", ia->asst.fixed_renderer,
-    "text", TEXT_IMPORT_MODEL_COLUMN_LINE,
-    (void *) NULL);
+  column = gtk_tree_view_column_new_with_attributes 
+    (
+     title, ia->asst.fixed_renderer,
+     "text", TEXT_IMPORT_MODEL_COLUMN_LINE,
+     (void *) NULL
+     );
   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
 
   max_line_length = 0;
@@ -892,7 +893,7 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
 
   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
                                        max_line_length);
-  header_width = get_string_width (tree_view, ia->asst.prop_renderer, "Text");
+  header_width = get_string_width (tree_view, ia->asst.prop_renderer, title);
   gtk_tree_view_column_set_fixed_width (column, MAX (content_width,
                                                      header_width));
   gtk_tree_view_append_column (tree_view, column);
@@ -1018,6 +1019,31 @@ static const struct separator separators[] =
   };
 #define SEPARATOR_CNT (sizeof separators / sizeof *separators)
 
+static void
+set_quote_list (GtkComboBoxEntry *cb)
+{
+  GtkListStore *list =  gtk_list_store_new (1, G_TYPE_STRING);
+  GtkTreeIter iter;
+  gint i;
+  const gchar *seperator[3] = {"'\"", "\'", "\""};
+
+  for (i = 0; i < 3; i++)
+    {
+      const gchar *s = seperator[i];
+
+      /* Add a new row to the model */
+      gtk_list_store_append (list, &iter);
+      gtk_list_store_set (list, &iter,
+                          0, s,
+                          -1);
+
+    }
+
+  gtk_combo_box_set_model (GTK_COMBO_BOX (cb), GTK_TREE_MODEL (list));
+
+  gtk_combo_box_entry_set_text_column (cb, 0);
+}
+
 /* Initializes IA's separators substructure. */
 static void
 init_separators_page (struct import_assistant *ia)
@@ -1038,12 +1064,13 @@ init_separators_page (struct import_assistant *ia)
   p->escape_cb = get_widget_assert (builder, "escape");
 
   set_separators (ia);
+  set_quote_list (GTK_COMBO_BOX_ENTRY (p->quote_combo));
   p->fields_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "fields"));
-  g_signal_connect (GTK_COMBO_BOX (p->quote_combo), "changed",
+  g_signal_connect (p->quote_combo, "changed",
                     G_CALLBACK (on_quote_combo_change), ia);
   g_signal_connect (p->quote_cb, "toggled",
                     G_CALLBACK (on_quote_cb_toggle), ia);
-  g_signal_connect (GTK_ENTRY (p->custom_entry), "notify::text",
+  g_signal_connect (p->custom_entry, "notify::text",
                     G_CALLBACK (on_separators_custom_entry_notify), ia);
   g_signal_connect (p->custom_cb, "toggled",
                     G_CALLBACK (on_separators_custom_cb_toggle), ia);
@@ -1133,7 +1160,7 @@ split_fields (struct import_assistant *ia)
   clear_fields (ia);
 
   /* Is space in the set of separators? */
-  space_sep = ss_find_char (ds_ss (&s->separators), ' ') != SIZE_MAX;
+  space_sep = ss_find_byte (ds_ss (&s->separators), ' ') != SIZE_MAX;
 
   /* Split all the lines, not just those from
      ia->first_line.skip_lines on, so that we split the line that
@@ -1160,9 +1187,9 @@ split_fields (struct import_assistant *ia)
               field = text;
             }
           else if (!ds_is_empty (&s->quotes)
-                   && ds_find_char (&s->quotes, text.string[0]) != SIZE_MAX)
+                   && ds_find_byte (&s->quotes, text.string[0]) != SIZE_MAX)
             {
-              int quote = ss_get_char (&text);
+              int quote = ss_get_byte (&text);
               if (!s->escape)
                 ss_get_until (&text, quote, &field);
               else
@@ -1171,18 +1198,18 @@ split_fields (struct import_assistant *ia)
                   int c;
 
                   ds_init_empty (&s);
-                  while ((c = ss_get_char (&text)) != EOF)
+                  while ((c = ss_get_byte (&text)) != EOF)
                     if (c != quote)
-                      ds_put_char (&s, c);
-                    else if (ss_match_char (&text, quote))
-                      ds_put_char (&s, quote);
+                      ds_put_byte (&s, c);
+                    else if (ss_match_byte (&text, quote))
+                      ds_put_byte (&s, quote);
                     else
                       break;
                   field = ds_ss (&s);
                 }
             }
           else
-            ss_get_chars (&text, ss_cspan (text, ds_ss (&s->separators)),
+            ss_get_bytes (&text, ss_cspan (text, ds_ss (&s->separators)),
                           &field);
 
           if (column_idx >= s->column_cnt)
@@ -1207,7 +1234,7 @@ split_fields (struct import_assistant *ia)
             ss_ltrim (&text, ss_cstr (" "));
           if (ss_is_empty (text))
             break;
-          if (ss_find_char (ds_ss (&s->separators), ss_first (text))
+          if (ss_find_byte (ds_ss (&s->separators), ss_first (text))
               != SIZE_MAX)
             ss_advance (&text, 1);
         }
@@ -1229,15 +1256,13 @@ choose_column_names (struct import_assistant *ia)
   name_row = f->variable_names && f->skip_lines ? f->skip_lines : 0;
   for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
     {
-      char name[VAR_NAME_LEN + 1];
-      char *hint;
+      char *hint, *name;
 
       hint = name_row ? ss_xstrdup (col->contents[name_row - 1]) : NULL;
-      if (!dict_make_unique_var_name (dict, hint, &generated_name_count, name))
-        NOT_REACHED ();
+      name = dict_make_unique_var_name (dict, hint, &generated_name_count);
       free (hint);
 
-      col->name = xstrdup (name);
+      col->name = name;
       dict_create_var_assert (dict, name, 0);
     }
   dict_destroy (dict);
@@ -1295,7 +1320,7 @@ find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
   if (max_count > 0)
     {
       ds_clear (result);
-      ds_put_char (result, max);
+      ds_put_byte (result, max);
     }
   else
     ds_assign_cstr (result, def);
@@ -1351,7 +1376,7 @@ set_separators (struct import_assistant *ia)
             }
         }
 
-      ds_put_char (&custom, c);
+      ds_put_byte (&custom, c);
     next:;
     }
 
@@ -1370,6 +1395,7 @@ set_separators (struct import_assistant *ia)
   ds_destroy (&custom);
 
   any_quotes = !ds_is_empty (&s->quotes);
+
   gtk_entry_set_text (s->quote_entry,
                       any_quotes ? ds_cstr (&s->quotes) : "\"");
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (s->quote_cb),
@@ -1393,7 +1419,7 @@ get_separators (struct import_assistant *ia)
       const struct separator *sep = &separators[i];
       GtkWidget *button = get_widget_assert (ia->asst.builder, sep->name);
       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
-        ds_put_char (&s->separators, sep->c);
+        ds_put_byte (&s->separators, sep->c);
     }
 
   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->custom_cb)))
@@ -1533,6 +1559,7 @@ init_formats_page (struct import_assistant *ia)
   p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "data"));
   p->modified_vars = NULL;
   p->modified_var_cnt = 0;
+  p->dict = NULL;
 }
 
 /* Frees IA's formats substructure. */
@@ -1573,7 +1600,6 @@ prepare_formats_page (struct import_assistant *ia)
   for (column_idx = 0; column_idx < s->column_cnt; column_idx++)
     {
       struct variable *modified_var;
-      char name[VAR_NAME_LEN + 1];
 
       modified_var = (column_idx < p->modified_var_cnt
                       ? p->modified_vars[column_idx] : NULL);
@@ -1582,11 +1608,11 @@ prepare_formats_page (struct import_assistant *ia)
           struct column *column = &s->columns[column_idx];
           struct variable *var;
           struct fmt_spec format;
+          char *name;
           size_t row;
 
           /* Choose variable name. */
-          if (!dict_make_unique_var_name (dict, column->name, &number, name))
-            NOT_REACHED ();
+          name = dict_make_unique_var_name (dict, column->name, &number);
 
           /* Choose variable format. */
           fmt_guesser_clear (fg);
@@ -1598,13 +1624,17 @@ prepare_formats_page (struct import_assistant *ia)
           /* Create variable. */
           var = dict_create_var_assert (dict, name, fmt_var_width (&format));
           var_set_both_formats (var, &format);
+
+          free (name);
         }
       else
         {
-          if (!dict_make_unique_var_name (dict, var_get_name (modified_var),
-                                          &number, name))
-            NOT_REACHED ();
-          dict_clone_var_assert (dict, modified_var, name);
+          char *name;
+
+          name = dict_make_unique_var_name (dict, var_get_name (modified_var),
+                                            &number);
+          dict_clone_var_as_assert (dict, modified_var, name);
+          free (name);
         }
     }
   fmt_guesser_destroy (fg);
@@ -1722,7 +1752,7 @@ parse_field (struct import_assistant *ia,
              char **outputp, char **tooltipp)
 {
   struct substring field;
-  union value *val;
+  union value val;
   struct variable *var;
   const struct fmt_spec *in;
   struct fmt_spec out;
@@ -1731,39 +1761,36 @@ parse_field (struct import_assistant *ia,
 
   field = ia->separators.columns[column].contents[row];
   var = dict_get_var (ia->formats.dict, column);
-  val = value_create (var_get_width (var));
+  value_init (&val, var_get_width (var));
   in = var_get_print_format (var);
   out = fmt_for_output_from_input (in);
   tooltip = NULL;
   if (field.string != NULL)
     {
-      msg_disable ();
-      if (!data_in (field, LEGACY_NATIVE, in->type, 0, 0, 0,
-                    val, var_get_width (var)))
+      char *error;
+
+      error = data_in (field, C_ENCODING, in->type, &val, var_get_width (var),
+                       dict_get_encoding (ia->formats.dict));
+      if (error != NULL)
         {
-          char fmt_string[FMT_STRING_LEN_MAX + 1];
-          fmt_to_string (in, fmt_string);
-          tooltip = xasprintf (_("Field content \"%.*s\" cannot be parsed in "
-                                 "format %s."),
+          tooltip = xasprintf (_("Cannot parse field content `%.*s' as "
+                                 "format %s: %s"),
                                (int) field.length, field.string,
-                               fmt_string);
+                               fmt_name (in->type), error);
+          free (error);
         }
-      msg_enable ();
     }
   else
     {
       tooltip = xstrdup (_("This input line has too few separators "
                            "to fill in this field."));
-      value_set_missing (val, var_get_width (var));
+      value_set_missing (&val, var_get_width (var));
     }
   if (outputp != NULL)
     {
-      char *output = xmalloc (out.w + 1);
-      data_out (val, &out, output);
-      output[out.w] = '\0';
-      *outputp = output;
+      *outputp = data_out (&val, dict_get_encoding (ia->formats.dict),  &out);
     }
-  free (val);
+  value_destroy (&val, var_get_width (var));
 
   ok = tooltip == NULL;
   if (tooltipp != NULL)
@@ -1899,7 +1926,7 @@ add_line_number_column (const struct import_assistant *ia,
   GtkTreeViewColumn *column;
 
   column = gtk_tree_view_column_new_with_attributes (
-    "Line", ia->asst.prop_renderer,
+                                                    _("Line"), ia->asst.prop_renderer,
     "text", TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER,
     (void *) NULL);
   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
@@ -1916,8 +1943,8 @@ get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
   gint width;
 
   ds_init_empty (&s);
-  ds_put_char_multiple (&s, '0', char_cnt);
-  ds_put_char (&s, ' ');
+  ds_put_byte_multiple (&s, '0', char_cnt);
+  ds_put_byte (&s, ' ');
   width = get_string_width (treeview, renderer, ds_cstr (&s));
   ds_destroy (&s);
 
@@ -1941,17 +1968,17 @@ make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
 {
   struct variable *var = NULL;
   struct column *column = NULL;
-  char name[(VAR_NAME_LEN * 2) + 1];
   size_t char_cnt;
   gint content_width, header_width;
   GtkTreeViewColumn *tree_column;
+  char *name;
 
   if (input)
     column = &ia->separators.columns[dict_idx];
   else
     var = dict_get_var (ia->formats.dict, dict_idx);
 
-  escape_underscores (input ? column->name : var_get_name (var), name);
+  name = escape_underscores (input ? column->name : var_get_name (var));
   char_cnt = input ? column->width : var_get_print_format (var)->w;
   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
                                        char_cnt);
@@ -1971,6 +1998,8 @@ make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
   gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
                                                           header_width));
 
+  free (name);
+
   return tree_column;
 }
 
@@ -2001,16 +2030,22 @@ create_data_tree_view (bool input, GtkContainer *parent,
   return tree_view;
 }
 
-static void
-escape_underscores (const char *in, char *out)
+static char *
+escape_underscores (const char *in)
 {
+  char *out = xmalloc (2 * strlen (in) + 1);
+  char *p;
+
+  p = out;
   for (; *in != '\0'; in++)
     {
       if (*in == '_')
-        *out++ = '_';
-      *out++ = *in;
+        *p++ = '_';
+      *p++ = *in;
     }
-  *out = '\0';
+  *p = '\0';
+
+  return out;
 }
 \f
 /* TextImportModel, a GtkTreeModel implementation used by some
@@ -2307,5 +2342,3 @@ pop_watch_cursor (struct import_assistant *ia)
       gdk_window_set_cursor (widget->window, NULL);
     }
 }
-
-#endif