[gspell/wip/entry-context-menu: 1/2] InlineCheckerTextBuffer: make suggestions context menu re-usable



commit f2a4d8951b00cd66861dfb040f5bc552551995e4
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sat Nov 26 13:47:19 2016 +0100

    InlineCheckerTextBuffer: make suggestions context menu re-usable
    
    So that it can be used in GspellEntry.

 gspell/gspell-context-menu.c               |  217 +++++++++++++++++++++++++++-
 gspell/gspell-context-menu.h               |   10 ++
 gspell/gspell-inline-checker-text-buffer.c |  192 ++++---------------------
 3 files changed, 253 insertions(+), 166 deletions(-)
---
diff --git a/gspell/gspell-context-menu.c b/gspell/gspell-context-menu.c
index 46cc587..1e4d55f 100644
--- a/gspell/gspell-context-menu.c
+++ b/gspell/gspell-context-menu.c
@@ -22,8 +22,11 @@
 #include <glib/gi18n-lib.h>
 
 #define LANGUAGE_DATA_KEY "gspell-language-data-key"
+#define SUGGESTION_DATA_KEY "gspell-suggestion-data-key"
+
+typedef struct _LanguageData   LanguageData;
+typedef struct _SuggestionData SuggestionData;
 
-typedef struct _LanguageData LanguageData;
 struct _LanguageData
 {
        const GspellLanguage *lang;
@@ -31,6 +34,30 @@ struct _LanguageData
        gpointer user_data;
 };
 
