This aligns with what SPSS does.
PROP_0,
PROP_CHILD,
PROP_DELIMITERS,
- PROP_QUOTES,
+ PROP_QUOTE,
PROP_FIRST_LINE
};
if (c == quote)
quote = -1;
- else if (c == tf->quotes[0] || c == tf->quotes[1])
+ else if (tf->quote && c == tf->quote)
quote = c;
if (quote == -1)
g_slist_free (tf->delimiters);
tf->delimiters = g_slist_copy (g_value_get_pointer (value));
break;
- case PROP_QUOTES:
- {
- tf->quotes[0] = tf->quotes[1] = -1;
-
- const gchar *s = g_value_get_string (value);
- for (size_t i = 0; i < 2 && s && s[0]; i++)
- {
- tf->quotes[i] = g_utf8_get_char (s);
- s = g_utf8_find_next_char (s, NULL);
- }
- }
+ case PROP_QUOTE:
+ tf->quote = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
case PROP_DELIMITERS:
g_value_set_pointer (value, text_file->delimiters);
break;
- case PROP_QUOTES:
- {
- GString *s = g_string_new (NULL);
- for (size_t i = 0; i < 2; i++)
- {
- gunichar quote = text_file->quotes[i];
- if (quote && quote != -1)
- g_string_append_unichar (s, quote);
- }
- }
+ case PROP_QUOTE:
+ g_value_set_uint (value, text_file->quote);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
gboolean char_is_quote = FALSE;
if (quote == -1)
{
- if (character == file->quotes[0] || character == file->quotes[1])
+ if (file->quote && character == file->quote)
{
quote = character;
char_is_quote = TRUE;
P_("A GSList of gunichars which delimit the fields."),
G_PARAM_READWRITE);
- GParamSpec *quotes_spec =
- g_param_spec_string ("quotes",
- "Field Quotes",
- P_("A string of characters that quote the fields."),
- P_(""),
+ GParamSpec *quote_spec =
+ g_param_spec_unichar ("quote",
+ "Quote Character",
+ P_("A character that quotes the field, or 0 to disable quoting."),
+ 0,
G_PARAM_READWRITE);
GParamSpec *child_spec =
delimiters_spec);
g_object_class_install_property (object_class,
- PROP_QUOTES,
- quotes_spec);
+ PROP_QUOTE,
+ quote_spec);
g_object_class_install_property (object_class,
PROP_FIRST_LINE,
text_file->max_delimiters = 0;
- text_file->quotes[0] = text_file->quotes[1] = -1;
+ text_file->quote = 0;
text_file->dispose_has_run = FALSE;
text_file->stamp = g_random_int ();
GSList *delimiters;
gint max_delimiters;
- gunichar quotes[2];
+ gunichar quote;
/*< private >*/
gboolean dispose_has_run ;
GtkWidget *custom_cb;
GtkWidget *custom_entry;
- GtkWidget *quote_cb;
- GtkWidget *quote_combo;
+ GtkWidget *quote_none;
+ GtkWidget *quote_single;
+ GtkWidget *quote_double;
+ GtkWidget *quote_custom;
+ GtkWidget *quote_custom_entry;
GtkWidget *fields_tree_view;
/* Chooses a name for each column on the separators page */
static void choose_column_names (PsppireImportAssistant *ia);
+static gunichar
+get_quote_character (const PsppireImportAssistant *ia)
+{
+ GtkToggleButton *quote_single = GTK_TOGGLE_BUTTON (ia->quote_single);
+ GtkToggleButton *quote_double = GTK_TOGGLE_BUTTON (ia->quote_double);
+ GtkToggleButton *quote_custom = GTK_TOGGLE_BUTTON (ia->quote_custom);
+
+ if (gtk_toggle_button_get_active (quote_custom))
+ {
+ GtkEntry *quote_custom_entry = GTK_ENTRY (ia->quote_custom_entry);
+ const gchar *text = gtk_entry_get_text (quote_custom_entry);
+ return text && text[0] ? g_utf8_get_char (text) : 0;
+ }
+ else
+ return (gtk_toggle_button_get_active (quote_single) ? '\''
+ : gtk_toggle_button_get_active (quote_double) ? '"'
+ : 0);
+}
+
/* Revises the contents of the fields tree view based on the
currently chosen set of separators and quotes. */
static void
}
}
- GtkComboBoxText *cbt = GTK_COMBO_BOX_TEXT (ia->quote_combo);
- GtkToggleButton *quote_cb = GTK_TOGGLE_BUTTON (ia->quote_cb);
- const gchar *quotes = (gtk_toggle_button_get_active (quote_cb)
- ? gtk_combo_box_text_get_active_text (cbt)
- : "");
-
g_object_set (ia->delimiters_model,
"delimiters", delimiters,
- "quotes", quotes,
+ "quote", get_quote_character (ia),
NULL);
choose_column_names (ia);
revise_fields_preview (ia);
}
-/* Called when the user changes the selection in the combo box
- that selects a quote character. */
+/* Called when the user changes any of the quote settings. */
static void
-on_quote_combo_change (GtkComboBox *combo, PsppireImportAssistant *ia)
+on_quote_change (GtkWidget *widget UNUSED, PsppireImportAssistant *ia)
{
+ GtkToggleButton *quote_custom = GTK_TOGGLE_BUTTON (ia->quote_custom);
+ bool is_custom = gtk_toggle_button_get_active (quote_custom);
+ gtk_widget_set_sensitive (ia->quote_custom_entry, is_custom);
revise_fields_preview (ia);
}
-/* Called when the user toggles the checkbox that enables
- quoting. */
static void
-on_quote_cb_toggle (GtkToggleButton *quote_cb, PsppireImportAssistant *ia)
+on_quote_custom_entry_change (GObject *gobject UNUSED,
+ GParamSpec *arg1 UNUSED,
+ PsppireImportAssistant *ia)
{
- bool is_active = gtk_toggle_button_get_active (quote_cb);
- gtk_widget_set_sensitive (ia->quote_combo, is_active);
revise_fields_preview (ia);
}
-
/* Called when the Reset button is clicked. */
static void
reset_separators_page (PsppireImportAssistant *ia)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->custom_cb), FALSE);
gtk_entry_set_text (GTK_ENTRY (ia->custom_entry), "");
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->quote_cb), TRUE);
- gtk_combo_box_set_active (GTK_COMBO_BOX (ia->quote_combo), 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ia->quote_double), TRUE);
+ gtk_entry_set_text (GTK_ENTRY (ia->quote_custom_entry), "");
for (gint i = 0; i < N_SEPARATORS; i++)
{
ia->custom_cb = get_widget_assert (builder, "custom-cb");
ia->custom_entry = get_widget_assert (builder, "custom-entry");
- ia->quote_combo = get_widget_assert (builder, "quote-combo");
- ia->quote_cb = get_widget_assert (builder, "quote-cb");
+ ia->quote_none = get_widget_assert (builder, "quote-none");
+ ia->quote_single = get_widget_assert (builder, "quote-single");
+ ia->quote_double = get_widget_assert (builder, "quote-double");
+ ia->quote_custom = get_widget_assert (builder, "quote-custom");
+ ia->quote_custom_entry = get_widget_assert (builder, "quote-custom-entry");
gtk_widget_set_sensitive (ia->custom_entry,
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->custom_cb)));
- gtk_entry_set_max_length (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (ia->quote_combo))), 1);
+ gtk_entry_set_max_length (GTK_ENTRY (ia->quote_custom_entry), 1);
if (ia->fields_tree_view == NULL)
{
gtk_widget_show_all (scroller);
}
- g_signal_connect (ia->quote_combo, "changed",
- G_CALLBACK (on_quote_combo_change), ia);
- g_signal_connect (ia->quote_cb, "toggled",
- G_CALLBACK (on_quote_cb_toggle), ia);
+ g_signal_connect (ia->quote_none, "toggled", G_CALLBACK (on_quote_change), ia);
+ g_signal_connect (ia->quote_single, "toggled", G_CALLBACK (on_quote_change), ia);
+ g_signal_connect (ia->quote_double, "toggled", G_CALLBACK (on_quote_change), ia);
+ g_signal_connect (ia->quote_custom, "toggled", G_CALLBACK (on_quote_change), ia);
+ g_signal_connect (ia->quote_custom_entry, "notify::text", G_CALLBACK (on_quote_custom_entry_change), ia);
g_signal_connect (ia->custom_entry, "notify::text",
G_CALLBACK (on_separators_custom_entry_notify), ia);
g_signal_connect (ia->custom_cb, "toggled",
}
ds_put_cstr (s, "\"\n");
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ia->quote_cb)))
+ gunichar quote = get_quote_character (ia);
+ if (quote)
{
- GtkComboBoxText *cbt = GTK_COMBO_BOX_TEXT (ia->quote_combo);
- gchar *quotes = gtk_combo_box_text_get_active_text (cbt);
- if (quotes && *quotes)
- syntax_gen_pspp (s, " /QUALIFIER=%sq\n", quotes);
- free (quotes);
+ GString *quote_s = g_string_new (NULL);
+ g_string_append_unichar (quote_s, quote);
+ syntax_gen_pspp (s, " /QUALIFIER=%sq\n", quote_s->str);
+ g_string_free (quote_s, TRUE);
}
}
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
+ <!-- n-columns=3 n-rows=4 -->
<object class="GtkGrid" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes"><b>Separators</b></property>
+ <property name="label" translatable="yes"><b>What characters separate fields?</b></property>
<property name="use_markup">True</property>
</object>
</child>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
- <object class="GtkGrid" id="table2">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="margin_start">12</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkComboBoxText" id="quote-combo">
+ <object class="GtkRadioButton" id="quote-none">
+ <property name="label" translatable="yes">None</property>
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="has_frame">False</property>
- <property name="has_entry">True</property>
- <items>
- <item translatable="no">"</item>
- <item translatable="no">'</item>
- </items>
- <child internal-child="entry">
- <object class="GtkEntry" id="combobox-entry1">
- <property name="can_focus">False</property>
- </object>
- </child>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkCheckButton" id="quote-cb">
- <property name="label" translatable="yes">Quote separator characters with</property>
+ <object class="GtkRadioButton" id="quote-single">
+ <property name="label" translatable="yes">Single quote (')</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="halign">start</property>
+ <property name="active">True</property>
<property name="draw_indicator">True</property>
+ <property name="group">quote-none</property>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="quote-double">
+ <property name="label" translatable="yes">Double quote (")</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="halign">start</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">quote-none</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkRadioButton" id="quote-custom">
+ <property name="label" translatable="yes">Custom:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">quote-none</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="quote-custom-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="width_chars">1</property>
+ <property name="max-width_chars">1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes"><b>Quoting</b></property>
+ <property name="label" translatable="yes"><b>What character quotes fields?</b></property>
<property name="use_markup">True</property>
</object>
</child>