[gspell: 3/3] Entry: do not check word currently typed
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gspell: 3/3] Entry: do not check word currently typed
- Date: Wed, 21 Dec 2016 15:46:34 +0000 (UTC)
commit 994312cea5d7866ad5083dfe06dd0a2b5c16b802
Author: Sébastien Wilmet <swilmet gnome org>
Date: Thu Dec 8 17:09:21 2016 +0100
Entry: do not check word currently typed
gspell/gspell-entry.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 253 insertions(+), 8 deletions(-)
---
diff --git a/gspell/gspell-entry.c b/gspell/gspell-entry.c
index 0e7e2b6..d54f728 100644
--- a/gspell/gspell-entry.c
+++ b/gspell/gspell-entry.c
@@ -22,6 +22,7 @@
#include "gspell-entry-buffer.h"
#include "gspell-entry-utils.h"
#include "gspell-context-menu.h"
+#include "gspell-current-word-policy.h"
/**
* SECTION:entry
@@ -54,6 +55,8 @@ struct _GspellEntry
GtkEntryBuffer *buffer;
GspellChecker *checker;
+ GspellCurrentWordPolicy *current_word_policy;
+
/* List elements: GspellEntryWord*.
* Used for unit tests.
*/
@@ -242,6 +245,17 @@ update_misspelled_words_list (GspellEntry *gspell_entry)
gspell_entry->misspelled_words = g_slist_reverse (gspell_entry->misspelled_words);
}
+static gboolean
+is_current_word (GspellEntry *gspell_entry,
+ GspellEntryWord *word)
+{
+ gint cursor_pos;
+
+ cursor_pos = gtk_editable_get_position (GTK_EDITABLE (gspell_entry->entry));
+
+ return (word->char_start <= cursor_pos && cursor_pos <= word->char_end);
+}
+
static void
recheck_all (GspellEntry *gspell_entry)
{
@@ -253,6 +267,12 @@ recheck_all (GspellEntry *gspell_entry)
{
GspellEntryWord *cur_word = l->data;
+ if (!_gspell_current_word_policy_get_check_current_word (gspell_entry->current_word_policy) &&
+ is_current_word (gspell_entry, cur_word))
+ {
+ continue;
+ }
+
insert_underline (gspell_entry,
cur_word->byte_start,
cur_word->byte_end);
@@ -323,6 +343,23 @@ notify_attributes_cb (GtkEntry *gtk_entry,
}
static void
+language_notify_cb (GspellChecker *checker,
+ GParamSpec *pspec,
+ GspellEntry *gspell_entry)
+{
+ _gspell_current_word_policy_language_changed (gspell_entry->current_word_policy);
+ emit_changed_signal (gspell_entry);
+}
+
+static void
+session_cleared_cb (GspellChecker *checker,
+ GspellEntry *gspell_entry)
+{
+ _gspell_current_word_policy_session_cleared (gspell_entry->current_word_policy);
+ emit_changed_signal (gspell_entry);
+}
+
+static void
set_checker (GspellEntry *gspell_entry,
GspellChecker *checker)
{
@@ -334,6 +371,14 @@ set_checker (GspellEntry *gspell_entry,
if (gspell_entry->checker != NULL)
{
g_signal_handlers_disconnect_by_func (gspell_entry->checker,
+ language_notify_cb,
+ gspell_entry);
+
+ g_signal_handlers_disconnect_by_func (gspell_entry->checker,
+ session_cleared_cb,
+ gspell_entry);
+
+ g_signal_handlers_disconnect_by_func (gspell_entry->checker,
emit_changed_signal,
gspell_entry);
@@ -344,15 +389,15 @@ set_checker (GspellEntry *gspell_entry,
if (gspell_entry->checker != NULL)
{
- g_signal_connect_swapped (gspell_entry->checker,
- "notify::language",
- G_CALLBACK (emit_changed_signal),
- gspell_entry);
+ g_signal_connect (gspell_entry->checker,
+ "notify::language",
+ G_CALLBACK (language_notify_cb),
+ gspell_entry);
- g_signal_connect_swapped (gspell_entry->checker,
- "session-cleared",
- G_CALLBACK (emit_changed_signal),
- gspell_entry);
+ g_signal_connect (gspell_entry->checker,
+ "session-cleared",
+ G_CALLBACK (session_cleared_cb),
+ gspell_entry);
g_signal_connect_swapped (gspell_entry->checker,
"word-added-to-personal",
@@ -380,10 +425,46 @@ notify_spell_checker_cb (GspellEntryBuffer *gspell_buffer,
GspellEntry *gspell_entry)
{
update_checker (gspell_entry);
+
+ _gspell_current_word_policy_checker_changed (gspell_entry->current_word_policy);
emit_changed_signal (gspell_entry);
}
static void
+inserted_text_cb (GtkEntryBuffer *buffer,
+ guint position,
+ gchar *chars,
+ guint n_chars,
+ GspellEntry *gspell_entry)
+{
+ if (n_chars > 1)
+ {
+ _gspell_current_word_policy_several_chars_inserted (gspell_entry->current_word_policy);
+ }
+ else
+ {
+ gunichar ch;
+ gboolean empty_selection;
+ gint cursor_pos;
+ gboolean at_cursor_pos;
+
+ ch = g_utf8_get_char (chars);
+
+ empty_selection = !gtk_editable_get_selection_bounds (GTK_EDITABLE (gspell_entry->entry),
+ NULL,
+ NULL);
+
+ cursor_pos = gtk_editable_get_position (GTK_EDITABLE (gspell_entry->entry));
+ at_cursor_pos = cursor_pos == (gint)position;
+
+ _gspell_current_word_policy_single_char_inserted (gspell_entry->current_word_policy,
+ ch,
+ empty_selection,
+ at_cursor_pos);
+ }
+}
+
+static void
set_buffer (GspellEntry *gspell_entry,
GtkEntryBuffer *gtk_buffer)
{
@@ -402,6 +483,10 @@ set_buffer (GspellEntry *gspell_entry,
notify_spell_checker_cb,
gspell_entry);
+ g_signal_handlers_disconnect_by_func (gspell_entry->buffer,
+ inserted_text_cb,
+ gspell_entry);
+
g_object_unref (gspell_entry->buffer);
}
@@ -416,6 +501,11 @@ set_buffer (GspellEntry *gspell_entry,
G_CALLBACK (notify_spell_checker_cb),
gspell_entry);
+ g_signal_connect (gspell_entry->buffer,
+ "inserted-text",
+ G_CALLBACK (inserted_text_cb),
+ gspell_entry);
+
g_object_ref (gspell_entry->buffer);
}
@@ -489,6 +579,9 @@ button_press_event_cb (GtkEntry *gtk_entry,
_gspell_entry_utils_get_char_position_at_event (gtk_entry, event);
}
+ _gspell_current_word_policy_cursor_moved (gspell_entry->current_word_policy);
+ emit_changed_signal (gspell_entry);
+
return GDK_EVENT_PROPAGATE;
}
@@ -622,6 +715,129 @@ populate_popup_cb (GtkEntry *gtk_entry,
}
static void
+move_cursor_cb (GspellEntry *gspell_entry)
+{
+ _gspell_current_word_policy_cursor_moved (gspell_entry->current_word_policy);
+ emit_changed_signal (gspell_entry);
+}
+
+static gboolean
+is_inside_word (const GSList *words,
+ gint char_pos)
+{
+ const GSList *l;
+
+ for (l = words; l != NULL; l = l->next)
+ {
+ const GspellEntryWord *cur_word = l->data;
+
+ if (cur_word->char_start <= char_pos && char_pos < cur_word->char_end)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+ends_word (const GSList *words,
+ gint char_pos)
+{
+ const GSList *l;
+
+ for (l = words; l != NULL; l = l->next)
+ {
+ const GspellEntryWord *cur_word = l->data;
+
+ if (cur_word->char_end == char_pos)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+delete_text_before_cb (GtkEditable *editable,
+ gint start_pos,
+ gint end_pos,
+ GspellEntry *gspell_entry)
+{
+ gint real_start_pos;
+ gint real_end_pos;
+ gint cursor_pos;
+ GSList *words;
+ gboolean empty_selection;
+ gboolean spans_several_lines;
+ gboolean several_chars;
+ gboolean cursor_pos_at_start;
+ gboolean cursor_pos_at_end;
+ gboolean start_is_inside_word;
+ gboolean start_ends_word;
+ gboolean end_is_inside_word;
+ gboolean end_ends_word;
+
+ real_start_pos = start_pos;
+
+ if (end_pos < 0)
+ {
+ real_end_pos = gtk_entry_get_text_length (gspell_entry->entry);
+ }
+ else
+ {
+ real_end_pos = end_pos;
+ }
+
+ if (real_start_pos == real_end_pos)
+ {
+ return;
+ }
+
+ if (real_start_pos > real_end_pos)
+ {
+ gint real_start_pos_copy;
+
+ /* swap */
+ real_start_pos_copy = real_start_pos;
+ real_start_pos = real_end_pos;
+ real_end_pos = real_start_pos_copy;
+ }
+
+ g_assert_cmpint (real_start_pos, <, real_end_pos);
+
+ empty_selection = !gtk_editable_get_selection_bounds (editable, NULL, NULL);
+ spans_several_lines = FALSE;
+ several_chars = (real_end_pos - real_start_pos) > 1;
+
+ cursor_pos = gtk_editable_get_position (editable);
+ cursor_pos_at_start = cursor_pos == real_start_pos;
+ cursor_pos_at_end = cursor_pos == real_end_pos;
+
+ words = _gspell_entry_utils_get_words (gspell_entry->entry);
+
+ start_is_inside_word = is_inside_word (words, real_start_pos);
+ start_ends_word = ends_word (words, real_start_pos);
+
+ end_is_inside_word = is_inside_word (words, real_end_pos);
+ end_ends_word = ends_word (words, real_end_pos);
+
+ g_slist_free_full (words, _gspell_entry_word_free);
+
+ _gspell_current_word_policy_text_deleted (gspell_entry->current_word_policy,
+ empty_selection,
+ spans_several_lines,
+ several_chars,
+ cursor_pos_at_start,
+ cursor_pos_at_end,
+ start_is_inside_word,
+ start_ends_word,
+ end_is_inside_word,
+ end_ends_word);
+}
+
+static void
set_entry (GspellEntry *gspell_entry,
GtkEntry *gtk_entry)
{
@@ -670,6 +886,22 @@ set_entry (GspellEntry *gspell_entry,
G_CALLBACK (populate_popup_cb),
gspell_entry);
+ /* Connecting to notify::cursor-position is not suitable because we have
+ * notifications also when text is inserted/deleted. And we get the
+ * notification *after* the GtkEditable::insert-text signal (not
+ * *during* its emission). So it's simpler to connect to ::move-cursor,
+ * even if it is not recommended.
+ */
+ g_signal_connect_swapped (gtk_entry,
+ "move-cursor",
+ G_CALLBACK (move_cursor_cb),
+ gspell_entry);
+
+ g_signal_connect (GTK_EDITABLE (gtk_entry),
+ "delete-text",
+ G_CALLBACK (delete_text_before_cb),
+ gspell_entry);
+
update_buffer (gspell_entry);
g_object_notify (G_OBJECT (gspell_entry), "entry");
@@ -742,6 +974,17 @@ gspell_entry_dispose (GObject *object)
}
static void
+gspell_entry_finalize (GObject *object)
+{
+ GspellEntry *gspell_entry = GSPELL_ENTRY (object);
+
+ /* Internal GObject, we can release it in finalize. */
+ g_clear_object (&gspell_entry->current_word_policy);
+
+ G_OBJECT_CLASS (gspell_entry_parent_class)->finalize (object);
+}
+
+static void
gspell_entry_class_init (GspellEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -749,6 +992,7 @@ gspell_entry_class_init (GspellEntryClass *klass)
object_class->get_property = gspell_entry_get_property;
object_class->set_property = gspell_entry_set_property;
object_class->dispose = gspell_entry_dispose;
+ object_class->finalize = gspell_entry_finalize;
/**
* GspellEntry:entry:
@@ -787,6 +1031,7 @@ gspell_entry_class_init (GspellEntryClass *klass)
static void
gspell_entry_init (GspellEntry *gspell_entry)
{
+ gspell_entry->current_word_policy = _gspell_current_word_policy_new ();
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]