Revision: 90 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=90&view=rev Author: eht16 Date: 2008-06-28 09:20:36 -0700 (Sat, 28 Jun 2008)
Log Message: ----------- Use "populate-edit-menu" signal to add a "Spell Check" menu item to the editing menu and provide a submenu with suggestions for misspelled words and allow to add the word to the personal dictionary.
Modified Paths: -------------- trunk/spellcheck/ChangeLog trunk/spellcheck/src/spellcheck.c
Modified: trunk/spellcheck/ChangeLog =================================================================== --- trunk/spellcheck/ChangeLog 2008-06-28 08:19:15 UTC (rev 89) +++ trunk/spellcheck/ChangeLog 2008-06-28 16:20:36 UTC (rev 90) @@ -1,3 +1,12 @@ +2008-06-28 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de> + + * src/spellcheck.c: + Use "populate-edit-menu" signal to add a "Spell Check" menu item to + the editing menu and provide a submenu with suggestions for + misspelled words and allow to add the word to the personal + dictionary. + + 2008-06-19 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* README, configure.in, src/Makefile.am, src/spellcheck.c:
Modified: trunk/spellcheck/src/spellcheck.c =================================================================== --- trunk/spellcheck/src/spellcheck.c 2008-06-28 08:19:15 UTC (rev 89) +++ trunk/spellcheck/src/spellcheck.c 2008-06-28 16:20:36 UTC (rev 90) @@ -54,7 +54,7 @@ GeanyFunctions *geany_functions;
-PLUGIN_VERSION_CHECK(71) +PLUGIN_VERSION_CHECK(72) PLUGIN_SET_INFO(_("Spell Check"), _("Checks the spelling of the current document."), "0.2", _("The Geany developer team"))
@@ -66,12 +66,28 @@ gboolean check_while_typing; gulong signal_id; GPtrArray *dicts; + GtkWidget *edit_menu; + GtkWidget *edit_menu_sep; + GtkWidget *edit_menu_sub; EnchantBroker *broker; EnchantDict *dict; } SpellCheck; static SpellCheck *sc;
+#define MAX_MENU_SUGGESTIONS 10 +typedef struct +{ + gint pos; + GeanyDocument *doc; + gchar *suggs[MAX_MENU_SUGGESTIONS]; + gchar *word; +} SpellClickInfo; +static SpellClickInfo clickinfo;
+ +static void on_populate_edit_menu(GObject *obj, const gchar *word, gint pos, + GeanyDocument *doc, gpointer user_data); + /* Keybinding(s) */ enum { @@ -82,6 +98,13 @@
+PluginCallback plugin_callbacks[] = +{ + { "populate-edit-menu", (GCallback) &on_populate_edit_menu, FALSE, NULL }, + { NULL, NULL, FALSE, NULL } +}; + + /* currently unused */ #ifdef G_OS_WIN32 #warning TODO check Windows support @@ -105,6 +128,140 @@ #endif
+static void clear_indicators_on_range(GeanyDocument *doc, gint start, gint len) +{ + g_return_if_fail(doc != NULL); + + if (len > 0) + { + p_sci->send_message(doc->sci, SCI_STARTSTYLING, start, INDIC2_MASK); + p_sci->send_message(doc->sci, SCI_SETSTYLING, len, 0); + } +} + + +static void clear_indicators_on_line(GeanyDocument *doc, gint line_number) +{ + gint start_pos, length; + + g_return_if_fail(doc != NULL); + + start_pos = p_sci->get_position_from_line(doc->sci, line_number); + length = p_sci->get_line_length(doc->sci, line_number); + + clear_indicators_on_range(doc, start_pos, length); +} + + + +static void on_menu_suggestion_item_activate(GtkMenuItem *menuitem, gpointer gdata) +{ + gchar *sugg = gdata; + gint startword, endword; + + if (clickinfo.doc == NULL || clickinfo.pos == -1) + { + g_free(sugg); + return; + } + + startword = p_sci->send_message(clickinfo.doc->sci, SCI_WORDSTARTPOSITION, clickinfo.pos, 0); + endword = p_sci->send_message(clickinfo.doc->sci, SCI_WORDENDPOSITION, clickinfo.pos, 0); + + if (startword != endword) + { + p_sci->set_selection_start(clickinfo.doc->sci, startword); + p_sci->set_selection_end(clickinfo.doc->sci, endword); + p_sci->replace_sel(clickinfo.doc->sci, sugg); + + clear_indicators_on_range(clickinfo.doc, startword, endword - startword); + } +} + + +static void on_menu_addword_item_activate(GtkMenuItem *menuitem, gpointer gdata) +{ + gint startword, endword; + + if (clickinfo.doc == NULL || clickinfo.word == NULL || clickinfo.pos == -1) + return; + + enchant_dict_add_to_pwl(sc->dict, clickinfo.word, -1); + + startword = p_sci->send_message(clickinfo.doc->sci, SCI_WORDSTARTPOSITION, clickinfo.pos, 0); + endword = p_sci->send_message(clickinfo.doc->sci, SCI_WORDENDPOSITION, clickinfo.pos, 0); + if (startword != endword) + { + clear_indicators_on_range(clickinfo.doc, startword, endword - startword); + } +} + + +static void on_populate_edit_menu(GObject *obj, const gchar *word, gint pos, + GeanyDocument *doc, gpointer user_data) +{ + gsize n_suggs, i; + gchar **tmp_suggs; + + if (! NZV(word) || enchant_dict_check(sc->dict, word, -1) == 0) + { + gtk_widget_hide(sc->edit_menu); + gtk_widget_hide(sc->edit_menu_sep); + return; + } + + tmp_suggs = enchant_dict_suggest(sc->dict, word, -1, &n_suggs); + + if (tmp_suggs != NULL) + { + GtkWidget *menu_item, *image; + gchar *label; + + clickinfo.pos = pos; + clickinfo.doc = doc; + setptr(clickinfo.word, g_strdup(word)); + + if (GTK_IS_WIDGET(sc->edit_menu_sub)) + gtk_widget_destroy(sc->edit_menu_sub); + + sc->edit_menu_sub = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(sc->edit_menu), sc->edit_menu_sub); + + /* TODO do we need more than 10 suggestions? gtkspell offers additional suggestions + * in another sub menu, should we too? */ + for (i = 0; i < MIN(n_suggs, 10); i++) + { + /* keep the suggestions in a static array for the callback function */ + g_free(clickinfo.suggs[i]); + clickinfo.suggs[i] = g_strdup(tmp_suggs[i]); + + menu_item = gtk_menu_item_new_with_label(clickinfo.suggs[i]); + gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item); + g_signal_connect((gpointer) menu_item, "activate", + G_CALLBACK(on_menu_suggestion_item_activate), clickinfo.suggs[i]); + } + menu_item = gtk_separator_menu_item_new(); + gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item); + + image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU); + + label = g_strdup_printf(_("Add "%s" to Dictionary"), word); + menu_item = gtk_image_menu_item_new_with_label(label); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image); + gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item); + g_signal_connect((gpointer) menu_item, "activate", + G_CALLBACK(on_menu_addword_item_activate), NULL); + + gtk_widget_show(sc->edit_menu); + gtk_widget_show(sc->edit_menu_sep); + gtk_widget_show_all(sc->edit_menu_sub); + + enchant_dict_free_string_list(sc->dict, tmp_suggs); + g_free(label); + } +} + + static void dict_describe(const gchar* const lang, const gchar* const name, const gchar* const desc, const gchar* const file, void *target) { @@ -248,22 +405,6 @@ }
-static void clear_indicators_on_line(GeanyDocument *doc, gint line_number) -{ - glong start_pos, length; - - g_return_if_fail(doc != NULL); - - start_pos = p_sci->get_position_from_line(doc->sci, line_number); - length = p_sci->get_line_length(doc->sci, line_number); - if (length > 0) - { - p_sci->send_message(doc->sci, SCI_STARTSTYLING, start_pos, INDIC2_MASK); - p_sci->send_message(doc->sci, SCI_SETSTYLING, length, 0); - } -} - - /* Checks only the last word before the current cursor position -> check as you type. */ static gboolean on_key_release(GtkWidget *widget, GdkEventKey *ev, gpointer user_data) { @@ -458,6 +599,20 @@ }
+static void create_edit_menu() +{ + sc->edit_menu = gtk_image_menu_item_new_from_stock(GTK_STOCK_SPELL_CHECK, NULL); + gtk_container_add(GTK_CONTAINER(main_widgets->editor_menu), sc->edit_menu); + gtk_menu_reorder_child(GTK_MENU(main_widgets->editor_menu), sc->edit_menu, 0); + + sc->edit_menu_sep = gtk_separator_menu_item_new(); + gtk_container_add(GTK_CONTAINER(main_widgets->editor_menu), sc->edit_menu_sep); + gtk_menu_reorder_child(GTK_MENU(main_widgets->editor_menu), sc->edit_menu_sep, 1); + + gtk_widget_show_all(sc->edit_menu); +} + + static GtkWidget *create_menu() { GtkWidget *sp_item, *menu, *subitem; @@ -494,6 +649,7 @@ { GtkWidget *sp_item; GKeyFile *config = g_key_file_new(); + guint i;
sc = g_new0(SpellCheck, 1);
@@ -517,8 +673,15 @@ return; }
+ for (i = 0; i < MAX_MENU_SUGGESTIONS; i++) + { + clickinfo.suggs[i] = NULL; + } + clickinfo.word = NULL; + create_dicts_array();
+ create_edit_menu(); sp_item = create_menu(); gtk_widget_show_all(sp_item);
@@ -578,6 +741,11 @@ void plugin_cleanup(void) { guint i; + for (i = 0; i < MAX_MENU_SUGGESTIONS; i++) + { + clickinfo.suggs[i] = NULL; + } + g_free(clickinfo.word); for (i = 0; i < sc->dicts->len; i++) { g_free(g_ptr_array_index(sc->dicts, i)); @@ -586,6 +754,9 @@
g_signal_handler_disconnect(main_widgets->window, sc->signal_id);
+ gtk_widget_destroy(sc->edit_menu); + gtk_widget_destroy(sc->edit_menu_sep); + enchant_broker_free_dict(sc->broker, sc->dict); enchant_broker_free(sc->broker);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.