+struct _SuggestionData
+{
+       GspellChecker *checker;
+       gchar *misspelled_word;
+
+       gchar *suggested_word;
+       GspellSuggestionActivatedCallback callback;
+       gpointer user_data;
+};
+
+static void
+suggestion_data_free (gpointer data)
+{
+       SuggestionData *suggestion_data = data;
+
+       if (suggestion_data != NULL)
+       {
+               g_clear_object (&suggestion_data->checker);
+               g_free (suggestion_data->misspelled_word);
+               g_free (suggestion_data->suggested_word);
+               g_free (suggestion_data);
+       }
+}
+
 static void
 activate_language_cb (GtkWidget *menu_item)
 {
@@ -126,4 +153,192 @@ _gspell_context_menu_get_language_menu_item (const GspellLanguage            *cu
        return menu_item;
 }
 
+static void
+activate_suggestion_cb (GtkWidget *menu_item)
+{
+       SuggestionData *data;
+
+       data = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_DATA_KEY);
+       g_return_if_fail (data != NULL);
+
+       if (data->callback != NULL)
+       {
+               data->callback (data->suggested_word, data->user_data);
+       }
+}
+
+static void
+ignore_all_cb (GtkWidget *menu_item)
+{
+       SuggestionData *data;
+
+       data = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_DATA_KEY);
+       g_return_if_fail (data != NULL);
+
+       gspell_checker_add_word_to_session (data->checker,
+                                           data->misspelled_word,
+                                           -1);
+}
+
+static void
+add_to_dictionary_cb (GtkWidget *menu_item)
+{
+       SuggestionData *data;
+
+       data = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_DATA_KEY);
+       g_return_if_fail (data != NULL);
+
+       gspell_checker_add_word_to_personal (data->checker,
+                                            data->misspelled_word,
+                                            -1);
+}
+
+static GtkWidget *
+get_suggestion_menu (GspellChecker                     *checker,
+                    const gchar                       *misspelled_word,
+                    GspellSuggestionActivatedCallback  callback,
+                    gpointer                           user_data)
+{
+       GtkWidget *top_menu;
+       GtkWidget *menu_item;
+       GSList *suggestions = NULL;
+       SuggestionData *data;
+
+       top_menu = gtk_menu_new ();
+
+       suggestions = gspell_checker_get_suggestions (checker, misspelled_word, -1);
+
+       if (suggestions == NULL)
+       {
+               /* No suggestions. Put something in the menu anyway... */
+               menu_item = gtk_menu_item_new_with_label (_("(no suggested words)"));
+               gtk_widget_set_sensitive (menu_item, FALSE);
+               gtk_menu_shell_prepend (GTK_MENU_SHELL (top_menu), menu_item);
+       }
+       else
+       {
+               GtkWidget *menu = top_menu;
+               gint count = 0;
+               GSList *l;
+
+               /* Build a set of menus with suggestions. */
+               for (l = suggestions; l != NULL; l = l->next)
+               {
+                       gchar *suggested_word = l->data;
+                       GtkWidget *label;
+                       gchar *label_text;
+
+                       if (count == 10)
+                       {
+                               /* Separator */
+                               menu_item = gtk_separator_menu_item_new ();
+                               gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+
+                               menu_item = gtk_menu_item_new_with_mnemonic (_("_More…"));
+                               gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+
+                               menu = gtk_menu_new ();
+                               gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
+                               count = 0;
+                       }
+
+                       label_text = g_strdup_printf ("<b>%s</b>", suggested_word);
+
+                       label = gtk_label_new (label_text);
+                       gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+                       gtk_widget_set_halign (label, GTK_ALIGN_START);
+
+                       menu_item = gtk_menu_item_new ();
+                       gtk_container_add (GTK_CONTAINER (menu_item), label);
+                       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+
+                       data = g_new0 (SuggestionData, 1);
+                       data->suggested_word = g_strdup (suggested_word);
+                       data->callback = callback;
+                       data->user_data = user_data;
+
+                       g_object_set_data_full (G_OBJECT (menu_item),
+                                               SUGGESTION_DATA_KEY,
+                                               data,
+                                               suggestion_data_free);
+
+                       g_signal_connect (menu_item,
+                                         "activate",
+                                         G_CALLBACK (activate_suggestion_cb),
+                                         NULL);
+
+                       g_free (label_text);
+                       count++;
+               }
+       }
+
+       g_slist_free_full (suggestions, g_free);
+
+       /* Separator */
+       menu_item = gtk_separator_menu_item_new ();
+       gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
+
+       /* Ignore all */
+       menu_item = gtk_menu_item_new_with_mnemonic (_("_Ignore All"));
+       gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
+
+       data = g_new0 (SuggestionData, 1);
+       data->checker = g_object_ref (checker);
+       data->misspelled_word = g_strdup (misspelled_word);
+
+       g_object_set_data_full (G_OBJECT (menu_item),
+                               SUGGESTION_DATA_KEY,
+                               data,
+                               suggestion_data_free);
+
+       g_signal_connect (menu_item,
+                         "activate",
+                         G_CALLBACK (ignore_all_cb),
+                         NULL);
+
+       /* Add to Dictionary */
+       menu_item = gtk_menu_item_new_with_mnemonic (_("_Add"));
+       gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
+
+       data = g_new0 (SuggestionData, 1);
+       data->checker = g_object_ref (checker);
+       data->misspelled_word = g_strdup (misspelled_word);
+
+       g_object_set_data_full (G_OBJECT (menu_item),
+                               SUGGESTION_DATA_KEY,
+                               data,
+                               suggestion_data_free);
+
+       g_signal_connect (menu_item,
+                         "activate",
+                         G_CALLBACK (add_to_dictionary_cb),
+                         NULL);
+
+       return top_menu;
+}
+
+GtkMenuItem *
+_gspell_context_menu_get_suggestions_menu_item (GspellChecker                     *checker,
+                                               const gchar                       *misspelled_word,
+                                               GspellSuggestionActivatedCallback  callback,
+                                               gpointer                           user_data)
+{
+       GtkWidget *suggestion_menu;
+       GtkMenuItem *menu_item;
+
+       g_return_val_if_fail (GSPELL_IS_CHECKER (checker), NULL);
+       g_return_val_if_fail (misspelled_word != NULL, NULL);
+
+       suggestion_menu = get_suggestion_menu (checker,
+                                              misspelled_word,
+                                              callback,
+                                              user_data);
+
+       menu_item = GTK_MENU_ITEM (gtk_menu_item_new_with_mnemonic (_("_Spelling Suggestions…")));
+       gtk_menu_item_set_submenu (menu_item, suggestion_menu);
+       gtk_widget_show_all (GTK_WIDGET (menu_item));
+
+       return menu_item;
+}
+
 /* ex:set ts=8 noet: */
diff --git a/gspell/gspell-context-menu.h b/gspell/gspell-context-menu.h
index 5359e15..ee2e430 100644
--- a/gspell/gspell-context-menu.h
+++ b/gspell/gspell-context-menu.h
@@ -21,6 +21,7 @@
 #define GSPELL_CONTEXT_MENU_H
 
 #include <gtk/gtk.h>
+#include "gspell-checker.h"
 #include "gspell-language.h"
 
 G_BEGIN_DECLS
@@ -28,11 +29,20 @@ G_BEGIN_DECLS
 typedef void (*GspellLanguageActivatedCallback) (const GspellLanguage *lang,
                                                 gpointer              user_data);
 
+typedef void (*GspellSuggestionActivatedCallback) (const gchar *suggested_word,
+                                                  gpointer     user_data);
+
 G_GNUC_INTERNAL
 GtkMenuItem *  _gspell_context_menu_get_language_menu_item     (const GspellLanguage            
*current_language,
                                                                 GspellLanguageActivatedCallback  callback,
                                                                 gpointer                         user_data);
 
