/* 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 "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 <gtksheet/gtksheet.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/data-editor.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/syntax-editor.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/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
+
/* TextImportModel, a GtkTreeModel used by the text data import
dialog. */
enum
/* The main body of the GTK+ assistant and related data. */
struct assistant
{
- GladeXML *xml;
+ GtkBuilder *builder;
GtkAssistant *assistant;
GMainLoop *main_loop;
GtkWidget *paste_button;
GtkWidget *reset_button;
int response;
+ int watch_cursor;
GtkCellRenderer *prop_renderer;
GtkCellRenderer *fixed_renderer;
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 = de->parent.window;
struct import_assistant *ia;
ia = xzalloc (sizeof *ia);
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);
- struct syntax_editor *se =
- (struct syntax_editor *) window_create (WINDOW_SYNTAX, NULL);
- gtk_text_buffer_insert_at_cursor (se->buffer, syntax, -1);
- free (syntax);
- }
+ free (paste_syntax_to_window (generate_syntax (ia)));
break;
default:
break;
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))
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))
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++)
{
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))
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;
}
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);
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;
{
struct assistant *a = &ia->asst;
- a->xml = XML_NEW ("text-data-import.glade");
+ a->builder = builder_new ("text-data-import.ui");
a->assistant = GTK_ASSISTANT (gtk_assistant_new ());
g_signal_connect (a->assistant, "prepare", G_CALLBACK (on_prepare), ia);
g_signal_connect (a->assistant, "cancel", G_CALLBACK (on_cancel), ia);
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);
g_object_unref (a->prop_renderer);
g_object_unref (a->fixed_renderer);
- g_object_unref (a->xml);
+ g_object_unref (a->builder);
}
/* Appends a page of the given TYPE, with PAGE as its content, to
gtk_assistant_append_page (ia->asst.assistant, content);
gtk_assistant_set_page_type (ia->asst.assistant, content, type);
gtk_assistant_set_page_title (ia->asst.assistant, content, title_copy);
+ gtk_assistant_set_page_complete (ia->asst.assistant, content, true);
free (title_copy);
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)
gtk_widget_show (ia->asst.paste_button);
else
gtk_widget_hide (ia->asst.paste_button);
-
- /* Make the user visit each page in the assistant once. Seems
- like a reasonable user interface, plus visiting the final
- page is what constructs the dictionary. */
- gtk_assistant_set_page_complete (assistant, page, true);
}
/* Called when the Cancel button in the assistant is clicked. */
\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
init_intro_page (struct import_assistant *ia)
{
- GladeXML *xml = ia->asst.xml;
+ 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);
- p->page = add_page_to_assistant (ia, get_widget_assert (xml, "Intro"),
+ 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 (xml, "import-all-cases");
- p->n_cases_button = get_widget_assert (xml, "import-n-cases");
- p->n_cases_spin = get_widget_assert (xml, "n-cases-spin");
- p->percent_button = get_widget_assert (xml, "import-percent");
- p->percent_spin = get_widget_assert (xml, "percent-spin");
- g_signal_connect (p->all_cases_button, "toggled",
+
+ p->all_cases_button = get_widget_assert (builder, "import-all-cases");
+
+ p->n_cases_button = get_widget_assert (builder, "import-n-cases");
+
+ p->percent_button = get_widget_assert (builder, "import-percent");
+
+ 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 "
}
ds_put_cstr (&s, _("You may choose below how much of the file should "
"actually be imported."));
- gtk_label_set_text (GTK_LABEL (get_widget_assert (xml, "intro-label")),
+ gtk_label_set_text (GTK_LABEL (get_widget_assert (builder, "intro-label")),
ds_cstr (&s));
ds_destroy (&s);
}
/* 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;
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)));
}
init_first_line_page (struct import_assistant *ia)
{
struct first_line_page *p = &ia->first_line;
- GladeXML *xml = ia->asst.xml;
+ GtkBuilder *builder = ia->asst.builder;
- p->page = add_page_to_assistant (ia, get_widget_assert (xml, "FirstLine"),
+ p->page = add_page_to_assistant (ia, get_widget_assert (builder, "FirstLine"),
GTK_ASSISTANT_PAGE_CONTENT);
- gtk_widget_destroy (get_widget_assert (xml, "first-line"));
+ gtk_widget_destroy (get_widget_assert (builder, "first-line"));
p->tree_view = create_lines_tree_view (
- GTK_CONTAINER (get_widget_assert (xml, "first-line-scroller")), ia);
- p->variable_names_cb = get_widget_assert (xml, "variable-names");
+ GTK_CONTAINER (get_widget_assert (builder, "first-line-scroller")), ia);
+ p->variable_names_cb = get_widget_assert (builder, "variable-names");
gtk_tree_selection_set_mode (
gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)),
GTK_SELECTION_BROWSE);
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;
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);
};
#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)
{
- GladeXML *xml = ia->asst.xml;
+ GtkBuilder *builder = ia->asst.builder;
struct separators_page *p = &ia->separators;
size_t i;
choose_likely_separators (ia);
- p->page = add_page_to_assistant (ia, get_widget_assert (xml, "Separators"),
+ p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Separators"),
GTK_ASSISTANT_PAGE_CONTENT);
- p->custom_cb = get_widget_assert (xml, "custom-cb");
- p->custom_entry = get_widget_assert (xml, "custom-entry");
- p->quote_combo = get_widget_assert (xml, "quote-combo");
+ p->custom_cb = get_widget_assert (builder, "custom-cb");
+ p->custom_entry = get_widget_assert (builder, "custom-entry");
+ p->quote_combo = get_widget_assert (builder, "quote-combo");
p->quote_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (p->quote_combo)));
- p->quote_cb = get_widget_assert (xml, "quote-cb");
- p->escape_cb = get_widget_assert (xml, "escape");
+ p->quote_cb = get_widget_assert (builder, "quote-cb");
+ p->escape_cb = get_widget_assert (builder, "escape");
set_separators (ia);
- p->fields_tree_view = GTK_TREE_VIEW (get_widget_assert (xml, "fields"));
- g_signal_connect (GTK_COMBO_BOX (p->quote_combo), "changed",
+ 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 (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);
for (i = 0; i < SEPARATOR_CNT; i++)
- g_signal_connect (get_widget_assert (xml, separators[i].name),
+ g_signal_connect (get_widget_assert (builder, separators[i].name),
"toggled", G_CALLBACK (on_separator_toggle), ia);
g_signal_connect (p->escape_cb, "toggled",
G_CALLBACK (on_separator_toggle), 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
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
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)
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);
}
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);
if (max_count > 0)
{
ds_clear (result);
- ds_put_char (result, max);
+ ds_put_byte (result, max);
}
else
ds_assign_cstr (result, def);
revise_fields_preview (struct import_assistant *ia)
{
GtkWidget *w;
+
+ push_watch_cursor (ia);
+
w = GTK_WIDGET (ia->separators.fields_tree_view);
gtk_widget_destroy (w);
get_separators (ia);
choose_column_names (ia);
ia->separators.fields_tree_view = create_data_tree_view (
true,
- GTK_CONTAINER (get_widget_assert (ia->asst.xml, "fields-scroller")),
+ GTK_CONTAINER (get_widget_assert (ia->asst.builder, "fields-scroller")),
ia);
+
+ pop_watch_cursor (ia);
}
/* Sets the widgets to match IA's separators substructure. */
}
}
- ds_put_char (&custom, c);
+ ds_put_byte (&custom, c);
next:;
}
for (i = 0; i < SEPARATOR_CNT; i++)
{
const struct separator *s = &separators[i];
- GtkWidget *button = get_widget_assert (ia->asst.xml, s->name);
+ GtkWidget *button = get_widget_assert (ia->asst.builder, s->name);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
(seps & (1u << i)) != 0);
}
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),
for (i = 0; i < SEPARATOR_CNT; i++)
{
const struct separator *sep = &separators[i];
- GtkWidget *button = get_widget_assert (ia->asst.xml, sep->name);
+ 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)))
static void
init_formats_page (struct import_assistant *ia)
{
- GladeXML *xml = ia->asst.xml;
+ GtkBuilder *builder = ia->asst.builder;
struct formats_page *p = &ia->formats;
- p->page = add_page_to_assistant (ia, get_widget_assert (xml, "Formats"),
+ p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Formats"),
GTK_ASSISTANT_PAGE_CONFIRM);
- p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (xml, "data"));
+ 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. */
unsigned long int number = 0;
size_t column_idx;
+ push_watch_cursor (ia);
+
dict = dict_create ();
fg = fmt_guesser_create ();
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);
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);
/* 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);
hold a reference via ia->formats.dict. */
var_store = psppire_var_store_new (psppire_dict);
g_object_set (var_store,
- "trailing-rows", 1,
"format-type", PSPPIRE_VAR_STORE_INPUT_FORMATS,
(void *) NULL);
var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
g_object_set (var_sheet,
- "row-geometry", var_store,
"model", var_store,
"may-create-vars", FALSE,
(void *) NULL);
- vars_scroller = GTK_BIN (get_widget_assert (ia->asst.xml, "vars-scroller"));
+ vars_scroller = GTK_BIN (get_widget_assert (ia->asst.builder, "vars-scroller"));
old_var_sheet = gtk_bin_get_child (vars_scroller);
if (old_var_sheet != NULL)
gtk_widget_destroy (old_var_sheet);
gtk_widget_destroy (GTK_WIDGET (ia->formats.data_tree_view));
ia->formats.data_tree_view = create_data_tree_view (
false,
- GTK_CONTAINER (get_widget_assert (ia->asst.xml, "data-scroller")),
+ GTK_CONTAINER (get_widget_assert (ia->asst.builder, "data-scroller")),
ia);
+
+ pop_watch_cursor (ia);
}
/* Clears the set of user-modified variables from IA's formats
GtkTreeView *tv = ia->formats.data_tree_view;
gint column_idx = dict_idx + 1;
+ push_watch_cursor (ia);
+
/* Remove previous column and replace with new column. */
gtk_tree_view_remove_column (tv, gtk_tree_view_get_column (tv, column_idx));
gtk_tree_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx),
var_destroy (p->modified_vars[dict_idx]);
p->modified_vars[dict_idx]
= var_clone (psppire_dict_get_variable (dict, dict_idx));
+
+ pop_watch_cursor (ia);
}
/* Parses the contents of the field at (ROW,COLUMN) according to
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;
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, LEGACY_NATIVE, 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)
GtkTreeModel *tree_model;
bool ok;
+ /* Check that WIDGET is really visible on the screen before we
+ do anything else. This is a bug fix for a sticky situation:
+ when text_data_import_assistant() returns, it frees the data
+ necessary to compose the tool tip message, but there may be
+ a tool tip under preparation at that point (even if there is
+ no visible tool tip) that will call back into us a little
+ bit later. Perhaps the correct solution to this problem is
+ to make the data related to the tool tips part of a GObject
+ that only gets destroyed when all references are released,
+ but this solution appears to be effective too. */
+ if (!GTK_WIDGET_MAPPED (widget))
+ return FALSE;
+
gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
wx, wy, &bx, &by);
if (!gtk_tree_view_get_path_at_pos (tree_view, bx, by,
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);
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);
{
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);
gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
header_width));
+ free (name);
+
return tree_column;
}
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
assert (iter->stamp == TREE_MODEL_STAMP);
return GPOINTER_TO_INT (iter->user_data);
}
+
+/* Increments the "watch cursor" level, setting the cursor for
+ the assistant window to a watch face to indicate to the user
+ that the ongoing operation may take some time. */
+static void
+push_watch_cursor (struct import_assistant *ia)
+{
+ if (++ia->asst.watch_cursor == 1)
+ {
+ GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
+ GdkDisplay *display = gtk_widget_get_display (widget);
+ GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+ gdk_window_set_cursor (widget->window, cursor);
+ gdk_cursor_unref (cursor);
+ gdk_display_flush (display);
+ }
+}
+
+/* Decrements the "watch cursor" level. If the level reaches
+ zero, the cursor is reset to its default shape. */
+static void
+pop_watch_cursor (struct import_assistant *ia)
+{
+ if (--ia->asst.watch_cursor == 0)
+ {
+ GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
+ gdk_window_set_cursor (widget->window, NULL);
+ }
+}