From d55060c0fc838d89cbdea453a2ce58c3fb1b9b45 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Mon, 5 Apr 2021 14:32:48 +0100 Subject: [PATCH] Bug 796761 - Control characters can be pasted in register fields If copied text includes control characters they are inserted when pasted which can cause alignment issues. This commit filters the clipboard text for control characters before it is pasted. --- .../register-gnome/gnucash-item-edit.c | 39 ++++++++++- libgnucash/app-utils/gnc-ui-util.c | 64 +++++++++++++++++++ libgnucash/app-utils/gnc-ui-util.h | 9 +++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c index 3ea0de3103..9fb4f35c04 100644 --- a/gnucash/register/register-gnome/gnucash-item-edit.c +++ b/gnucash/register/register-gnome/gnucash-item-edit.c @@ -40,6 +40,7 @@ #include "gnucash-sheetP.h" #include "gnucash-style.h" +#include "gnc-ui-util.h" /* The arguments we take */ enum @@ -398,7 +399,43 @@ gnc_item_edit_copy_clipboard (GncItemEdit *item_edit) void gnc_item_edit_paste_clipboard (GncItemEdit *item_edit) { - gtk_editable_paste_clipboard(GTK_EDITABLE(item_edit->editor)); + GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET(item_edit->editor), + GDK_SELECTION_CLIPBOARD); + gchar *text = gtk_clipboard_wait_for_text (clipboard); + gchar *filtered_text; + gint start_pos, end_pos; + gint position; + + if (!text) + return; + + filtered_text = gnc_filter_text_for_control_chars (text); + + if (!filtered_text) + { + g_free (text); + return; + } + + position = gtk_editable_get_position (GTK_EDITABLE(item_edit->editor)); + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE(item_edit->editor), + &start_pos, &end_pos)) + { + position = start_pos; + + gtk_editable_delete_selection (GTK_EDITABLE(item_edit->editor)); + gtk_editable_insert_text (GTK_EDITABLE(item_edit->editor), + filtered_text, -1, &position); + } + else + gtk_editable_insert_text (GTK_EDITABLE(item_edit->editor), + filtered_text, -1, &position); + + gtk_editable_set_position (GTK_EDITABLE(item_edit->editor), position); + + g_free (text); + g_free (filtered_text); } diff --git a/libgnucash/app-utils/gnc-ui-util.c b/libgnucash/app-utils/gnc-ui-util.c index 8ab9dd7fb3..9fc8ae0b12 100644 --- a/libgnucash/app-utils/gnc-ui-util.c +++ b/libgnucash/app-utils/gnc-ui-util.c @@ -2663,3 +2663,67 @@ gnc_ui_util_remove_registered_prefs (void) GNC_PREF_AUTO_DECIMAL_PLACES, gnc_set_auto_decimal_places, NULL); } + +static gboolean +unichar_is_cntrl (gunichar uc) +{ + if (uc < 0x20 || (uc > 0x7e && uc < 0xa0)) + return TRUE; + else + return FALSE; +} + +gchar * +gnc_filter_text_for_control_chars (const gchar *text) +{ + gchar *normal_text, *nt; + GString *filtered; + gboolean cntrl = FALSE; + gboolean text_found = FALSE; + + if (!text) + return NULL; + + if (!g_utf8_validate (text, -1, NULL)) + return NULL; + + normal_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL_COMPOSE); + + filtered = g_string_sized_new (strlen (normal_text) + 1); + + nt = normal_text; + + while (*nt) + { + gunichar uc = g_utf8_get_char (nt); + + // check for starting with control characters + if (unichar_is_cntrl (uc) && !text_found) + { + nt = g_utf8_next_char (nt); + continue; + } + // check for alpha, num and punctuation + if (!unichar_is_cntrl (uc)) + { + filtered = g_string_append_unichar (filtered, uc); + text_found = TRUE; + } + // check for control characters after text + if (unichar_is_cntrl (uc)) + cntrl = TRUE; + + nt = g_utf8_next_char (nt); + + if (cntrl) // if control characters in text replace with space + { + gunichar uc2 = g_utf8_get_char (nt); + + if (!unichar_is_cntrl (uc2)) + filtered = g_string_append_unichar (filtered, ' '); + } + cntrl = FALSE; + } + g_free (normal_text); + return g_string_free (filtered, FALSE); +} diff --git a/libgnucash/app-utils/gnc-ui-util.h b/libgnucash/app-utils/gnc-ui-util.h index 40c99f7e14..c400c06378 100644 --- a/libgnucash/app-utils/gnc-ui-util.h +++ b/libgnucash/app-utils/gnc-ui-util.h @@ -397,6 +397,15 @@ void gnc_ui_util_init (void); void gnc_ui_util_remove_registered_prefs (void); +/** Returns the incoming text removed of control characters + * + * @param incoming_text The text to filter + * + * @return The incoming text filtered of control characters to be + * freed by the caller. +*/ +gchar * gnc_filter_text_for_control_chars (const gchar *incoming_text); + #endif /** @} */ /** @} */