+G_GNUC_INTERNAL
+GtkMenuItem *  _gspell_context_menu_get_suggestions_menu_item  (GspellChecker                     *checker,
+                                                                const gchar                       
*misspelled_word,
+                                                                GspellSuggestionActivatedCallback  callback,
+                                                                gpointer                           
user_data);
+
 G_END_DECLS
 
 #endif /* GSPELL_CONTEXT_MENU_H */
diff --git a/gspell/gspell-inline-checker-text-buffer.c b/gspell/gspell-inline-checker-text-buffer.c
index 038f315..c0fbf45 100644
--- a/gspell/gspell-inline-checker-text-buffer.c
+++ b/gspell/gspell-inline-checker-text-buffer.c
@@ -28,6 +28,7 @@
 #include <glib/gi18n-lib.h>
 #include "gspellregion.h"
 #include "gspell-checker.h"
+#include "gspell-context-menu.h"
 #include "gspell-text-buffer.h"
 #include "gspell-text-iter.h"
 #include "gspell-utils.h"
@@ -76,8 +77,7 @@ typedef enum
        ADJUST_MODE_INCLUDE_NEIGHBORS,
 } AdjustMode;
 
-#define INLINE_CHECKER_TEXT_BUFFER_KEY "GspellInlineCheckerTextBufferID"
-#define SUGGESTION_KEY                 "GspellInlineSuggestionID"
+#define INLINE_CHECKER_TEXT_BUFFER_KEY "GspellInlineCheckerTextBufferID"
 
 /* Timeout durations in milliseconds. Writing and deleting text should be smooth
  * and responsive.
@@ -739,59 +739,17 @@ get_word_extents_at_click_position (GspellInlineCheckerTextBuffer *spell,
 }
 
 static void
-add_to_dictionary_cb (GtkWidget                     *menu_item,
-                     GspellInlineCheckerTextBuffer *spell)
-{
-       GtkTextIter start;
-       GtkTextIter end;
-       gchar *word;
-
-       if (!get_word_extents_at_click_position (spell, &start, &end))
-       {
-               return;
-       }
-
-       word = gtk_text_buffer_get_text (spell->buffer, &start, &end, FALSE);
-
-       if (spell->spell_checker != NULL)
-       {
-               gspell_checker_add_word_to_personal (spell->spell_checker, word, -1);
-       }
-
-       g_free (word);
-}
-
-static void
-ignore_all_cb (GtkWidget                     *menu_item,
-              GspellInlineCheckerTextBuffer *spell)
+suggestion_activated_cb (const gchar *suggested_word,
+                        gpointer     user_data)
 {
+       GspellInlineCheckerTextBuffer *spell;
        GtkTextIter start;
        GtkTextIter end;
-       gchar *word;
-
-       if (!get_word_extents_at_click_position (spell, &start, &end))
-       {
-               return;
-       }
-
-       word = gtk_text_buffer_get_text (spell->buffer, &start, &end, FALSE);
-
-       if (spell->spell_checker != NULL)
-       {
-               gspell_checker_add_word_to_session (spell->spell_checker, word, -1);
-       }
+       gchar *old_word;
 
-       g_free (word);
-}
+       g_return_if_fail (GSPELL_IS_INLINE_CHECKER_TEXT_BUFFER (user_data));
 
-static void
-replace_word_cb (GtkWidget                     *menu_item,
-                GspellInlineCheckerTextBuffer *spell)
-{
-       GtkTextIter start;
-       GtkTextIter end;
-       gchar *old_word;
-       const gchar *new_word;
+       spell = GSPELL_INLINE_CHECKER_TEXT_BUFFER (user_data);
 
        if (!get_word_extents_at_click_position (spell, &start, &end))
        {
@@ -800,13 +758,10 @@ replace_word_cb (GtkWidget                     *menu_item,
 
        old_word = gtk_text_buffer_get_text (spell->buffer, &start, &end, FALSE);
 
-       new_word = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_KEY);
-       g_return_if_fail (new_word != NULL);
-
        gtk_text_buffer_begin_user_action (spell->buffer);
 
        gtk_text_buffer_delete (spell->buffer, &start, &end);
-       gtk_text_buffer_insert (spell->buffer, &start, new_word, -1);
+       gtk_text_buffer_insert (spell->buffer, &start, suggested_word, -1);
 
        gtk_text_buffer_end_user_action (spell->buffer);
 
@@ -814,121 +769,20 @@ replace_word_cb (GtkWidget                     *menu_item,
        {
                gspell_checker_set_correction (spell->spell_checker,
                                               old_word, -1,
-                                              new_word, -1);
+                                              suggested_word, -1);
        }
 
        g_free (old_word);
 }
 
-static GtkWidget *
-get_suggestion_menu (GspellInlineCheckerTextBuffer *spell,
-                    const gchar                   *word)
-{
-       GtkWidget *top_menu;
-       GtkWidget *menu_item;
-       GSList *suggestions = NULL;
-
-       top_menu = gtk_menu_new ();
-
-       if (spell->spell_checker != NULL)
-       {
-               suggestions = gspell_checker_get_suggestions (spell->spell_checker, word, -1);
-       }
-
-       if (suggestions == NULL)
-       {
-               /* No suggestions. Put something in the menu anyway... */
-               menu_item = gtk_menu_item_new_with_label (_("(no suggested words)"));
-               gtk_widget_set_sensitive (menu_item, FALSE);
-               gtk_menu_shell_prepend (GTK_MENU_SHELL (top_menu), menu_item);
-       }
-       else
-       {
-               GtkWidget *menu = top_menu;
-               gint count = 0;
-               GSList *l;
-
-               /* Build a set of menus with suggestions. */
-               for (l = suggestions; l != NULL; l = l->next)
-               {
-                       gchar *suggested_word = l->data;
-                       GtkWidget *label;
-                       gchar *label_text;
-
-                       if (count == 10)
-                       {
-                               /* Separator */
-                               menu_item = gtk_separator_menu_item_new ();
-                               gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
-
-                               menu_item = gtk_menu_item_new_with_mnemonic (_("_More…"));
-                               gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
-
-                               menu = gtk_menu_new ();
-                               gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
-                               count = 0;
-                       }
-
-                       label_text = g_strdup_printf ("<b>%s</b>", suggested_word);
-
-                       label = gtk_label_new (label_text);
-                       gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
-                       gtk_widget_set_halign (label, GTK_ALIGN_START);
-
-                       menu_item = gtk_menu_item_new ();
-                       gtk_container_add (GTK_CONTAINER (menu_item), label);
-                       gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
-
-                       g_object_set_data_full (G_OBJECT (menu_item),
-                                               SUGGESTION_KEY,
-                                               g_strdup (suggested_word),
-                                               g_free);
-
-                       g_signal_connect (menu_item,
-                                         "activate",
-                                         G_CALLBACK (replace_word_cb),
-                                         spell);
-
-                       g_free (label_text);
-                       count++;
-               }
-       }
-
-       g_slist_free_full (suggestions, g_free);
-
-       /* Separator */
-       menu_item = gtk_separator_menu_item_new ();
-       gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
-
-       /* Ignore all */
-       menu_item = gtk_menu_item_new_with_mnemonic (_("_Ignore All"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
-
-       g_signal_connect (menu_item,
-                         "activate",
-                         G_CALLBACK (ignore_all_cb),
-                         spell);
-
-       /* Add to Dictionary */
-       menu_item = gtk_menu_item_new_with_mnemonic (_("_Add"));
-       gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
-
-       g_signal_connect (menu_item,
-                         "activate",
-                         G_CALLBACK (add_to_dictionary_cb),
-                         spell);
-
-       return top_menu;
-}
-
 void
 _gspell_inline_checker_text_buffer_populate_popup (GspellInlineCheckerTextBuffer *spell,
                                                   GtkMenu                       *menu)
 {
-       GtkWidget *menu_item;
+       GtkMenuItem *menu_item;
        GtkTextIter start;
        GtkTextIter end;
-       gchar *word;
+       gchar *misspelled_word;
 
        if (!get_word_extents_at_click_position (spell, &start, &end))
        {
@@ -940,16 +794,24 @@ _gspell_inline_checker_text_buffer_populate_popup (GspellInlineCheckerTextBuffer
                return;
        }
 
+       if (spell->spell_checker == NULL)
+       {
+               return;
+       }
+
        /* Prepend suggestions */
-       menu_item = gtk_menu_item_new_with_mnemonic (_("_Spelling Suggestions…"));
-       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
 
-       word = gtk_text_buffer_get_text (spell->buffer, &start, &end, FALSE);
-       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
-                                  get_suggestion_menu (spell, word));
-       g_free (word);
+       misspelled_word = gtk_text_buffer_get_text (spell->buffer, &start, &end, FALSE);
+
+       menu_item = _gspell_context_menu_get_suggestions_menu_item (spell->spell_checker,
+                                                                   misspelled_word,
+                                                                   suggestion_activated_cb,
+                                                                   spell);
+
+       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu),
+                               GTK_WIDGET (menu_item));
 
-       gtk_widget_show_all (menu_item);
+       g_free (misspelled_word);
 }
 
 static gboolean


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]