From 5ded9cba8563f336939400303d6a841d5089b107 Mon Sep 17 00:00:00 2001 From: Perberos Date: Mon, 7 Nov 2011 19:52:18 -0300 Subject: renaming from gedit to pluma --- plugins/spell/Makefile.am | 58 +- plugins/spell/gedit-automatic-spell-checker.c | 1015 --------------------- plugins/spell/gedit-automatic-spell-checker.h | 67 -- plugins/spell/gedit-spell-checker-dialog.c | 722 --------------- plugins/spell/gedit-spell-checker-dialog.h | 92 -- plugins/spell/gedit-spell-checker-language.c | 439 --------- plugins/spell/gedit-spell-checker-language.h | 51 -- plugins/spell/gedit-spell-checker.c | 520 ----------- plugins/spell/gedit-spell-checker.h | 109 --- plugins/spell/gedit-spell-language-dialog.c | 309 ------- plugins/spell/gedit-spell-language-dialog.h | 67 -- plugins/spell/gedit-spell-marshal.list | 6 - plugins/spell/gedit-spell-plugin.c | 1217 ------------------------- plugins/spell/gedit-spell-plugin.h | 75 -- plugins/spell/gedit-spell-utils.c | 94 -- plugins/spell/gedit-spell-utils.h | 37 - plugins/spell/pluma-automatic-spell-checker.c | 1015 +++++++++++++++++++++ plugins/spell/pluma-automatic-spell-checker.h | 67 ++ plugins/spell/pluma-spell-checker-dialog.c | 722 +++++++++++++++ plugins/spell/pluma-spell-checker-dialog.h | 92 ++ plugins/spell/pluma-spell-checker-language.c | 439 +++++++++ plugins/spell/pluma-spell-checker-language.h | 51 ++ plugins/spell/pluma-spell-checker.c | 520 +++++++++++ plugins/spell/pluma-spell-checker.h | 109 +++ plugins/spell/pluma-spell-language-dialog.c | 309 +++++++ plugins/spell/pluma-spell-language-dialog.h | 67 ++ plugins/spell/pluma-spell-marshal.list | 6 + plugins/spell/pluma-spell-plugin.c | 1217 +++++++++++++++++++++++++ plugins/spell/pluma-spell-plugin.h | 75 ++ plugins/spell/pluma-spell-utils.c | 94 ++ plugins/spell/pluma-spell-utils.h | 37 + plugins/spell/spell.gedit-plugin.desktop.in | 9 - plugins/spell/spell.pluma-plugin.desktop.in | 9 + 33 files changed, 4858 insertions(+), 4858 deletions(-) delete mode 100755 plugins/spell/gedit-automatic-spell-checker.c delete mode 100755 plugins/spell/gedit-automatic-spell-checker.h delete mode 100755 plugins/spell/gedit-spell-checker-dialog.c delete mode 100755 plugins/spell/gedit-spell-checker-dialog.h delete mode 100755 plugins/spell/gedit-spell-checker-language.c delete mode 100755 plugins/spell/gedit-spell-checker-language.h delete mode 100755 plugins/spell/gedit-spell-checker.c delete mode 100755 plugins/spell/gedit-spell-checker.h delete mode 100755 plugins/spell/gedit-spell-language-dialog.c delete mode 100755 plugins/spell/gedit-spell-language-dialog.h delete mode 100755 plugins/spell/gedit-spell-marshal.list delete mode 100755 plugins/spell/gedit-spell-plugin.c delete mode 100755 plugins/spell/gedit-spell-plugin.h delete mode 100755 plugins/spell/gedit-spell-utils.c delete mode 100755 plugins/spell/gedit-spell-utils.h create mode 100755 plugins/spell/pluma-automatic-spell-checker.c create mode 100755 plugins/spell/pluma-automatic-spell-checker.h create mode 100755 plugins/spell/pluma-spell-checker-dialog.c create mode 100755 plugins/spell/pluma-spell-checker-dialog.h create mode 100755 plugins/spell/pluma-spell-checker-language.c create mode 100755 plugins/spell/pluma-spell-checker-language.h create mode 100755 plugins/spell/pluma-spell-checker.c create mode 100755 plugins/spell/pluma-spell-checker.h create mode 100755 plugins/spell/pluma-spell-language-dialog.c create mode 100755 plugins/spell/pluma-spell-language-dialog.h create mode 100755 plugins/spell/pluma-spell-marshal.list create mode 100755 plugins/spell/pluma-spell-plugin.c create mode 100755 plugins/spell/pluma-spell-plugin.h create mode 100755 plugins/spell/pluma-spell-utils.c create mode 100755 plugins/spell/pluma-spell-utils.h delete mode 100755 plugins/spell/spell.gedit-plugin.desktop.in create mode 100755 plugins/spell/spell.pluma-plugin.desktop.in (limited to 'plugins/spell') diff --git a/plugins/spell/Makefile.am b/plugins/spell/Makefile.am index 9d332f95..24299165 100755 --- a/plugins/spell/Makefile.am +++ b/plugins/spell/Makefile.am @@ -1,59 +1,59 @@ # Spell checker plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(ENCHANT_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) BUILT_SOURCES = \ - gedit-spell-marshal.c \ - gedit-spell-marshal.h + pluma-spell-marshal.c \ + pluma-spell-marshal.h plugin_LTLIBRARIES = libspell.la libspell_la_SOURCES = \ - gedit-spell-plugin.c \ - gedit-spell-plugin.h \ - gedit-spell-checker.c \ - gedit-spell-checker.h \ - gedit-spell-checker-dialog.c \ - gedit-spell-checker-dialog.h \ - gedit-spell-checker-language.c \ - gedit-spell-checker-language.h \ - gedit-spell-language-dialog.c \ - gedit-spell-language-dialog.h \ - gedit-automatic-spell-checker.c \ - gedit-automatic-spell-checker.h \ - gedit-spell-utils.c \ - gedit-spell-utils.h \ + pluma-spell-plugin.c \ + pluma-spell-plugin.h \ + pluma-spell-checker.c \ + pluma-spell-checker.h \ + pluma-spell-checker-dialog.c \ + pluma-spell-checker-dialog.h \ + pluma-spell-checker-language.c \ + pluma-spell-checker-language.h \ + pluma-spell-language-dialog.c \ + pluma-spell-language-dialog.h \ + pluma-automatic-spell-checker.c \ + pluma-automatic-spell-checker.h \ + pluma-spell-utils.c \ + pluma-spell-utils.h \ $(BUILT_SOURCES) libspell_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libspell_la_LIBADD = $(GEDIT_LIBS) $(ENCHANT_LIBS) +libspell_la_LIBADD = $(PLUMA_LIBS) $(ENCHANT_LIBS) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/spell +uidir = $(PLUMA_PLUGINS_DATA_DIR)/spell ui_DATA = spell-checker.ui languages-dialog.ui -gedit-spell-marshal.h: gedit-spell-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=gedit_marshal > $@ +pluma-spell-marshal.h: pluma-spell-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=pluma_marshal > $@ -gedit-spell-marshal.c: gedit-spell-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) echo "#include \"gedit-spell-marshal.h\"" > $@ && \ - $(GLIB_GENMARSHAL) $< --body --prefix=gedit_marshal >> $@ +pluma-spell-marshal.c: pluma-spell-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) echo "#include \"pluma-spell-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=pluma_marshal >> $@ -plugin_in_files = spell.gedit-plugin.desktop.in +plugin_in_files = spell.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = \ $(ui_DATA) \ $(plugin_in_files) \ - gedit-spell-marshal.list + pluma-spell-marshal.list CLEANFILES = $(BUILT_SOURCES) $(plugin_DATA) diff --git a/plugins/spell/gedit-automatic-spell-checker.c b/plugins/spell/gedit-automatic-spell-checker.c deleted file mode 100755 index 96b2fae9..00000000 --- a/plugins/spell/gedit-automatic-spell-checker.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-automatic-spell-checker.c - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -/* This is a modified version of gtkspell 2.0.5 (gtkspell.sf.net) */ -/* gtkspell - a spell-checking addon for GTK's TextView widget - * Copyright (c) 2002 Evan Martin. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include "gedit-automatic-spell-checker.h" -#include "gedit-spell-utils.h" - -struct _GeditAutomaticSpellChecker { - GeditDocument *doc; - GSList *views; - - GtkTextMark *mark_insert_start; - GtkTextMark *mark_insert_end; - gboolean deferred_check; - - GtkTextTag *tag_highlight; - GtkTextMark *mark_click; - - GeditSpellChecker *spell_checker; -}; - -static GQuark automatic_spell_checker_id = 0; -static GQuark suggestion_id = 0; - -static void gedit_automatic_spell_checker_free_internal (GeditAutomaticSpellChecker *spell); - -static void -view_destroy (GeditView *view, GeditAutomaticSpellChecker *spell) -{ - gedit_automatic_spell_checker_detach_view (spell, view); -} - -static void -check_word (GeditAutomaticSpellChecker *spell, GtkTextIter *start, GtkTextIter *end) -{ - gchar *word; - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), start, end, FALSE); - - /* - g_print ("Check word: %s [%d - %d]\n", word, gtk_text_iter_get_offset (start), - gtk_text_iter_get_offset (end)); - */ - - if (!gedit_spell_checker_check_word (spell->spell_checker, word, -1)) - { - /* - g_print ("Apply tag: [%d - %d]\n", gtk_text_iter_get_offset (start), - gtk_text_iter_get_offset (end)); - */ - gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - start, - end); - } - - g_free (word); -} - -static void -check_range (GeditAutomaticSpellChecker *spell, - GtkTextIter start, - GtkTextIter end, - gboolean force_all) -{ - /* we need to "split" on word boundaries. - * luckily, Pango knows what "words" are - * so we don't have to figure it out. */ - - GtkTextIter wstart; - GtkTextIter wend; - GtkTextIter cursor; - GtkTextIter precursor; - gboolean highlight; - - /* - g_print ("Check range: [%d - %d]\n", gtk_text_iter_get_offset (&start), - gtk_text_iter_get_offset (&end)); - */ - - if (gtk_text_iter_inside_word (&end)) - gtk_text_iter_forward_word_end (&end); - - if (!gtk_text_iter_starts_word (&start)) - { - if (gtk_text_iter_inside_word (&start) || - gtk_text_iter_ends_word (&start)) - { - gtk_text_iter_backward_word_start (&start); - } - else - { - /* if we're neither at the beginning nor inside a word, - * me must be in some spaces. - * skip forward to the beginning of the next word. */ - - if (gtk_text_iter_forward_word_end (&start)) - gtk_text_iter_backward_word_start (&start); - } - } - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), - &cursor, - gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (spell->doc))); - - precursor = cursor; - gtk_text_iter_backward_char (&precursor); - - highlight = gtk_text_iter_has_tag (&cursor, spell->tag_highlight) || - gtk_text_iter_has_tag (&precursor, spell->tag_highlight); - - gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - &start, - &end); - - /* Fix a corner case when replacement occurs at beginning of buffer: - * An iter at offset 0 seems to always be inside a word, - * even if it's not. Possibly a pango bug. - */ - if (gtk_text_iter_get_offset (&start) == 0) - { - gtk_text_iter_forward_word_end(&start); - gtk_text_iter_backward_word_start(&start); - } - - wstart = start; - - while (gedit_spell_utils_skip_no_spell_check (&wstart, &end) && - gtk_text_iter_compare (&wstart, &end) < 0) - { - gboolean inword; - - /* move wend to the end of the current word. */ - wend = wstart; - - gtk_text_iter_forward_word_end (&wend); - - inword = (gtk_text_iter_compare (&wstart, &cursor) < 0) && - (gtk_text_iter_compare (&cursor, &wend) <= 0); - - if (inword && !force_all) - { - /* this word is being actively edited, - * only check if it's already highligted, - * otherwise defer this check until later. */ - if (highlight) - check_word (spell, &wstart, &wend); - else - spell->deferred_check = TRUE; - } - else - { - check_word (spell, &wstart, &wend); - spell->deferred_check = FALSE; - } - - /* now move wend to the beginning of the next word, */ - gtk_text_iter_forward_word_end (&wend); - gtk_text_iter_backward_word_start (&wend); - - /* make sure we've actually advanced - * (we don't advance in some corner cases), */ - if (gtk_text_iter_equal (&wstart, &wend)) - break; /* we're done in these cases.. */ - - /* and then pick this as the new next word beginning. */ - wstart = wend; - } -} - -static void -check_deferred_range (GeditAutomaticSpellChecker *spell, - gboolean force_all) -{ - GtkTextIter start, end; - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), - &start, - spell->mark_insert_start); - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), - &end, - spell->mark_insert_end); - - check_range (spell, start, end, force_all); -} - -/* insertion works like this: - * - before the text is inserted, we mark the position in the buffer. - * - after the text is inserted, we see where our mark is and use that and - * the current position to check the entire range of inserted text. - * - * this may be overkill for the common case (inserting one character). */ - -static void -insert_text_before (GtkTextBuffer *buffer, GtkTextIter *iter, - gchar *text, gint len, GeditAutomaticSpellChecker *spell) -{ - gtk_text_buffer_move_mark (buffer, spell->mark_insert_start, iter); -} - -static void -insert_text_after (GtkTextBuffer *buffer, GtkTextIter *iter, - gchar *text, gint len, GeditAutomaticSpellChecker *spell) -{ - GtkTextIter start; - - /* we need to check a range of text. */ - gtk_text_buffer_get_iter_at_mark (buffer, &start, spell->mark_insert_start); - - check_range (spell, start, *iter, FALSE); - - gtk_text_buffer_move_mark (buffer, spell->mark_insert_end, iter); -} - -/* deleting is more simple: we're given the range of deleted text. - * after deletion, the start and end iters should be at the same position - * (because all of the text between them was deleted!). - * this means we only really check the words immediately bounding the - * deletion. - */ - -static void -delete_range_after (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, - GeditAutomaticSpellChecker *spell) -{ - check_range (spell, *start, *end, FALSE); -} - -static void -mark_set (GtkTextBuffer *buffer, - GtkTextIter *iter, - GtkTextMark *mark, - GeditAutomaticSpellChecker *spell) -{ - /* if the cursor has moved and there is a deferred check so handle it now */ - if ((mark == gtk_text_buffer_get_insert (buffer)) && spell->deferred_check) - check_deferred_range (spell, FALSE); -} - -static void -get_word_extents_from_mark (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - GtkTextMark *mark) -{ - gtk_text_buffer_get_iter_at_mark(buffer, start, mark); - - if (!gtk_text_iter_starts_word (start)) - gtk_text_iter_backward_word_start (start); - - *end = *start; - - if (gtk_text_iter_inside_word (end)) - gtk_text_iter_forward_word_end (end); -} - -static void -remove_tag_to_word (GeditAutomaticSpellChecker *spell, const gchar *word) -{ - GtkTextIter iter; - GtkTextIter match_start, match_end; - - gboolean found; - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (spell->doc), &iter, 0); - - found = TRUE; - - while (found) - { - found = gtk_text_iter_forward_search (&iter, - word, - GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY, - &match_start, - &match_end, - NULL); - - if (found) - { - if (gtk_text_iter_starts_word (&match_start) && - gtk_text_iter_ends_word (&match_end)) - { - gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - &match_start, - &match_end); - } - - iter = match_end; - } - } -} - -static void -add_to_dictionary (GtkWidget *menuitem, GeditAutomaticSpellChecker *spell) -{ - gchar *word; - - GtkTextIter start, end; - - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), - &start, - &end, - FALSE); - - gedit_spell_checker_add_word_to_personal (spell->spell_checker, word, -1); - - g_free (word); -} - -static void -ignore_all (GtkWidget *menuitem, GeditAutomaticSpellChecker *spell) -{ - gchar *word; - - GtkTextIter start, end; - - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), - &start, - &end, - FALSE); - - gedit_spell_checker_add_word_to_session (spell->spell_checker, word, -1); - - g_free (word); -} - -static void -replace_word (GtkWidget *menuitem, GeditAutomaticSpellChecker *spell) -{ - gchar *oldword; - const gchar *newword; - - GtkTextIter start, end; - - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - oldword = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); - - newword = g_object_get_qdata (G_OBJECT (menuitem), suggestion_id); - g_return_if_fail (newword != NULL); - - gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (spell->doc)); - - gtk_text_buffer_delete (GTK_TEXT_BUFFER (spell->doc), &start, &end); - gtk_text_buffer_insert (GTK_TEXT_BUFFER (spell->doc), &start, newword, -1); - - gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (spell->doc)); - - gedit_spell_checker_set_correction (spell->spell_checker, - oldword, strlen (oldword), - newword, strlen (newword)); - - g_free (oldword); -} - -static GtkWidget * -build_suggestion_menu (GeditAutomaticSpellChecker *spell, const gchar *word) -{ - GtkWidget *topmenu, *menu; - GtkWidget *mi; - GSList *suggestions; - GSList *list; - gchar *label_text; - - topmenu = menu = gtk_menu_new(); - - suggestions = gedit_spell_checker_get_suggestions (spell->spell_checker, word, -1); - - list = suggestions; - - if (suggestions == NULL) - { - /* no suggestions. put something in the menu anyway... */ - GtkWidget *label; - /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions for the current misspelled word */ - label = gtk_label_new (_("(no suggested words)")); - - mi = gtk_menu_item_new (); - gtk_widget_set_sensitive (mi, FALSE); - gtk_container_add (GTK_CONTAINER(mi), label); - gtk_widget_show_all (mi); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); - } - else - { - gint count = 0; - - /* build a set of menus with suggestions. */ - while (suggestions != NULL) - { - GtkWidget *label; - - if (count == 10) - { - /* Separator */ - mi = gtk_menu_item_new (); - gtk_widget_show (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - - mi = gtk_menu_item_new_with_mnemonic (_("_More...")); - gtk_widget_show (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - - menu = gtk_menu_new (); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu); - count = 0; - } - - label_text = g_strdup_printf ("%s", (gchar*) suggestions->data); - - label = gtk_label_new (label_text); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - - mi = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER(mi), label); - - gtk_widget_show_all (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - - g_object_set_qdata_full (G_OBJECT (mi), - suggestion_id, - g_strdup (suggestions->data), - (GDestroyNotify)g_free); - - g_free (label_text); - g_signal_connect (mi, - "activate", - G_CALLBACK (replace_word), - spell); - - count++; - - suggestions = g_slist_next (suggestions); - } - } - - /* free the suggestion list */ - suggestions = list; - - while (list) - { - g_free (list->data); - list = g_slist_next (list); - } - - g_slist_free (suggestions); - - /* Separator */ - mi = gtk_menu_item_new (); - gtk_widget_show (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); - - /* Ignore all */ - mi = gtk_image_menu_item_new_with_mnemonic (_("_Ignore All")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), - gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, - GTK_ICON_SIZE_MENU)); - - g_signal_connect (mi, - "activate", - G_CALLBACK(ignore_all), - spell); - - gtk_widget_show_all (mi); - - gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); - - /* + Add to Dictionary */ - mi = gtk_image_menu_item_new_with_mnemonic (_("_Add")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), - gtk_image_new_from_stock (GTK_STOCK_ADD, - GTK_ICON_SIZE_MENU)); - - g_signal_connect (mi, - "activate", - G_CALLBACK (add_to_dictionary), - spell); - - gtk_widget_show_all (mi); - - gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); - - return topmenu; -} - -static void -populate_popup (GtkTextView *textview, GtkMenu *menu, GeditAutomaticSpellChecker *spell) -{ - GtkWidget *img, *mi; - GtkTextIter start, end; - char *word; - - /* we need to figure out if they picked a misspelled word. */ - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - /* if our highlight algorithm ever messes up, - * this isn't correct, either. */ - if (!gtk_text_iter_has_tag (&start, spell->tag_highlight)) - return; /* word wasn't misspelled. */ - - /* menu separator comes first. */ - mi = gtk_menu_item_new (); - gtk_widget_show (mi); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); - - /* then, on top of it, the suggestions menu. */ - img = gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_mnemonic (_("_Spelling Suggestions...")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img); - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), - build_suggestion_menu (spell, word)); - g_free(word); - - gtk_widget_show_all (mi); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); -} - -void -gedit_automatic_spell_checker_recheck_all (GeditAutomaticSpellChecker *spell) -{ - GtkTextIter start, end; - - g_return_if_fail (spell != NULL); - - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end); - - check_range (spell, start, end, TRUE); -} - -static void -add_word_signal_cb (GeditSpellChecker *checker, - const gchar *word, - gint len, - GeditAutomaticSpellChecker *spell) -{ - gchar *w; - - if (len < 0) - w = g_strdup (word); - else - w = g_strndup (word, len); - - remove_tag_to_word (spell, w); - - g_free (w); -} - -static void -set_language_cb (GeditSpellChecker *checker, - const GeditSpellCheckerLanguage *lang, - GeditAutomaticSpellChecker *spell) -{ - gedit_automatic_spell_checker_recheck_all (spell); -} - -static void -clear_session_cb (GeditSpellChecker *checker, - GeditAutomaticSpellChecker *spell) -{ - gedit_automatic_spell_checker_recheck_all (spell); -} - -/* When the user right-clicks on a word, they want to check that word. - * Here, we do NOT move the cursor to the location of the clicked-upon word - * since that prevents the use of edit functions on the context menu. - */ -static gboolean -button_press_event (GtkTextView *view, - GdkEventButton *event, - GeditAutomaticSpellChecker *spell) -{ - if (event->button == 3) - { - gint x, y; - GtkTextIter iter; - - GtkTextBuffer *buffer = gtk_text_view_get_buffer (view); - - /* handle deferred check if it exists */ - if (spell->deferred_check) - check_deferred_range (spell, TRUE); - - gtk_text_view_window_to_buffer_coords (view, - GTK_TEXT_WINDOW_TEXT, - event->x, event->y, - &x, &y); - - gtk_text_view_get_iter_at_location (view, &iter, x, y); - - gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); - } - - return FALSE; /* false: let gtk process this event, too. - we don't want to eat any events. */ -} - -/* Move the insert mark before popping up the menu, otherwise it - * will contain the wrong set of suggestions. - */ -static gboolean -popup_menu_event (GtkTextView *view, GeditAutomaticSpellChecker *spell) -{ - GtkTextIter iter; - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (view); - - /* handle deferred check if it exists */ - if (spell->deferred_check) - check_deferred_range (spell, TRUE); - - gtk_text_buffer_get_iter_at_mark (buffer, &iter, - gtk_text_buffer_get_insert (buffer)); - gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); - - return FALSE; -} - -static void -tag_table_changed (GtkTextTagTable *table, - GeditAutomaticSpellChecker *spell) -{ - g_return_if_fail (spell->tag_highlight != NULL); - - gtk_text_tag_set_priority (spell->tag_highlight, - gtk_text_tag_table_get_size (table) - 1); -} - -static void -tag_added_or_removed (GtkTextTagTable *table, - GtkTextTag *tag, - GeditAutomaticSpellChecker *spell) -{ - tag_table_changed (table, spell); -} - -static void -tag_changed (GtkTextTagTable *table, - GtkTextTag *tag, - gboolean size_changed, - GeditAutomaticSpellChecker *spell) -{ - tag_table_changed (table, spell); -} - -static void -highlight_updated (GtkSourceBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - GeditAutomaticSpellChecker *spell) -{ - check_range (spell, *start, *end, FALSE); -} - -static void -spell_tag_destroyed (GeditAutomaticSpellChecker *spell, - GObject *where_the_object_was) -{ - spell->tag_highlight = NULL; -} - -GeditAutomaticSpellChecker * -gedit_automatic_spell_checker_new (GeditDocument *doc, - GeditSpellChecker *checker) -{ - GeditAutomaticSpellChecker *spell; - GtkTextTagTable *tag_table; - GtkTextIter start, end; - - g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL); - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (checker), NULL); - g_return_val_if_fail ((spell = gedit_automatic_spell_checker_get_from_document (doc)) == NULL, - spell); - - /* attach to the widget */ - spell = g_new0 (GeditAutomaticSpellChecker, 1); - - spell->doc = doc; - spell->spell_checker = g_object_ref (checker); - - if (automatic_spell_checker_id == 0) - { - automatic_spell_checker_id = - g_quark_from_string ("GeditAutomaticSpellCheckerID"); - } - if (suggestion_id == 0) - { - suggestion_id = g_quark_from_string ("GeditAutoSuggestionID"); - } - - g_object_set_qdata_full (G_OBJECT (doc), - automatic_spell_checker_id, - spell, - (GDestroyNotify)gedit_automatic_spell_checker_free_internal); - - g_signal_connect (doc, - "insert-text", - G_CALLBACK (insert_text_before), - spell); - g_signal_connect_after (doc, - "insert-text", - G_CALLBACK (insert_text_after), - spell); - g_signal_connect_after (doc, - "delete-range", - G_CALLBACK (delete_range_after), - spell); - g_signal_connect (doc, - "mark-set", - G_CALLBACK (mark_set), - spell); - - g_signal_connect (doc, - "highlight-updated", - G_CALLBACK (highlight_updated), - spell); - - g_signal_connect (spell->spell_checker, - "add_word_to_session", - G_CALLBACK (add_word_signal_cb), - spell); - g_signal_connect (spell->spell_checker, - "add_word_to_personal", - G_CALLBACK (add_word_signal_cb), - spell); - g_signal_connect (spell->spell_checker, - "clear_session", - G_CALLBACK (clear_session_cb), - spell); - g_signal_connect (spell->spell_checker, - "set_language", - G_CALLBACK (set_language_cb), - spell); - - spell->tag_highlight = gtk_text_buffer_create_tag ( - GTK_TEXT_BUFFER (doc), - "gtkspell-misspelled", - "underline", PANGO_UNDERLINE_ERROR, - NULL); - - g_object_weak_ref (G_OBJECT (spell->tag_highlight), - (GWeakNotify)spell_tag_destroyed, - spell); - - tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (doc)); - - gtk_text_tag_set_priority (spell->tag_highlight, - gtk_text_tag_table_get_size (tag_table) - 1); - - g_signal_connect (tag_table, - "tag-added", - G_CALLBACK (tag_added_or_removed), - spell); - g_signal_connect (tag_table, - "tag-removed", - G_CALLBACK (tag_added_or_removed), - spell); - g_signal_connect (tag_table, - "tag-changed", - G_CALLBACK (tag_changed), - spell); - - /* we create the mark here, but we don't use it until text is - * inserted, so we don't really care where iter points. */ - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end); - - spell->mark_insert_start = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-start"); - - if (spell->mark_insert_start == NULL) - { - spell->mark_insert_start = - gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-start", - &start, - TRUE); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - spell->mark_insert_start, - &start); - } - - spell->mark_insert_end = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-end"); - - if (spell->mark_insert_end == NULL) - { - spell->mark_insert_end = - gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-end", - &start, - TRUE); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - spell->mark_insert_end, - &start); - } - - spell->mark_click = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-click"); - - if (spell->mark_click == NULL) - { - spell->mark_click = - gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-click", - &start, - TRUE); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - spell->mark_click, - &start); - } - - spell->deferred_check = FALSE; - - return spell; -} - -GeditAutomaticSpellChecker * -gedit_automatic_spell_checker_get_from_document (const GeditDocument *doc) -{ - g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL); - - if (automatic_spell_checker_id == 0) - return NULL; - - return g_object_get_qdata (G_OBJECT (doc), automatic_spell_checker_id); -} - -void -gedit_automatic_spell_checker_free (GeditAutomaticSpellChecker *spell) -{ - g_return_if_fail (spell != NULL); - g_return_if_fail (gedit_automatic_spell_checker_get_from_document (spell->doc) == spell); - - if (automatic_spell_checker_id == 0) - return; - - g_object_set_qdata (G_OBJECT (spell->doc), automatic_spell_checker_id, NULL); -} - -static void -gedit_automatic_spell_checker_free_internal (GeditAutomaticSpellChecker *spell) -{ - GtkTextTagTable *table; - GtkTextIter start, end; - GSList *list; - - g_return_if_fail (spell != NULL); - - table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (spell->doc)); - - if (table != NULL && spell->tag_highlight != NULL) - { - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), - &start, - &end); - gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - &start, - &end); - - g_signal_handlers_disconnect_matched (G_OBJECT (table), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - gtk_text_tag_table_remove (table, spell->tag_highlight); - } - - g_signal_handlers_disconnect_matched (G_OBJECT (spell->doc), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_signal_handlers_disconnect_matched (G_OBJECT (spell->spell_checker), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_object_unref (spell->spell_checker); - - list = spell->views; - while (list != NULL) - { - GeditView *view = GEDIT_VIEW (list->data); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - list = g_slist_next (list); - } - - g_slist_free (spell->views); - - g_free (spell); -} - -void -gedit_automatic_spell_checker_attach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view) -{ - g_return_if_fail (spell != NULL); - g_return_if_fail (GEDIT_IS_VIEW (view)); - - g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == - GTK_TEXT_BUFFER (spell->doc)); - - g_signal_connect (view, - "button-press-event", - G_CALLBACK (button_press_event), - spell); - g_signal_connect (view, - "popup-menu", - G_CALLBACK (popup_menu_event), - spell); - g_signal_connect (view, - "populate-popup", - G_CALLBACK (populate_popup), - spell); - g_signal_connect (view, - "destroy", - G_CALLBACK (view_destroy), - spell); - - spell->views = g_slist_prepend (spell->views, view); -} - -void -gedit_automatic_spell_checker_detach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view) -{ - g_return_if_fail (spell != NULL); - g_return_if_fail (GEDIT_IS_VIEW (view)); - - g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == - GTK_TEXT_BUFFER (spell->doc)); - g_return_if_fail (spell->views != NULL); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - spell->views = g_slist_remove (spell->views, view); -} - diff --git a/plugins/spell/gedit-automatic-spell-checker.h b/plugins/spell/gedit-automatic-spell-checker.h deleted file mode 100755 index cc634424..00000000 --- a/plugins/spell/gedit-automatic-spell-checker.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-automatic-spell-checker.h - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -/* This is a modified version of gtkspell 2.0.2 (gtkspell.sf.net) */ -/* gtkspell - a spell-checking addon for GTK's TextView widget - * Copyright (c) 2002 Evan Martin. - */ - -#ifndef __GEDIT_AUTOMATIC_SPELL_CHECKER_H__ -#define __GEDIT_AUTOMATIC_SPELL_CHECKER_H__ - -#include -#include - -#include "gedit-spell-checker.h" - -typedef struct _GeditAutomaticSpellChecker GeditAutomaticSpellChecker; - -GeditAutomaticSpellChecker *gedit_automatic_spell_checker_new ( - GeditDocument *doc, - GeditSpellChecker *checker); - -GeditAutomaticSpellChecker *gedit_automatic_spell_checker_get_from_document ( - const GeditDocument *doc); - -void gedit_automatic_spell_checker_free ( - GeditAutomaticSpellChecker *spell); - -void gedit_automatic_spell_checker_attach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view); - -void gedit_automatic_spell_checker_detach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view); - -void gedit_automatic_spell_checker_recheck_all ( - GeditAutomaticSpellChecker *spell); - -#endif /* __GEDIT_AUTOMATIC_SPELL_CHECKER_H__ */ - diff --git a/plugins/spell/gedit-spell-checker-dialog.c b/plugins/spell/gedit-spell-checker-dialog.c deleted file mode 100755 index 0488d160..00000000 --- a/plugins/spell/gedit-spell-checker-dialog.c +++ /dev/null @@ -1,722 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-dialog.c - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include "gedit-spell-checker-dialog.h" -#include "gedit-spell-marshal.h" - -struct _GeditSpellCheckerDialog -{ - GtkWindow parent_instance; - - GeditSpellChecker *spell_checker; - - gchar *misspelled_word; - - GtkWidget *misspelled_word_label; - GtkWidget *word_entry; - GtkWidget *check_word_button; - GtkWidget *ignore_button; - GtkWidget *ignore_all_button; - GtkWidget *change_button; - GtkWidget *change_all_button; - GtkWidget *add_word_button; - GtkWidget *close_button; - GtkWidget *suggestions_list; - GtkWidget *language_label; - - GtkTreeModel *suggestions_list_model; -}; - -enum -{ - IGNORE, - IGNORE_ALL, - CHANGE, - CHANGE_ALL, - ADD_WORD_TO_PERSONAL, - LAST_SIGNAL -}; - -enum -{ - COLUMN_SUGGESTIONS, - NUM_COLUMNS -}; - -static void update_suggestions_list_model (GeditSpellCheckerDialog *dlg, - GSList *suggestions); - -static void word_entry_changed_handler (GtkEditable *editable, - GeditSpellCheckerDialog *dlg); -static void close_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void suggestions_list_selection_changed_handler (GtkTreeSelection *selection, - GeditSpellCheckerDialog *dlg); -static void check_word_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void add_word_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void ignore_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void ignore_all_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void change_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void change_all_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void suggestions_list_row_activated_handler (GtkTreeView *view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditSpellCheckerDialog *dlg); - - -static guint signals [LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(GeditSpellCheckerDialog, gedit_spell_checker_dialog, GTK_TYPE_WINDOW) - -static void -gedit_spell_checker_dialog_destroy (GtkObject *object) -{ - GeditSpellCheckerDialog *dlg = GEDIT_SPELL_CHECKER_DIALOG (object); - - if (dlg->spell_checker != NULL) - { - g_object_unref (dlg->spell_checker); - dlg->spell_checker = NULL; - } - - if (dlg->misspelled_word != NULL) - { - g_free (dlg->misspelled_word); - dlg->misspelled_word = NULL; - } - - GTK_OBJECT_CLASS (gedit_spell_checker_dialog_parent_class)->destroy (object); -} - -static void -gedit_spell_checker_dialog_class_init (GeditSpellCheckerDialogClass * klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - GTK_OBJECT_CLASS (object_class)->destroy = gedit_spell_checker_dialog_destroy; - - signals[IGNORE] = - g_signal_new ("ignore", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, ignore), - NULL, NULL, - gedit_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - signals[IGNORE_ALL] = - g_signal_new ("ignore_all", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, ignore_all), - NULL, NULL, - gedit_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - signals[CHANGE] = - g_signal_new ("change", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, change), - NULL, NULL, - gedit_marshal_VOID__STRING_STRING, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_STRING); - - signals[CHANGE_ALL] = - g_signal_new ("change_all", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, change_all), - NULL, NULL, - gedit_marshal_VOID__STRING_STRING, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_STRING); - - signals[ADD_WORD_TO_PERSONAL] = - g_signal_new ("add_word_to_personal", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, add_word_to_personal), - NULL, NULL, - gedit_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); -} - -static void -create_dialog (GeditSpellCheckerDialog *dlg, - const gchar *data_dir) -{ - GtkWidget *error_widget; - GtkWidget *content; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - GtkTreeSelection *selection; - gchar *root_objects[] = { - "content", - "check_word_image", - "add_word_image", - "ignore_image", - "change_image", - "ignore_all_image", - "change_all_image", - NULL - }; - gboolean ret; - gchar *ui_file; - - g_return_if_fail (dlg != NULL); - - dlg->spell_checker = NULL; - dlg->misspelled_word = NULL; - - ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - root_objects, - &error_widget, - - "content", &content, - "misspelled_word_label", &dlg->misspelled_word_label, - "word_entry", &dlg->word_entry, - "check_word_button", &dlg->check_word_button, - "ignore_button", &dlg->ignore_button, - "ignore_all_button", &dlg->ignore_all_button, - "change_button", &dlg->change_button, - "change_all_button", &dlg->change_all_button, - "add_word_button", &dlg->add_word_button, - "close_button", &dlg->close_button, - "suggestions_list", &dlg->suggestions_list, - "language_label", &dlg->language_label, - NULL); - g_free (ui_file); - - if (!ret) - { - gtk_widget_show (error_widget); - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - error_widget, TRUE, TRUE, 0); - - return; - } - - gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), ""); - gtk_widget_set_sensitive (dlg->word_entry, FALSE); - gtk_widget_set_sensitive (dlg->check_word_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); - gtk_widget_set_sensitive (dlg->change_button, FALSE); - gtk_widget_set_sensitive (dlg->change_all_button, FALSE); - gtk_widget_set_sensitive (dlg->add_word_button, FALSE); - - gtk_label_set_label (GTK_LABEL (dlg->language_label), ""); - - gtk_container_add (GTK_CONTAINER (dlg), content); - g_object_unref (content); - - gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE); - gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling")); - - /* Suggestion list */ - dlg->suggestions_list_model = GTK_TREE_MODEL ( - gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING)); - - gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list), - dlg->suggestions_list_model); - - /* Add the suggestions column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell, - "text", COLUMN_SUGGESTIONS, NULL); - - gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column); - - gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list), - COLUMN_SUGGESTIONS); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); - - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - /* Set default button */ - GTK_WIDGET_SET_FLAGS (dlg->change_button, GTK_CAN_DEFAULT); - gtk_widget_grab_default (dlg->change_button); - - gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE); - - /* Connect signals */ - g_signal_connect (dlg->word_entry, "changed", - G_CALLBACK (word_entry_changed_handler), dlg); - g_signal_connect (dlg->close_button, "clicked", - G_CALLBACK (close_button_clicked_handler), dlg); - g_signal_connect (selection, "changed", - G_CALLBACK (suggestions_list_selection_changed_handler), - dlg); - g_signal_connect (dlg->check_word_button, "clicked", - G_CALLBACK (check_word_button_clicked_handler), dlg); - g_signal_connect (dlg->add_word_button, "clicked", - G_CALLBACK (add_word_button_clicked_handler), dlg); - g_signal_connect (dlg->ignore_button, "clicked", - G_CALLBACK (ignore_button_clicked_handler), dlg); - g_signal_connect (dlg->ignore_all_button, "clicked", - G_CALLBACK (ignore_all_button_clicked_handler), dlg); - g_signal_connect (dlg->change_button, "clicked", - G_CALLBACK (change_button_clicked_handler), dlg); - g_signal_connect (dlg->change_all_button, "clicked", - G_CALLBACK (change_all_button_clicked_handler), dlg); - g_signal_connect (dlg->suggestions_list, "row-activated", - G_CALLBACK (suggestions_list_row_activated_handler), dlg); -} - -static void -gedit_spell_checker_dialog_init (GeditSpellCheckerDialog *dlg) -{ -} - -GtkWidget * -gedit_spell_checker_dialog_new (const gchar *data_dir) -{ - GeditSpellCheckerDialog *dlg; - - dlg = GEDIT_SPELL_CHECKER_DIALOG ( - g_object_new (GEDIT_TYPE_SPELL_CHECKER_DIALOG, NULL)); - - g_return_val_if_fail (dlg != NULL, NULL); - - create_dialog (dlg, data_dir); - - return GTK_WIDGET (dlg); -} - -GtkWidget * -gedit_spell_checker_dialog_new_from_spell_checker (GeditSpellChecker *spell, - const gchar *data_dir) -{ - GeditSpellCheckerDialog *dlg; - - g_return_val_if_fail (spell != NULL, NULL); - - dlg = GEDIT_SPELL_CHECKER_DIALOG ( - g_object_new (GEDIT_TYPE_SPELL_CHECKER_DIALOG, NULL)); - - g_return_val_if_fail (dlg != NULL, NULL); - - create_dialog (dlg, data_dir); - - gedit_spell_checker_dialog_set_spell_checker (dlg, spell); - - return GTK_WIDGET (dlg); -} - -void -gedit_spell_checker_dialog_set_spell_checker (GeditSpellCheckerDialog *dlg, GeditSpellChecker *spell) -{ - const GeditSpellCheckerLanguage* language; - const gchar *lang; - gchar *tmp; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (spell != NULL); - - if (dlg->spell_checker != NULL) - g_object_unref (dlg->spell_checker); - - dlg->spell_checker = spell; - g_object_ref (dlg->spell_checker); - - language = gedit_spell_checker_get_language (dlg->spell_checker); - - lang = gedit_spell_checker_language_to_string (language); - tmp = g_strdup_printf("%s", lang); - - gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp); - g_free (tmp); - - if (dlg->misspelled_word != NULL) - gedit_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1); - else - gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); - - /* TODO: reset all widgets */ -} - -void -gedit_spell_checker_dialog_set_misspelled_word (GeditSpellCheckerDialog *dlg, - const gchar *word, - gint len) -{ - gchar *tmp; - GSList *sug; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (word != NULL); - - g_return_if_fail (dlg->spell_checker != NULL); - g_return_if_fail (!gedit_spell_checker_check_word (dlg->spell_checker, word, -1)); - - /* build_suggestions_list */ - if (dlg->misspelled_word != NULL) - g_free (dlg->misspelled_word); - - dlg->misspelled_word = g_strdup (word); - - tmp = g_strdup_printf("%s", word); - gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp); - g_free (tmp); - - sug = gedit_spell_checker_get_suggestions (dlg->spell_checker, - dlg->misspelled_word, - -1); - - update_suggestions_list_model (dlg, sug); - - /* free the suggestion list */ - g_slist_foreach (sug, (GFunc)g_free, NULL); - g_slist_free (sug); - - gtk_widget_set_sensitive (dlg->ignore_button, TRUE); - gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE); - gtk_widget_set_sensitive (dlg->add_word_button, TRUE); -} - -static void -update_suggestions_list_model (GeditSpellCheckerDialog *dlg, GSList *suggestions) -{ - GtkListStore *store; - GtkTreeIter iter; - GtkTreeSelection *sel; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model)); - - store = GTK_LIST_STORE (dlg->suggestions_list_model); - gtk_list_store_clear (store); - - gtk_widget_set_sensitive (dlg->word_entry, TRUE); - - if (suggestions == NULL) - { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions - * for the current misspelled word */ - COLUMN_SUGGESTIONS, _("(no suggested words)"), - -1); - - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); - - gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); - - return; - } - - gtk_widget_set_sensitive (dlg->suggestions_list, TRUE); - - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data); - - while (suggestions != NULL) - { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COLUMN_SUGGESTIONS, (gchar*)suggestions->data, - -1); - - suggestions = g_slist_next (suggestions); - } - - sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); - gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter); - gtk_tree_selection_select_iter (sel, &iter); -} - -static void -word_entry_changed_handler (GtkEditable *editable, GeditSpellCheckerDialog *dlg) -{ - const gchar *text; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); - - if (g_utf8_strlen (text, -1) > 0) - { - gtk_widget_set_sensitive (dlg->check_word_button, TRUE); - gtk_widget_set_sensitive (dlg->change_button, TRUE); - gtk_widget_set_sensitive (dlg->change_all_button, TRUE); - } - else - { - gtk_widget_set_sensitive (dlg->check_word_button, FALSE); - gtk_widget_set_sensitive (dlg->change_button, FALSE); - gtk_widget_set_sensitive (dlg->change_all_button, FALSE); - } -} - -static void -close_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - gtk_widget_destroy (GTK_WIDGET (dlg)); -} - -static void -suggestions_list_selection_changed_handler (GtkTreeSelection *selection, - GeditSpellCheckerDialog *dlg) -{ - GtkTreeIter iter; - GValue value = {0, }; - const gchar *text; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) - return; - - gtk_tree_model_get_value (dlg->suggestions_list_model, &iter, - COLUMN_SUGGESTIONS, - &value); - - text = g_value_get_string (&value); - - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text); - - g_value_unset (&value); -} - -static void -check_word_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - const gchar *word; - gssize len; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); - len = strlen (word); - g_return_if_fail (len > 0); - - if (gedit_spell_checker_check_word (dlg->spell_checker, word, len)) - { - GtkListStore *store; - GtkTreeIter iter; - - store = GTK_LIST_STORE (dlg->suggestions_list_model); - gtk_list_store_clear (store); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - /* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */ - COLUMN_SUGGESTIONS, _("(correct spelling)"), - -1); - - gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); - } - else - { - GSList *sug; - - sug = gedit_spell_checker_get_suggestions (dlg->spell_checker, - word, - len); - - update_suggestions_list_model (dlg, sug); - - /* free the suggestion list */ - g_slist_foreach (sug, (GFunc)g_free, NULL); - g_slist_free (sug); - } -} - -static void -add_word_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - gedit_spell_checker_add_word_to_personal (dlg->spell_checker, - dlg->misspelled_word, - -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word); - - g_free (word); -} - -static void -ignore_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word); - - g_free (word); -} - -static void -ignore_all_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - gedit_spell_checker_add_word_to_session (dlg->spell_checker, - dlg->misspelled_word, - -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word); - - g_free (word); -} - -static void -change_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - gchar *change; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); - g_return_if_fail (change != NULL); - g_return_if_fail (*change != '\0'); - - gedit_spell_checker_set_correction (dlg->spell_checker, - dlg->misspelled_word, -1, - change, -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change); - - g_free (word); - g_free (change); -} - -/* double click on one of the suggestions is like clicking on "change" */ -static void -suggestions_list_row_activated_handler (GtkTreeView *view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditSpellCheckerDialog *dlg) -{ - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg); -} - -static void -change_all_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - gchar *change; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); - g_return_if_fail (change != NULL); - g_return_if_fail (*change != '\0'); - - gedit_spell_checker_set_correction (dlg->spell_checker, - dlg->misspelled_word, -1, - change, -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change); - - g_free (word); - g_free (change); -} - -void -gedit_spell_checker_dialog_set_completed (GeditSpellCheckerDialog *dlg) -{ - gchar *tmp; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - tmp = g_strdup_printf("%s", _("Completed spell checking")); - gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), - tmp); - g_free (tmp); - - gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); - - gtk_widget_set_sensitive (dlg->word_entry, FALSE); - gtk_widget_set_sensitive (dlg->check_word_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); - gtk_widget_set_sensitive (dlg->change_button, FALSE); - gtk_widget_set_sensitive (dlg->change_all_button, FALSE); - gtk_widget_set_sensitive (dlg->add_word_button, FALSE); - gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); -} - diff --git a/plugins/spell/gedit-spell-checker-dialog.h b/plugins/spell/gedit-spell-checker-dialog.h deleted file mode 100755 index 257c2b75..00000000 --- a/plugins/spell/gedit-spell-checker-dialog.h +++ /dev/null @@ -1,92 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-dialog.h - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_CHECKER_DIALOG_H__ -#define __GEDIT_SPELL_CHECKER_DIALOG_H__ - -#include -#include "gedit-spell-checker.h" - -G_BEGIN_DECLS - -#define GEDIT_TYPE_SPELL_CHECKER_DIALOG (gedit_spell_checker_dialog_get_type ()) -#define GEDIT_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_SPELL_CHECKER_DIALOG, GeditSpellCheckerDialog)) -#define GEDIT_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_SPELL_CHECKER_DIALOG, GeditSpellCheckerDialog)) -#define GEDIT_IS_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_SPELL_CHECKER_DIALOG)) -#define GEDIT_IS_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_SPELL_CHECKER_DIALOG)) -#define GEDIT_SPELL_CHECKER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_SPELL_CHECKER_DIALOG, GeditSpellCheckerDialog)) - - -typedef struct _GeditSpellCheckerDialog GeditSpellCheckerDialog; - -typedef struct _GeditSpellCheckerDialogClass GeditSpellCheckerDialogClass; - -struct _GeditSpellCheckerDialogClass -{ - GtkWindowClass parent_class; - - /* Signals */ - void (*ignore) (GeditSpellCheckerDialog *dlg, - const gchar *word); - void (*ignore_all) (GeditSpellCheckerDialog *dlg, - const gchar *word); - void (*change) (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change_to); - void (*change_all) (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change_to); - void (*add_word_to_personal) (GeditSpellCheckerDialog *dlg, - const gchar *word); - -}; - -GType gedit_spell_checker_dialog_get_type (void) G_GNUC_CONST; - -/* Constructors */ -GtkWidget *gedit_spell_checker_dialog_new (const gchar *data_dir); -GtkWidget *gedit_spell_checker_dialog_new_from_spell_checker - (GeditSpellChecker *spell, - const gchar *data_dir); - -void gedit_spell_checker_dialog_set_spell_checker - (GeditSpellCheckerDialog *dlg, - GeditSpellChecker *spell); -void gedit_spell_checker_dialog_set_misspelled_word - (GeditSpellCheckerDialog *dlg, - const gchar* word, - gint len); - -void gedit_spell_checker_dialog_set_completed - (GeditSpellCheckerDialog *dlg); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_CHECKER_DIALOG_H__ */ - diff --git a/plugins/spell/gedit-spell-checker-language.c b/plugins/spell/gedit-spell-checker-language.c deleted file mode 100755 index ae7e2422..00000000 --- a/plugins/spell/gedit-spell-checker-language.c +++ /dev/null @@ -1,439 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-language.c - * This file is part of gedit - * - * Copyright (C) 2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2006. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -/* Part of the code taked from Epiphany. - * - * Copyright (C) 2003, 2004 Christian Persch - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "gedit-spell-checker-language.h" - -#include - -#define ISO_639_DOMAIN "iso_639" -#define ISO_3166_DOMAIN "iso_3166" - -#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale" - -struct _GeditSpellCheckerLanguage -{ - gchar *abrev; - gchar *name; -}; - -static gboolean available_languages_initialized = FALSE; -static GSList *available_languages = NULL; - -static GHashTable *iso_639_table = NULL; -static GHashTable *iso_3166_table = NULL; - -static void -bind_iso_domains (void) -{ - static gboolean bound = FALSE; - - if (bound == FALSE) - { - bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR); - bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8"); - - bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR); - bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8"); - - bound = TRUE; - } -} - -static void -read_iso_639_entry (xmlTextReaderPtr reader, - GHashTable *table) -{ - xmlChar *code, *name; - - code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code"); - name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); - - /* Get iso-639-2 code */ - if (code == NULL || code[0] == '\0') - { - xmlFree (code); - /* FIXME: use the 2T or 2B code? */ - code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code"); - } - - if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') - { - g_hash_table_insert (table, code, name); - } - else - { - xmlFree (code); - xmlFree (name); - } -} - -static void -read_iso_3166_entry (xmlTextReaderPtr reader, - GHashTable *table) -{ - xmlChar *code, *name; - - code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code"); - name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); - - if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') - { - char *lcode; - - lcode = g_ascii_strdown ((char *) code, -1); - xmlFree (code); - - /* g_print ("%s -> %s\n", lcode, name); */ - - g_hash_table_insert (table, lcode, name); - } - else - { - xmlFree (code); - xmlFree (name); - } -} - -typedef enum -{ - STATE_START, - STATE_STOP, - STATE_ENTRIES, -} ParserState; - -static void -load_iso_entries (int iso, - GFunc read_entry_func, - gpointer user_data) -{ - xmlTextReaderPtr reader; - ParserState state = STATE_START; - xmlChar iso_entries[32], iso_entry[32]; - char *filename; - int ret = -1; - - gedit_debug_message (DEBUG_PLUGINS, "Loading ISO-%d codes", iso); - - filename = g_strdup_printf (ISO_CODES_PREFIX "/share/xml/iso-codes/iso_%d.xml", iso); - reader = xmlNewTextReaderFilename (filename); - if (reader == NULL) goto out; - - xmlStrPrintf (iso_entries, sizeof (iso_entries), (const xmlChar *)"iso_%d_entries", iso); - xmlStrPrintf (iso_entry, sizeof (iso_entry), (const xmlChar *)"iso_%d_entry", iso); - - ret = xmlTextReaderRead (reader); - - while (ret == 1) - { - const xmlChar *tag; - xmlReaderTypes type; - - tag = xmlTextReaderConstName (reader); - type = xmlTextReaderNodeType (reader); - - if (state == STATE_ENTRIES && - type == XML_READER_TYPE_ELEMENT && - xmlStrEqual (tag, iso_entry)) - { - read_entry_func (reader, user_data); - } - else if (state == STATE_START && - type == XML_READER_TYPE_ELEMENT && - xmlStrEqual (tag, iso_entries)) - { - state = STATE_ENTRIES; - } - else if (state == STATE_ENTRIES && - type == XML_READER_TYPE_END_ELEMENT && - xmlStrEqual (tag, iso_entries)) - { - state = STATE_STOP; - } - else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE || - type == XML_READER_TYPE_WHITESPACE || - type == XML_READER_TYPE_TEXT || - type == XML_READER_TYPE_COMMENT) - { - /* eat it */ - } - else - { - /* ignore it */ - } - - ret = xmlTextReaderRead (reader); - } - - xmlFreeTextReader (reader); - -out: - if (ret < 0 || state != STATE_STOP) - { - g_warning ("Failed to load ISO-%d codes from %s!\n", - iso, filename); - } - - g_free (filename); -} - -static GHashTable * -create_iso_639_table (void) -{ - GHashTable *table; - - bind_iso_domains (); - table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) xmlFree, - (GDestroyNotify) xmlFree); - - load_iso_entries (639, (GFunc) read_iso_639_entry, table); - - return table; -} - -static GHashTable * -create_iso_3166_table (void) -{ - GHashTable *table; - - bind_iso_domains (); - table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) xmlFree); - - load_iso_entries (3166, (GFunc) read_iso_3166_entry, table); - - return table; -} - -static char * -create_name_for_language (const char *code) -{ - char **str; - char *name = NULL; - const char *langname, *localename; - int len; - - g_return_val_if_fail (iso_639_table != NULL, NULL); - g_return_val_if_fail (iso_3166_table != NULL, NULL); - - str = g_strsplit (code, "_", -1); - len = g_strv_length (str); - g_return_val_if_fail (len != 0, NULL); - - langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]); - - if (len == 1 && langname != NULL) - { - name = g_strdup (dgettext (ISO_639_DOMAIN, langname)); - } - else if (len == 2 && langname != NULL) - { - gchar *locale_code = g_ascii_strdown (str[1], -1); - - localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code); - g_free (locale_code); - - if (localename != NULL) - { - /* Translators: the first %s is the language name, and - * the second %s is the locale name. Example: - * "French (France)" - */ - name = g_strdup_printf (C_("language", "%s (%s)"), - dgettext (ISO_639_DOMAIN, langname), - dgettext (ISO_3166_DOMAIN, localename)); - } - else - { - name = g_strdup_printf (C_("language", "%s (%s)"), - dgettext (ISO_639_DOMAIN, langname), str[1]); - } - } - else - { - /* Translators: this refers to an unknown language code - * (one which isn't in our built-in list). - */ - name = g_strdup_printf (C_("language", "Unknown (%s)"), code); - } - - g_strfreev (str); - - return name; -} - -static void -enumerate_dicts (const char * const lang_tag, - const char * const provider_name, - const char * const provider_desc, - const char * const provider_file, - void * user_data) -{ - gchar *lang_name; - - GTree *dicts = (GTree *)user_data; - - lang_name = create_name_for_language (lang_tag); - g_return_if_fail (lang_name != NULL); - - /* g_print ("%s - %s\n", lang_tag, lang_name); */ - - g_tree_replace (dicts, g_strdup (lang_tag), lang_name); -} - -static gint -key_cmp (gconstpointer a, gconstpointer b, gpointer user_data) -{ - return strcmp (a, b); -} - -static gint -lang_cmp (const GeditSpellCheckerLanguage *a, - const GeditSpellCheckerLanguage *b) -{ - return g_utf8_collate (a->name, b->name); -} - -static gboolean -build_langs_list (const gchar *key, - const gchar *value, - gpointer data) -{ - GeditSpellCheckerLanguage *lang = g_new (GeditSpellCheckerLanguage, 1); - - lang->abrev = g_strdup (key); - lang->name = g_strdup (value); - - available_languages = g_slist_insert_sorted (available_languages, - lang, - (GCompareFunc)lang_cmp); - - return FALSE; -} - -const GSList * -gedit_spell_checker_get_available_languages (void) -{ - EnchantBroker *broker; - GTree *dicts; - - if (available_languages_initialized) - return available_languages; - - g_return_val_if_fail (available_languages == NULL, NULL); - - available_languages_initialized = TRUE; - - broker = enchant_broker_init (); - g_return_val_if_fail (broker != NULL, NULL); - - /* Use a GTree to efficiently remove duplicates while building the list */ - dicts = g_tree_new_full (key_cmp, - NULL, - (GDestroyNotify)g_free, - (GDestroyNotify)g_free); - - iso_639_table = create_iso_639_table (); - iso_3166_table = create_iso_3166_table (); - - enchant_broker_list_dicts (broker, enumerate_dicts, dicts); - - enchant_broker_free (broker); - - g_hash_table_destroy (iso_639_table); - g_hash_table_destroy (iso_3166_table); - - iso_639_table = NULL; - iso_3166_table = NULL; - - g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL); - - g_tree_destroy (dicts); - - return available_languages; -} - -const gchar * -gedit_spell_checker_language_to_string (const GeditSpellCheckerLanguage *lang) -{ - if (lang == NULL) - /* Translators: this refers the Default language used by the - * spell checker - */ - return C_("language", "Default"); - - return lang->name; -} - -const gchar * -gedit_spell_checker_language_to_key (const GeditSpellCheckerLanguage *lang) -{ - g_return_val_if_fail (lang != NULL, NULL); - - return lang->abrev; -} - -const GeditSpellCheckerLanguage * -gedit_spell_checker_language_from_key (const gchar *key) -{ - const GSList *langs; - - g_return_val_if_fail (key != NULL, NULL); - - langs = gedit_spell_checker_get_available_languages (); - - while (langs != NULL) - { - const GeditSpellCheckerLanguage *l = (const GeditSpellCheckerLanguage *)langs->data; - - if (g_ascii_strcasecmp (key, l->abrev) == 0) - return l; - - langs = g_slist_next (langs); - } - - return NULL; -} diff --git a/plugins/spell/gedit-spell-checker-language.h b/plugins/spell/gedit-spell-checker-language.h deleted file mode 100755 index 7e62de65..00000000 --- a/plugins/spell/gedit-spell-checker-language.h +++ /dev/null @@ -1,51 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-language.h - * This file is part of gedit - * - * Copyright (C) 2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2006. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_CHECKER_LANGUAGE_H__ -#define __GEDIT_SPELL_CHECKER_LANGUAGE_H__ - -#include - -G_BEGIN_DECLS - -typedef struct _GeditSpellCheckerLanguage GeditSpellCheckerLanguage; - -const gchar *gedit_spell_checker_language_to_string (const GeditSpellCheckerLanguage *lang); - -const gchar *gedit_spell_checker_language_to_key (const GeditSpellCheckerLanguage *lang); - -const GeditSpellCheckerLanguage *gedit_spell_checker_language_from_key (const gchar *key); - -/* GSList contains "GeditSpellCheckerLanguage*" items */ -const GSList *gedit_spell_checker_get_available_languages - (void); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_CHECKER_LANGUAGE_H__ */ diff --git a/plugins/spell/gedit-spell-checker.c b/plugins/spell/gedit-spell-checker.c deleted file mode 100755 index 51b8d8a8..00000000 --- a/plugins/spell/gedit-spell-checker.c +++ /dev/null @@ -1,520 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker.c - * This file is part of gedit - * - * Copyright (C) 2002-2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002-2006. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "gedit-spell-checker.h" -#include "gedit-spell-utils.h" -#include "gedit-spell-marshal.h" - -struct _GeditSpellChecker -{ - GObject parent_instance; - - EnchantDict *dict; - EnchantBroker *broker; - const GeditSpellCheckerLanguage *active_lang; -}; - -/* GObject properties */ -enum { - PROP_0 = 0, - PROP_LANGUAGE, - LAST_PROP -}; - -/* Signals */ -enum { - ADD_WORD_TO_PERSONAL = 0, - ADD_WORD_TO_SESSION, - SET_LANGUAGE, - CLEAR_SESSION, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(GeditSpellChecker, gedit_spell_checker, G_TYPE_OBJECT) - -static void -gedit_spell_checker_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - /* - GeditSpellChecker *spell = GEDIT_SPELL_CHECKER (object); - */ - - switch (prop_id) - { - case PROP_LANGUAGE: - /* TODO */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gedit_spell_checker_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - /* - GeditSpellChecker *spell = GEDIT_SPELL_CHECKER (object); - */ - - switch (prop_id) - { - case PROP_LANGUAGE: - /* TODO */ - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gedit_spell_checker_finalize (GObject *object) -{ - GeditSpellChecker *spell_checker; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER (object)); - - spell_checker = GEDIT_SPELL_CHECKER (object); - - if (spell_checker->dict != NULL) - enchant_broker_free_dict (spell_checker->broker, spell_checker->dict); - - if (spell_checker->broker != NULL) - enchant_broker_free (spell_checker->broker); - - G_OBJECT_CLASS (gedit_spell_checker_parent_class)->finalize (object); -} - -static void -gedit_spell_checker_class_init (GeditSpellCheckerClass * klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = gedit_spell_checker_set_property; - object_class->get_property = gedit_spell_checker_get_property; - - object_class->finalize = gedit_spell_checker_finalize; - - g_object_class_install_property (object_class, - PROP_LANGUAGE, - g_param_spec_pointer ("language", - "Language", - "The language used by the spell checker", - G_PARAM_READWRITE)); - - signals[ADD_WORD_TO_PERSONAL] = - g_signal_new ("add_word_to_personal", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, add_word_to_personal), - NULL, NULL, - gedit_marshal_VOID__STRING_INT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_INT); - - signals[ADD_WORD_TO_SESSION] = - g_signal_new ("add_word_to_session", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, add_word_to_session), - NULL, NULL, - gedit_marshal_VOID__STRING_INT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_INT); - - signals[SET_LANGUAGE] = - g_signal_new ("set_language", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, set_language), - NULL, NULL, - gedit_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - signals[CLEAR_SESSION] = - g_signal_new ("clear_session", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, clear_session), - NULL, NULL, - gedit_marshal_VOID__VOID, - G_TYPE_NONE, - 0); -} - -static void -gedit_spell_checker_init (GeditSpellChecker *spell_checker) -{ - spell_checker->broker = enchant_broker_init (); - spell_checker->dict = NULL; - spell_checker->active_lang = NULL; -} - -GeditSpellChecker * -gedit_spell_checker_new (void) -{ - GeditSpellChecker *spell; - - spell = GEDIT_SPELL_CHECKER ( - g_object_new (GEDIT_TYPE_SPELL_CHECKER, NULL)); - - g_return_val_if_fail (spell != NULL, NULL); - - return spell; -} - -static gboolean -lazy_init (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *language) -{ - if (spell->dict != NULL) - return TRUE; - - g_return_val_if_fail (spell->broker != NULL, FALSE); - - spell->active_lang = NULL; - - if (language != NULL) - { - spell->active_lang = language; - } - else - { - /* First try to get a default language */ - const GeditSpellCheckerLanguage *l; - gint i = 0; - const gchar * const *lang_tags = g_get_language_names (); - - while (lang_tags [i]) - { - l = gedit_spell_checker_language_from_key (lang_tags [i]); - - if (l != NULL) - { - spell->active_lang = l; - break; - } - - i++; - } - } - - /* Second try to get a default language */ - if (spell->active_lang == NULL) - spell->active_lang = gedit_spell_checker_language_from_key ("en_US"); - - /* Last try to get a default language */ - if (spell->active_lang == NULL) - { - const GSList *langs; - langs = gedit_spell_checker_get_available_languages (); - if (langs != NULL) - spell->active_lang = (const GeditSpellCheckerLanguage *)langs->data; - } - - if (spell->active_lang != NULL) - { - const gchar *key; - - key = gedit_spell_checker_language_to_key (spell->active_lang); - - spell->dict = enchant_broker_request_dict (spell->broker, - key); - } - - if (spell->dict == NULL) - { - spell->active_lang = NULL; - - if (language != NULL) - g_warning ("Spell checker plugin: cannot select a default language."); - - return FALSE; - } - - return TRUE; -} - -gboolean -gedit_spell_checker_set_language (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *language) -{ - gboolean ret; - - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - - if (spell->dict != NULL) - { - enchant_broker_free_dict (spell->broker, spell->dict); - spell->dict = NULL; - } - - ret = lazy_init (spell, language); - - if (ret) - g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language); - else - g_warning ("Spell checker plugin: cannot use language %s.", - gedit_spell_checker_language_to_string (language)); - - return ret; -} - -const GeditSpellCheckerLanguage * -gedit_spell_checker_get_language (GeditSpellChecker *spell) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), NULL); - - if (!lazy_init (spell, spell->active_lang)) - return NULL; - - return spell->active_lang; -} - -gboolean -gedit_spell_checker_check_word (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - gint enchant_result; - gboolean res = FALSE; - - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - if (len < 0) - len = strlen (word); - - if (strcmp (word, "gedit") == 0) - return TRUE; - - if (gedit_spell_utils_is_digit (word, len)) - return TRUE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - enchant_result = enchant_dict_check (spell->dict, word, len); - - switch (enchant_result) - { - case -1: - /* error */ - res = FALSE; - - g_warning ("Spell checker plugin: error checking word '%s' (%s).", - word, enchant_dict_get_error (spell->dict)); - - break; - case 1: - /* it is not in the directory */ - res = FALSE; - break; - case 0: - /* is is in the directory */ - res = TRUE; - break; - default: - g_return_val_if_reached (FALSE); - } - - return res; -} - - -/* return NULL on error or if no suggestions are found */ -GSList * -gedit_spell_checker_get_suggestions (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - gchar **suggestions; - size_t n_suggestions = 0; - GSList *suggestions_list = NULL; - gint i; - - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), NULL); - g_return_val_if_fail (word != NULL, NULL); - - if (!lazy_init (spell, spell->active_lang)) - return NULL; - - g_return_val_if_fail (spell->dict != NULL, NULL); - - if (len < 0) - len = strlen (word); - - suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions); - - if (n_suggestions == 0) - return NULL; - - g_return_val_if_fail (suggestions != NULL, NULL); - - for (i = 0; i < (gint)n_suggestions; i++) - { - suggestions_list = g_slist_prepend (suggestions_list, - suggestions[i]); - } - - /* The single suggestions will be freed by the caller */ - g_free (suggestions); - - suggestions_list = g_slist_reverse (suggestions_list); - - return suggestions_list; -} - -gboolean -gedit_spell_checker_add_word_to_personal (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - - if (len < 0) - len = strlen (word); - - enchant_dict_add_to_pwl (spell->dict, word, len); - - g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len); - - return TRUE; -} - -gboolean -gedit_spell_checker_add_word_to_session (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - - if (len < 0) - len = strlen (word); - - enchant_dict_add_to_session (spell->dict, word, len); - - g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len); - - return TRUE; -} - -gboolean -gedit_spell_checker_clear_session (GeditSpellChecker *spell) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - - /* free and re-request dictionary */ - if (spell->dict != NULL) - { - enchant_broker_free_dict (spell->broker, spell->dict); - spell->dict = NULL; - } - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0); - - return TRUE; -} - -/* - * Informs dictionary, that word 'word' will be replaced/corrected by word - * 'replacement' - */ -gboolean -gedit_spell_checker_set_correction (GeditSpellChecker *spell, - const gchar *word, - gssize w_len, - const gchar *replacement, - gssize r_len) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - g_return_val_if_fail (replacement != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - - if (w_len < 0) - w_len = strlen (word); - - if (r_len < 0) - r_len = strlen (replacement); - - enchant_dict_store_replacement (spell->dict, - word, - w_len, - replacement, - r_len); - - return TRUE; -} - diff --git a/plugins/spell/gedit-spell-checker.h b/plugins/spell/gedit-spell-checker.h deleted file mode 100755 index 0cc69d31..00000000 --- a/plugins/spell/gedit-spell-checker.h +++ /dev/null @@ -1,109 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker.h - * This file is part of gedit - * - * Copyright (C) 2002-2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_CHECKER_H__ -#define __GEDIT_SPELL_CHECKER_H__ - -#include -#include - -#include "gedit-spell-checker-language.h" - -G_BEGIN_DECLS - -#define GEDIT_TYPE_SPELL_CHECKER (gedit_spell_checker_get_type ()) -#define GEDIT_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_SPELL_CHECKER, GeditSpellChecker)) -#define GEDIT_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_SPELL_CHECKER, GeditSpellChecker)) -#define GEDIT_IS_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_SPELL_CHECKER)) -#define GEDIT_IS_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_SPELL_CHECKER)) -#define GEDIT_SPELL_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_SPELL_CHECKER, GeditSpellChecker)) - -typedef struct _GeditSpellChecker GeditSpellChecker; - -typedef struct _GeditSpellCheckerClass GeditSpellCheckerClass; - -struct _GeditSpellCheckerClass -{ - GObjectClass parent_class; - - /* Signals */ - void (*add_word_to_personal) (GeditSpellChecker *spell, - const gchar *word, - gint len); - - void (*add_word_to_session) (GeditSpellChecker *spell, - const gchar *word, - gint len); - - void (*set_language) (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *lang); - - void (*clear_session) (GeditSpellChecker *spell); -}; - - -GType gedit_spell_checker_get_type (void) G_GNUC_CONST; - -/* Constructors */ -GeditSpellChecker *gedit_spell_checker_new (void); - -gboolean gedit_spell_checker_set_language (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *lang); -const GeditSpellCheckerLanguage - *gedit_spell_checker_get_language (GeditSpellChecker *spell); - -gboolean gedit_spell_checker_check_word (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -GSList *gedit_spell_checker_get_suggestions (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -gboolean gedit_spell_checker_add_word_to_personal - (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -gboolean gedit_spell_checker_add_word_to_session - (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -gboolean gedit_spell_checker_clear_session (GeditSpellChecker *spell); - -gboolean gedit_spell_checker_set_correction (GeditSpellChecker *spell, - const gchar *word, - gssize w_len, - const gchar *replacement, - gssize r_len); -G_END_DECLS - -#endif /* __GEDIT_SPELL_CHECKER_H__ */ - diff --git a/plugins/spell/gedit-spell-language-dialog.c b/plugins/spell/gedit-spell-language-dialog.c deleted file mode 100755 index 1abba17f..00000000 --- a/plugins/spell/gedit-spell-language-dialog.c +++ /dev/null @@ -1,309 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-language-dialog.c - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include "gedit-spell-language-dialog.h" -#include "gedit-spell-checker-language.h" - - -enum -{ - COLUMN_LANGUAGE_NAME = 0, - COLUMN_LANGUAGE_POINTER, - ENCODING_NUM_COLS -}; - - -struct _GeditSpellLanguageDialog -{ - GtkDialog dialog; - - GtkWidget *languages_treeview; - GtkTreeModel *model; -}; - -G_DEFINE_TYPE(GeditSpellLanguageDialog, gedit_spell_language_dialog, GTK_TYPE_DIALOG) - - -static void -gedit_spell_language_dialog_class_init (GeditSpellLanguageDialogClass *klass) -{ - /* GObjectClass *object_class = G_OBJECT_CLASS (klass); */ -} - -static void -dialog_response_handler (GtkDialog *dlg, - gint res_id) -{ - if (res_id == GTK_RESPONSE_HELP) - { - gedit_help_display (GTK_WINDOW (dlg), - NULL, - "gedit-spell-checker-plugin"); - - g_signal_stop_emission_by_name (dlg, "response"); - } -} - -static void -scroll_to_selected (GtkTreeView *tree_view) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (tree_view); - g_return_if_fail (model != NULL); - - /* Scroll to selected */ - selection = gtk_tree_view_get_selection (tree_view); - g_return_if_fail (selection != NULL); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - GtkTreePath* path; - - path = gtk_tree_model_get_path (model, &iter); - g_return_if_fail (path != NULL); - - gtk_tree_view_scroll_to_cell (tree_view, - path, NULL, TRUE, 1.0, 0.0); - gtk_tree_path_free (path); - } -} - -static void -language_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditSpellLanguageDialog *dialog) -{ - gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); -} - -static void -create_dialog (GeditSpellLanguageDialog *dlg, - const gchar *data_dir) -{ - GtkWidget *error_widget; - GtkWidget *content; - gboolean ret; - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - gchar *ui_file; - gchar *root_objects[] = { - "content", - NULL - }; - - gtk_dialog_add_buttons (GTK_DIALOG (dlg), - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - GTK_STOCK_HELP, - GTK_RESPONSE_HELP, - NULL); - - gtk_window_set_title (GTK_WINDOW (dlg), _("Set language")); - gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE); - gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); - gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE); - - /* HIG defaults */ - gtk_container_set_border_width (GTK_CONTAINER (dlg), 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - 2); /* 2 * 5 + 2 = 12 */ - gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), - 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), - 6); - - g_signal_connect (dlg, - "response", - G_CALLBACK (dialog_response_handler), - NULL); - - ui_file = g_build_filename (data_dir, "languages-dialog.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - root_objects, - &error_widget, - "content", &content, - "languages_treeview", &dlg->languages_treeview, - NULL); - g_free (ui_file); - - if (!ret) - { - gtk_widget_show (error_widget); - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - error_widget, - TRUE, TRUE, 0); - - return; - } - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - content, TRUE, TRUE, 0); - g_object_unref (content); - gtk_container_set_border_width (GTK_CONTAINER (content), 5); - - dlg->model = GTK_TREE_MODEL (gtk_list_store_new (ENCODING_NUM_COLS, - G_TYPE_STRING, - G_TYPE_POINTER)); - - gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->languages_treeview), - dlg->model); - - g_object_unref (dlg->model); - - /* Add the encoding column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Languages"), - cell, - "text", - COLUMN_LANGUAGE_NAME, - NULL); - - gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->languages_treeview), - column); - - gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->languages_treeview), - COLUMN_LANGUAGE_NAME); - - g_signal_connect (dlg->languages_treeview, - "realize", - G_CALLBACK (scroll_to_selected), - dlg); - g_signal_connect (dlg->languages_treeview, - "row-activated", - G_CALLBACK (language_row_activated), - dlg); -} - -static void -gedit_spell_language_dialog_init (GeditSpellLanguageDialog *dlg) -{ - -} - -static void -populate_language_list (GeditSpellLanguageDialog *dlg, - const GeditSpellCheckerLanguage *cur_lang) -{ - GtkListStore *store; - GtkTreeIter iter; - - const GSList* langs; - - /* create list store */ - store = GTK_LIST_STORE (dlg->model); - - langs = gedit_spell_checker_get_available_languages (); - - while (langs) - { - const gchar *name; - - name = gedit_spell_checker_language_to_string ((const GeditSpellCheckerLanguage*)langs->data); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COLUMN_LANGUAGE_NAME, name, - COLUMN_LANGUAGE_POINTER, langs->data, - -1); - - if (langs->data == cur_lang) - { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); - g_return_if_fail (selection != NULL); - - gtk_tree_selection_select_iter (selection, &iter); - } - - langs = g_slist_next (langs); - } -} - -GtkWidget * -gedit_spell_language_dialog_new (GtkWindow *parent, - const GeditSpellCheckerLanguage *cur_lang, - const gchar *data_dir) -{ - GeditSpellLanguageDialog *dlg; - - g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); - - dlg = g_object_new (GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, NULL); - - create_dialog (dlg, data_dir); - - populate_language_list (dlg, cur_lang); - - gtk_window_set_transient_for (GTK_WINDOW (dlg), parent); - gtk_widget_grab_focus (dlg->languages_treeview); - - return GTK_WIDGET (dlg); -} - -const GeditSpellCheckerLanguage * -gedit_spell_language_get_selected_language (GeditSpellLanguageDialog *dlg) -{ - GValue value = {0, }; - const GeditSpellCheckerLanguage* lang; - - GtkTreeIter iter; - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); - g_return_val_if_fail (selection != NULL, NULL); - - if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) - return NULL; - - gtk_tree_model_get_value (dlg->model, - &iter, - COLUMN_LANGUAGE_POINTER, - &value); - - lang = (const GeditSpellCheckerLanguage* ) g_value_get_pointer (&value); - - return lang; -} - diff --git a/plugins/spell/gedit-spell-language-dialog.h b/plugins/spell/gedit-spell-language-dialog.h deleted file mode 100755 index 4ae9c97d..00000000 --- a/plugins/spell/gedit-spell-language-dialog.h +++ /dev/null @@ -1,67 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-language-dialog.h - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_LANGUAGE_DIALOG_H__ -#define __GEDIT_SPELL_LANGUAGE_DIALOG_H__ - -#include -#include "gedit-spell-checker-language.h" - -G_BEGIN_DECLS - -#define GEDIT_TYPE_SPELL_LANGUAGE_DIALOG (gedit_spell_language_dialog_get_type()) -#define GEDIT_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, GeditSpellLanguageDialog)) -#define GEDIT_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, GeditSpellLanguageDialogClass)) -#define GEDIT_IS_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG)) -#define GEDIT_IS_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG)) -#define GEDIT_SPELL_LANGUAGE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, GeditSpellLanguageDialogClass)) - - -typedef struct _GeditSpellLanguageDialog GeditSpellLanguageDialog; - -typedef struct _GeditSpellLanguageDialogClass GeditSpellLanguageDialogClass; - -struct _GeditSpellLanguageDialogClass -{ - GtkDialogClass parent_class; -}; - -GType gedit_spell_language_dialog_get_type (void) G_GNUC_CONST; - -GtkWidget *gedit_spell_language_dialog_new (GtkWindow *parent, - const GeditSpellCheckerLanguage *cur_lang, - const gchar *data_dir); - -const GeditSpellCheckerLanguage * - gedit_spell_language_get_selected_language (GeditSpellLanguageDialog *dlg); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_LANGUAGE_DIALOG_H__ */ - diff --git a/plugins/spell/gedit-spell-marshal.list b/plugins/spell/gedit-spell-marshal.list deleted file mode 100755 index 007dcf7d..00000000 --- a/plugins/spell/gedit-spell-marshal.list +++ /dev/null @@ -1,6 +0,0 @@ -VOID:STRING -VOID:STRING,STRING -VOID:STRING,INT -VOID:POINTER -VOID:VOID - diff --git a/plugins/spell/gedit-spell-plugin.c b/plugins/spell/gedit-spell-plugin.c deleted file mode 100755 index 6ef78e75..00000000 --- a/plugins/spell/gedit-spell-plugin.c +++ /dev/null @@ -1,1217 +0,0 @@ -/* - * gedit-spell-plugin.c - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-spell-plugin.h" -#include "gedit-spell-utils.h" - -#include /* For strlen */ - -#include -#include - -#include -#include -#include - -#include "gedit-spell-checker.h" -#include "gedit-spell-checker-dialog.h" -#include "gedit-spell-language-dialog.h" -#include "gedit-automatic-spell-checker.h" - -#ifdef G_OS_WIN32 -#include -#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "spell-language" -#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "spell-enabled" -#else -#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::gedit-spell-language" -#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::gedit-spell-enabled" -#endif - -#define WINDOW_DATA_KEY "GeditSpellPluginWindowData" -#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1" - -#define GEDIT_SPELL_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ - GEDIT_TYPE_SPELL_PLUGIN, \ - GeditSpellPluginPrivate)) - -GEDIT_PLUGIN_REGISTER_TYPE(GeditSpellPlugin, gedit_spell_plugin) - -typedef struct -{ - GtkActionGroup *action_group; - guint ui_id; - guint message_cid; - gulong tab_added_id; - gulong tab_removed_id; -} WindowData; - -typedef struct -{ - GeditPlugin *plugin; - GeditWindow *window; -} ActionData; - -static void spell_cb (GtkAction *action, ActionData *action_data); -static void set_language_cb (GtkAction *action, ActionData *action_data); -static void auto_spell_cb (GtkAction *action, GeditWindow *window); - -/* UI actions. */ -static const GtkActionEntry action_entries[] = -{ - { "CheckSpell", - GTK_STOCK_SPELL_CHECK, - N_("_Check Spelling..."), - "F7", - N_("Check the current document for incorrect spelling"), - G_CALLBACK (spell_cb) - }, - - { "ConfigSpell", - NULL, - N_("Set _Language..."), - NULL, - N_("Set the language of the current document"), - G_CALLBACK (set_language_cb) - } -}; - -static const GtkToggleActionEntry toggle_action_entries[] = -{ - { "AutoSpell", - NULL, - N_("_Autocheck Spelling"), - NULL, - N_("Automatically spell-check the current document"), - G_CALLBACK (auto_spell_cb), - FALSE - } -}; - -typedef struct _CheckRange CheckRange; - -struct _CheckRange -{ - GtkTextMark *start_mark; - GtkTextMark *end_mark; - - gint mw_start; /* misspelled word start */ - gint mw_end; /* end */ - - GtkTextMark *current_mark; -}; - -static GQuark spell_checker_id = 0; -static GQuark check_range_id = 0; - -static void -gedit_spell_plugin_init (GeditSpellPlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin initializing"); -} - -static void -gedit_spell_plugin_finalize (GObject *object) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin finalizing"); - - G_OBJECT_CLASS (gedit_spell_plugin_parent_class)->finalize (object); -} - -static void -set_spell_language_cb (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *lang, - GeditDocument *doc) -{ - const gchar *key; - - g_return_if_fail (GEDIT_IS_DOCUMENT (doc)); - g_return_if_fail (lang != NULL); - - key = gedit_spell_checker_language_to_key (lang); - g_return_if_fail (key != NULL); - - gedit_document_set_metadata (doc, GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE, - key, NULL); -} - -static void -set_language_from_metadata (GeditSpellChecker *spell, - GeditDocument *doc) -{ - const GeditSpellCheckerLanguage *lang = NULL; - gchar *value = NULL; - - value = gedit_document_get_metadata (doc, GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE); - - if (value != NULL) - { - lang = gedit_spell_checker_language_from_key (value); - g_free (value); - } - - if (lang != NULL) - { - g_signal_handlers_block_by_func (spell, set_spell_language_cb, doc); - gedit_spell_checker_set_language (spell, lang); - g_signal_handlers_unblock_by_func (spell, set_spell_language_cb, doc); - } -} - -static GeditSpellChecker * -get_spell_checker_from_document (GeditDocument *doc) -{ - GeditSpellChecker *spell; - gpointer data; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, NULL); - - data = g_object_get_qdata (G_OBJECT (doc), spell_checker_id); - - if (data == NULL) - { - spell = gedit_spell_checker_new (); - - set_language_from_metadata (spell, doc); - - g_object_set_qdata_full (G_OBJECT (doc), - spell_checker_id, - spell, - (GDestroyNotify) g_object_unref); - - g_signal_connect (spell, - "set_language", - G_CALLBACK (set_spell_language_cb), - doc); - } - else - { - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (data), NULL); - spell = GEDIT_SPELL_CHECKER (data); - } - - return spell; -} - -static CheckRange * -get_check_range (GeditDocument *doc) -{ - CheckRange *range; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, NULL); - - range = (CheckRange *) g_object_get_qdata (G_OBJECT (doc), check_range_id); - - return range; -} - -static void -update_current (GeditDocument *doc, - gint current) -{ - CheckRange *range; - GtkTextIter iter; - GtkTextIter end_iter; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (doc != NULL); - g_return_if_fail (current >= 0); - - range = get_check_range (doc); - g_return_if_fail (range != NULL); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), - &iter, current); - - if (!gtk_text_iter_inside_word (&iter)) - { - /* if we're not inside a word, - * we must be in some spaces. - * skip forward to the beginning of the next word. */ - if (!gtk_text_iter_is_end (&iter)) - { - gtk_text_iter_forward_word_end (&iter); - gtk_text_iter_backward_word_start (&iter); - } - } - else - { - if (!gtk_text_iter_starts_word (&iter)) - gtk_text_iter_backward_word_start (&iter); - } - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - &end_iter, - range->end_mark); - - if (gtk_text_iter_compare (&end_iter, &iter) < 0) - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->current_mark, - &end_iter); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->current_mark, - &iter); - } -} - -static void -set_check_range (GeditDocument *doc, - GtkTextIter *start, - GtkTextIter *end) -{ - CheckRange *range; - GtkTextIter iter; - - gedit_debug (DEBUG_PLUGINS); - - range = get_check_range (doc); - - if (range == NULL) - { - gedit_debug_message (DEBUG_PLUGINS, "There was not a previous check range"); - - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter); - - range = g_new0 (CheckRange, 1); - - range->start_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "check_range_start_mark", &iter, TRUE); - - range->end_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "check_range_end_mark", &iter, FALSE); - - range->current_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "check_range_current_mark", &iter, TRUE); - - g_object_set_qdata_full (G_OBJECT (doc), - check_range_id, - range, - (GDestroyNotify)g_free); - } - - if (gedit_spell_utils_skip_no_spell_check (start, end)) - { - if (!gtk_text_iter_inside_word (end)) - { - /* if we're neither inside a word, - * we must be in some spaces. - * skip backward to the end of the previous word. */ - if (!gtk_text_iter_is_end (end)) - { - gtk_text_iter_backward_word_start (end); - gtk_text_iter_forward_word_end (end); - } - } - else - { - if (!gtk_text_iter_ends_word (end)) - gtk_text_iter_forward_word_end (end); - } - } - else - { - /* no spell checking in the specified range */ - start = end; - } - - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->start_mark, - start); - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->end_mark, - end); - - range->mw_start = -1; - range->mw_end = -1; - - update_current (doc, gtk_text_iter_get_offset (start)); -} - -static gchar * -get_current_word (GeditDocument *doc, gint *start, gint *end) -{ - const CheckRange *range; - GtkTextIter end_iter; - GtkTextIter current_iter; - gint range_end; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, NULL); - g_return_val_if_fail (start != NULL, NULL); - g_return_val_if_fail (end != NULL, NULL); - - range = get_check_range (doc); - g_return_val_if_fail (range != NULL, NULL); - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - &end_iter, range->end_mark); - - range_end = gtk_text_iter_get_offset (&end_iter); - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - ¤t_iter, range->current_mark); - - end_iter = current_iter; - - if (!gtk_text_iter_is_end (&end_iter)) - { - gedit_debug_message (DEBUG_PLUGINS, "Current is not end"); - - gtk_text_iter_forward_word_end (&end_iter); - } - - *start = gtk_text_iter_get_offset (¤t_iter); - *end = MIN (gtk_text_iter_get_offset (&end_iter), range_end); - - gedit_debug_message (DEBUG_PLUGINS, "Current word extends [%d, %d]", *start, *end); - - if (!(*start < *end)) - return NULL; - - return gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), - ¤t_iter, - &end_iter, - TRUE); -} - -static gboolean -goto_next_word (GeditDocument *doc) -{ - CheckRange *range; - GtkTextIter current_iter; - GtkTextIter old_current_iter; - GtkTextIter end_iter; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, FALSE); - - range = get_check_range (doc); - g_return_val_if_fail (range != NULL, FALSE); - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - ¤t_iter, - range->current_mark); - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end_iter); - - old_current_iter = current_iter; - - gtk_text_iter_forward_word_ends (¤t_iter, 2); - gtk_text_iter_backward_word_start (¤t_iter); - - if (gedit_spell_utils_skip_no_spell_check (¤t_iter, &end_iter) && - (gtk_text_iter_compare (&old_current_iter, ¤t_iter) < 0) && - (gtk_text_iter_compare (¤t_iter, &end_iter) < 0)) - { - update_current (doc, gtk_text_iter_get_offset (¤t_iter)); - return TRUE; - } - - return FALSE; -} - -static gchar * -get_next_misspelled_word (GeditView *view) -{ - GeditDocument *doc; - CheckRange *range; - gint start, end; - gchar *word; - GeditSpellChecker *spell; - - g_return_val_if_fail (view != NULL, NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_val_if_fail (doc != NULL, NULL); - - range = get_check_range (doc); - g_return_val_if_fail (range != NULL, NULL); - - spell = get_spell_checker_from_document (doc); - g_return_val_if_fail (spell != NULL, NULL); - - word = get_current_word (doc, &start, &end); - if (word == NULL) - return NULL; - - gedit_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); - - while (gedit_spell_checker_check_word (spell, word, -1)) - { - g_free (word); - - if (!goto_next_word (doc)) - return NULL; - - /* may return null if we reached the end of the selection */ - word = get_current_word (doc, &start, &end); - if (word == NULL) - return NULL; - - gedit_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); - } - - if (!goto_next_word (doc)) - update_current (doc, gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc))); - - if (word != NULL) - { - GtkTextIter s, e; - - range->mw_start = start; - range->mw_end = end; - - gedit_debug_message (DEBUG_PLUGINS, "Select [%d, %d]", start, end); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &s, start); - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &e, end); - - gtk_text_buffer_select_range (GTK_TEXT_BUFFER (doc), &s, &e); - - gedit_view_scroll_to_cursor (view); - } - else - { - range->mw_start = -1; - range->mw_end = -1; - } - - return word; -} - -static void -ignore_cb (GeditSpellCheckerDialog *dlg, - const gchar *w, - GeditView *view) -{ - gchar *word = NULL; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (w != NULL); - g_return_if_fail (view != NULL); - - word = get_next_misspelled_word (view); - if (word == NULL) - { - gedit_spell_checker_dialog_set_completed (dlg); - - return; - } - - gedit_spell_checker_dialog_set_misspelled_word (GEDIT_SPELL_CHECKER_DIALOG (dlg), - word, - -1); - - g_free (word); -} - -static void -change_cb (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change, - GeditView *view) -{ - GeditDocument *doc; - CheckRange *range; - gchar *w = NULL; - GtkTextIter start, end; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (view != NULL); - g_return_if_fail (word != NULL); - g_return_if_fail (change != NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_if_fail (doc != NULL); - - range = get_check_range (doc); - g_return_if_fail (range != NULL); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); - if (range->mw_end < 0) - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); - else - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); - - w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); - g_return_if_fail (w != NULL); - - if (strcmp (w, word) != 0) - { - g_free (w); - return; - } - - g_free (w); - - gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER(doc)); - - gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), &start, &end); - gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), &start, change, -1); - - gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER(doc)); - - update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); - - /* go to next misspelled word */ - ignore_cb (dlg, word, view); -} - -static void -change_all_cb (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change, - GeditView *view) -{ - GeditDocument *doc; - CheckRange *range; - gchar *w = NULL; - GtkTextIter start, end; - gint flags = 0; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (view != NULL); - g_return_if_fail (word != NULL); - g_return_if_fail (change != NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_if_fail (doc != NULL); - - range = get_check_range (doc); - g_return_if_fail (range != NULL); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); - if (range->mw_end < 0) - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); - else - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); - - w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); - g_return_if_fail (w != NULL); - - if (strcmp (w, word) != 0) - { - g_free (w); - return; - } - - g_free (w); - - GEDIT_SEARCH_SET_CASE_SENSITIVE (flags, TRUE); - GEDIT_SEARCH_SET_ENTIRE_WORD (flags, TRUE); - - /* CHECK: currently this function does escaping etc */ - gedit_document_replace_all (doc, word, change, flags); - - update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); - - /* go to next misspelled word */ - ignore_cb (dlg, word, view); -} - -static void -add_word_cb (GeditSpellCheckerDialog *dlg, - const gchar *word, - GeditView *view) -{ - g_return_if_fail (view != NULL); - g_return_if_fail (word != NULL); - - /* go to next misspelled word */ - ignore_cb (dlg, word, view); -} - -static void -language_dialog_response (GtkDialog *dlg, - gint res_id, - GeditSpellChecker *spell) -{ - if (res_id == GTK_RESPONSE_OK) - { - const GeditSpellCheckerLanguage *lang; - - lang = gedit_spell_language_get_selected_language (GEDIT_SPELL_LANGUAGE_DIALOG (dlg)); - if (lang != NULL) - gedit_spell_checker_set_language (spell, lang); - } - - gtk_widget_destroy (GTK_WIDGET (dlg)); -} - -static void -set_language_cb (GtkAction *action, - ActionData *action_data) -{ - GeditDocument *doc; - GeditSpellChecker *spell; - const GeditSpellCheckerLanguage *lang; - GtkWidget *dlg; - GtkWindowGroup *wg; - gchar *data_dir; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (action_data->window); - g_return_if_fail (doc != NULL); - - spell = get_spell_checker_from_document (doc); - g_return_if_fail (spell != NULL); - - lang = gedit_spell_checker_get_language (spell); - - data_dir = gedit_plugin_get_data_dir (action_data->plugin); - dlg = gedit_spell_language_dialog_new (GTK_WINDOW (action_data->window), - lang, - data_dir); - g_free (data_dir); - - wg = gedit_window_get_group (action_data->window); - - gtk_window_group_add_window (wg, GTK_WINDOW (dlg)); - - gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); - - g_signal_connect (dlg, - "response", - G_CALLBACK (language_dialog_response), - spell); - - gtk_widget_show (dlg); -} - -static void -spell_cb (GtkAction *action, - ActionData *action_data) -{ - GeditView *view; - GeditDocument *doc; - GeditSpellChecker *spell; - GtkWidget *dlg; - GtkTextIter start, end; - gchar *word; - gchar *data_dir; - - gedit_debug (DEBUG_PLUGINS); - - view = gedit_window_get_active_view (action_data->window); - g_return_if_fail (view != NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_if_fail (doc != NULL); - - spell = get_spell_checker_from_document (doc); - g_return_if_fail (spell != NULL); - - if (gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc)) <= 0) - { - WindowData *data; - GtkWidget *statusbar; - - data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - statusbar = gedit_window_get_statusbar (action_data->window); - gedit_statusbar_flash_message (GEDIT_STATUSBAR (statusbar), - data->message_cid, - _("The document is empty.")); - - return; - } - - if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), - &start, - &end)) - { - /* no selection, get the whole doc */ - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), - &start, - &end); - } - - set_check_range (doc, &start, &end); - - word = get_next_misspelled_word (view); - if (word == NULL) - { - WindowData *data; - GtkWidget *statusbar; - - data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - statusbar = gedit_window_get_statusbar (action_data->window); - gedit_statusbar_flash_message (GEDIT_STATUSBAR (statusbar), - data->message_cid, - _("No misspelled words")); - - return; - } - - data_dir = gedit_plugin_get_data_dir (action_data->plugin); - dlg = gedit_spell_checker_dialog_new_from_spell_checker (spell, data_dir); - g_free (data_dir); - gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); - gtk_window_set_transient_for (GTK_WINDOW (dlg), - GTK_WINDOW (action_data->window)); - - g_signal_connect (dlg, "ignore", G_CALLBACK (ignore_cb), view); - g_signal_connect (dlg, "ignore_all", G_CALLBACK (ignore_cb), view); - - g_signal_connect (dlg, "change", G_CALLBACK (change_cb), view); - g_signal_connect (dlg, "change_all", G_CALLBACK (change_all_cb), view); - - g_signal_connect (dlg, "add_word_to_personal", G_CALLBACK (add_word_cb), view); - - gedit_spell_checker_dialog_set_misspelled_word (GEDIT_SPELL_CHECKER_DIALOG (dlg), - word, - -1); - - g_free (word); - - gtk_widget_show (dlg); -} - -static void -set_auto_spell (GeditWindow *window, - GeditDocument *doc, - gboolean active) -{ - GeditAutomaticSpellChecker *autospell; - GeditSpellChecker *spell; - - spell = get_spell_checker_from_document (doc); - g_return_if_fail (spell != NULL); - - autospell = gedit_automatic_spell_checker_get_from_document (doc); - - if (active) - { - if (autospell == NULL) - { - GeditView *active_view; - - active_view = gedit_window_get_active_view (window); - g_return_if_fail (active_view != NULL); - - autospell = gedit_automatic_spell_checker_new (doc, spell); - gedit_automatic_spell_checker_attach_view (autospell, active_view); - gedit_automatic_spell_checker_recheck_all (autospell); - } - } - else - { - if (autospell != NULL) - gedit_automatic_spell_checker_free (autospell); - } -} - -static void -auto_spell_cb (GtkAction *action, - GeditWindow *window) -{ - - GeditDocument *doc; - gboolean active; - - gedit_debug (DEBUG_PLUGINS); - - active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); - - gedit_debug_message (DEBUG_PLUGINS, active ? "Auto Spell activated" : "Auto Spell deactivated"); - - doc = gedit_window_get_active_document (window); - if (doc == NULL) - return; - - gedit_document_set_metadata (doc, - GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED, - active ? "1" : NULL, NULL); - - set_auto_spell (window, doc, active); -} - -static void -free_window_data (WindowData *data) -{ - g_return_if_fail (data != NULL); - - g_object_unref (data->action_group); - g_slice_free (WindowData, data); -} - -static void -free_action_data (gpointer data) -{ - g_return_if_fail (data != NULL); - - g_slice_free (ActionData, data); -} - -static void -update_ui_real (GeditWindow *window, - WindowData *data) -{ - GeditDocument *doc; - GeditView *view; - gboolean autospell; - GtkAction *action; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (window); - view = gedit_window_get_active_view (window); - - autospell = (doc != NULL && - gedit_automatic_spell_checker_get_from_document (doc) != NULL); - - if (doc != NULL) - { - GeditTab *tab; - GeditTabState state; - - tab = gedit_window_get_active_tab (window); - state = gedit_tab_get_state (tab); - - /* If the document is loading we can't get the metadata so we - endup with an useless speller */ - if (state == GEDIT_TAB_STATE_NORMAL) - { - action = gtk_action_group_get_action (data->action_group, - "AutoSpell"); - - g_signal_handlers_block_by_func (action, auto_spell_cb, - window); - set_auto_spell (window, doc, autospell); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - autospell); - g_signal_handlers_unblock_by_func (action, auto_spell_cb, - window); - } - } - - gtk_action_group_set_sensitive (data->action_group, - (view != NULL) && - gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); -} - -static void -set_auto_spell_from_metadata (GeditWindow *window, - GeditDocument *doc, - GtkActionGroup *action_group) -{ - gboolean active = FALSE; - gchar *active_str; - GeditDocument *active_doc; - - active_str = gedit_document_get_metadata (doc, - GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED); - - if (active_str) - { - active = *active_str == '1'; - - g_free (active_str); - } - - set_auto_spell (window, doc, active); - - /* In case that the doc is the active one we mark the spell action */ - active_doc = gedit_window_get_active_document (window); - - if (active_doc == doc && action_group != NULL) - { - GtkAction *action; - - action = gtk_action_group_get_action (action_group, - "AutoSpell"); - - g_signal_handlers_block_by_func (action, auto_spell_cb, - window); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - active); - g_signal_handlers_unblock_by_func (action, auto_spell_cb, - window); - } -} - -static void -on_document_loaded (GeditDocument *doc, - const GError *error, - GeditWindow *window) -{ - if (error == NULL) - { - WindowData *data; - GeditSpellChecker *spell; - - spell = GEDIT_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), - spell_checker_id)); - if (spell != NULL) - { - set_language_from_metadata (spell, doc); - } - - data = g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - - set_auto_spell_from_metadata (window, doc, data->action_group); - } -} - -static void -on_document_saved (GeditDocument *doc, - const GError *error, - GeditWindow *window) -{ - GeditAutomaticSpellChecker *autospell; - GeditSpellChecker *spell; - const gchar *key; - - if (error != NULL) - { - return; - } - - /* Make sure to save the metadata here too */ - autospell = gedit_automatic_spell_checker_get_from_document (doc); - spell = GEDIT_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id)); - - if (spell != NULL) - { - key = gedit_spell_checker_language_to_key (gedit_spell_checker_get_language (spell)); - } - else - { - key = NULL; - } - - gedit_document_set_metadata (doc, - GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED, - autospell != NULL ? "1" : NULL, - GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE, - key, - NULL); -} - -static void -tab_added_cb (GeditWindow *window, - GeditTab *tab, - gpointer useless) -{ - GeditDocument *doc; - GeditView *view; - - doc = gedit_tab_get_document (tab); - view = gedit_tab_get_view (tab); - - g_signal_connect (doc, "loaded", - G_CALLBACK (on_document_loaded), - window); - - g_signal_connect (doc, "saved", - G_CALLBACK (on_document_saved), - window); -} - -static void -tab_removed_cb (GeditWindow *window, - GeditTab *tab, - gpointer useless) -{ - GeditDocument *doc; - GeditView *view; - - doc = gedit_tab_get_document (tab); - view = gedit_tab_get_view (tab); - - g_signal_handlers_disconnect_by_func (doc, on_document_loaded, window); - g_signal_handlers_disconnect_by_func (doc, on_document_saved, window); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - ActionData *action_data; - GList *docs, *l; - - gedit_debug (DEBUG_PLUGINS); - - data = g_slice_new (WindowData); - action_data = g_slice_new (ActionData); - action_data->plugin = plugin; - action_data->window = window; - - manager = gedit_window_get_ui_manager (window); - - data->action_group = gtk_action_group_new ("GeditSpellPluginActions"); - gtk_action_group_set_translation_domain (data->action_group, - GETTEXT_PACKAGE); - gtk_action_group_add_actions_full (data->action_group, - action_entries, - G_N_ELEMENTS (action_entries), - action_data, - (GDestroyNotify) free_action_data); - gtk_action_group_add_toggle_actions (data->action_group, - toggle_action_entries, - G_N_ELEMENTS (toggle_action_entries), - window); - - gtk_ui_manager_insert_action_group (manager, data->action_group, -1); - - data->ui_id = gtk_ui_manager_new_merge_id (manager); - - data->message_cid = gtk_statusbar_get_context_id - (GTK_STATUSBAR (gedit_window_get_statusbar (window)), - "spell_plugin_message"); - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - (GDestroyNotify) free_window_data); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "CheckSpell", - "CheckSpell", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "AutoSpell", - "AutoSpell", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "ConfigSpell", - "ConfigSpell", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - update_ui_real (window, data); - - docs = gedit_window_get_documents (window); - for (l = docs; l != NULL; l = g_list_next (l)) - { - GeditDocument *doc = GEDIT_DOCUMENT (l->data); - - set_auto_spell_from_metadata (window, doc, - data->action_group); - - g_signal_handlers_disconnect_by_func (doc, - on_document_loaded, - window); - - g_signal_handlers_disconnect_by_func (doc, - on_document_saved, - window); - } - - data->tab_added_id = - g_signal_connect (window, "tab-added", - G_CALLBACK (tab_added_cb), NULL); - data->tab_removed_id = - g_signal_connect (window, "tab-removed", - G_CALLBACK (tab_removed_cb), NULL); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - manager = gedit_window_get_ui_manager (window); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - gtk_ui_manager_remove_ui (manager, data->ui_id); - gtk_ui_manager_remove_action_group (manager, data->action_group); - - g_signal_handler_disconnect (window, data->tab_added_id); - g_signal_handler_disconnect (window, data->tab_removed_id); - - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - update_ui_real (window, data); -} - -static void -gedit_spell_plugin_class_init (GeditSpellPluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_spell_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; - - if (spell_checker_id == 0) - spell_checker_id = g_quark_from_string ("GeditSpellCheckerID"); - - if (check_range_id == 0) - check_range_id = g_quark_from_string ("CheckRangeID"); -} diff --git a/plugins/spell/gedit-spell-plugin.h b/plugins/spell/gedit-spell-plugin.h deleted file mode 100755 index 7de5807a..00000000 --- a/plugins/spell/gedit-spell-plugin.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * gedit-spell-plugin.h - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifndef __GEDIT_SPELL_PLUGIN_H__ -#define __GEDIT_SPELL_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_SPELL_PLUGIN (gedit_spell_plugin_get_type ()) -#define GEDIT_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_SPELL_PLUGIN, GeditSpellPlugin)) -#define GEDIT_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_SPELL_PLUGIN, GeditSpellPluginClass)) -#define GEDIT_IS_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_SPELL_PLUGIN)) -#define GEDIT_IS_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_SPELL_PLUGIN)) -#define GEDIT_SPELL_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_SPELL_PLUGIN, GeditSpellPluginClass)) - -/* Private structure type */ -typedef struct _GeditSpellPluginPrivate GeditSpellPluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditSpellPlugin GeditSpellPlugin; - -struct _GeditSpellPlugin -{ - GeditPlugin parent_instance; -}; - -/* - * Class definition - */ -typedef struct _GeditSpellPluginClass GeditSpellPluginClass; - -struct _GeditSpellPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_spell_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_PLUGIN_H__ */ diff --git a/plugins/spell/gedit-spell-utils.c b/plugins/spell/gedit-spell-utils.c deleted file mode 100755 index 0782d37a..00000000 --- a/plugins/spell/gedit-spell-utils.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * gedit-spell-utils.c - * This file is part of gedit - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include - -#include "gedit-spell-utils.h" -#include - -gboolean -gedit_spell_utils_is_digit (const char *text, gssize length) -{ - gunichar c; - const gchar *p; - const gchar *end; - - g_return_val_if_fail (text != NULL, FALSE); - - if (length < 0) - length = strlen (text); - - p = text; - end = text + length; - - while (p != end) { - const gchar *next; - next = g_utf8_next_char (p); - - c = g_utf8_get_char (p); - - if (!g_unichar_isdigit (c) && c != '.' && c != ',') - return FALSE; - - p = next; - } - - return TRUE; -} - -gboolean -gedit_spell_utils_skip_no_spell_check (GtkTextIter *start, - GtkTextIter *end) -{ - GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (start)); - - while (gtk_source_buffer_iter_has_context_class (buffer, start, "no-spell-check")) - { - GtkTextIter last = *start; - - if (!gtk_source_buffer_iter_forward_to_context_class_toggle (buffer, start, "no-spell-check")) - { - return FALSE; - } - - if (gtk_text_iter_compare (start, &last) <= 0) - { - return FALSE; - } - - gtk_text_iter_forward_word_end (start); - gtk_text_iter_backward_word_start (start); - - if (gtk_text_iter_compare (start, &last) <= 0) - { - return FALSE; - } - - if (gtk_text_iter_compare (start, end) >= 0) - { - return FALSE; - } - } - - return TRUE; -} - diff --git a/plugins/spell/gedit-spell-utils.h b/plugins/spell/gedit-spell-utils.h deleted file mode 100755 index fbfe4b1b..00000000 --- a/plugins/spell/gedit-spell-utils.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * gedit-spell-utils.h - * This file is part of gedit - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GEDIT_SPELL_UTILS_H__ -#define __GEDIT_SPELL_UTILS_H__ - -#include - -G_BEGIN_DECLS - -gboolean gedit_spell_utils_is_digit (const char *text, gssize length); - -gboolean gedit_spell_utils_skip_no_spell_check (GtkTextIter *start, GtkTextIter *end); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_UTILS_H__ */ - diff --git a/plugins/spell/pluma-automatic-spell-checker.c b/plugins/spell/pluma-automatic-spell-checker.c new file mode 100755 index 00000000..88393379 --- /dev/null +++ b/plugins/spell/pluma-automatic-spell-checker.c @@ -0,0 +1,1015 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-automatic-spell-checker.c + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +/* This is a modified version of gtkspell 2.0.5 (gtkspell.sf.net) */ +/* gtkspell - a spell-checking addon for GTK's TextView widget + * Copyright (c) 2002 Evan Martin. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "pluma-automatic-spell-checker.h" +#include "pluma-spell-utils.h" + +struct _PlumaAutomaticSpellChecker { + PlumaDocument *doc; + GSList *views; + + GtkTextMark *mark_insert_start; + GtkTextMark *mark_insert_end; + gboolean deferred_check; + + GtkTextTag *tag_highlight; + GtkTextMark *mark_click; + + PlumaSpellChecker *spell_checker; +}; + +static GQuark automatic_spell_checker_id = 0; +static GQuark suggestion_id = 0; + +static void pluma_automatic_spell_checker_free_internal (PlumaAutomaticSpellChecker *spell); + +static void +view_destroy (PlumaView *view, PlumaAutomaticSpellChecker *spell) +{ + pluma_automatic_spell_checker_detach_view (spell, view); +} + +static void +check_word (PlumaAutomaticSpellChecker *spell, GtkTextIter *start, GtkTextIter *end) +{ + gchar *word; + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), start, end, FALSE); + + /* + g_print ("Check word: %s [%d - %d]\n", word, gtk_text_iter_get_offset (start), + gtk_text_iter_get_offset (end)); + */ + + if (!pluma_spell_checker_check_word (spell->spell_checker, word, -1)) + { + /* + g_print ("Apply tag: [%d - %d]\n", gtk_text_iter_get_offset (start), + gtk_text_iter_get_offset (end)); + */ + gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + start, + end); + } + + g_free (word); +} + +static void +check_range (PlumaAutomaticSpellChecker *spell, + GtkTextIter start, + GtkTextIter end, + gboolean force_all) +{ + /* we need to "split" on word boundaries. + * luckily, Pango knows what "words" are + * so we don't have to figure it out. */ + + GtkTextIter wstart; + GtkTextIter wend; + GtkTextIter cursor; + GtkTextIter precursor; + gboolean highlight; + + /* + g_print ("Check range: [%d - %d]\n", gtk_text_iter_get_offset (&start), + gtk_text_iter_get_offset (&end)); + */ + + if (gtk_text_iter_inside_word (&end)) + gtk_text_iter_forward_word_end (&end); + + if (!gtk_text_iter_starts_word (&start)) + { + if (gtk_text_iter_inside_word (&start) || + gtk_text_iter_ends_word (&start)) + { + gtk_text_iter_backward_word_start (&start); + } + else + { + /* if we're neither at the beginning nor inside a word, + * me must be in some spaces. + * skip forward to the beginning of the next word. */ + + if (gtk_text_iter_forward_word_end (&start)) + gtk_text_iter_backward_word_start (&start); + } + } + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), + &cursor, + gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (spell->doc))); + + precursor = cursor; + gtk_text_iter_backward_char (&precursor); + + highlight = gtk_text_iter_has_tag (&cursor, spell->tag_highlight) || + gtk_text_iter_has_tag (&precursor, spell->tag_highlight); + + gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + &start, + &end); + + /* Fix a corner case when replacement occurs at beginning of buffer: + * An iter at offset 0 seems to always be inside a word, + * even if it's not. Possibly a pango bug. + */ + if (gtk_text_iter_get_offset (&start) == 0) + { + gtk_text_iter_forward_word_end(&start); + gtk_text_iter_backward_word_start(&start); + } + + wstart = start; + + while (pluma_spell_utils_skip_no_spell_check (&wstart, &end) && + gtk_text_iter_compare (&wstart, &end) < 0) + { + gboolean inword; + + /* move wend to the end of the current word. */ + wend = wstart; + + gtk_text_iter_forward_word_end (&wend); + + inword = (gtk_text_iter_compare (&wstart, &cursor) < 0) && + (gtk_text_iter_compare (&cursor, &wend) <= 0); + + if (inword && !force_all) + { + /* this word is being actively edited, + * only check if it's already highligted, + * otherwise defer this check until later. */ + if (highlight) + check_word (spell, &wstart, &wend); + else + spell->deferred_check = TRUE; + } + else + { + check_word (spell, &wstart, &wend); + spell->deferred_check = FALSE; + } + + /* now move wend to the beginning of the next word, */ + gtk_text_iter_forward_word_end (&wend); + gtk_text_iter_backward_word_start (&wend); + + /* make sure we've actually advanced + * (we don't advance in some corner cases), */ + if (gtk_text_iter_equal (&wstart, &wend)) + break; /* we're done in these cases.. */ + + /* and then pick this as the new next word beginning. */ + wstart = wend; + } +} + +static void +check_deferred_range (PlumaAutomaticSpellChecker *spell, + gboolean force_all) +{ + GtkTextIter start, end; + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), + &start, + spell->mark_insert_start); + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), + &end, + spell->mark_insert_end); + + check_range (spell, start, end, force_all); +} + +/* insertion works like this: + * - before the text is inserted, we mark the position in the buffer. + * - after the text is inserted, we see where our mark is and use that and + * the current position to check the entire range of inserted text. + * + * this may be overkill for the common case (inserting one character). */ + +static void +insert_text_before (GtkTextBuffer *buffer, GtkTextIter *iter, + gchar *text, gint len, PlumaAutomaticSpellChecker *spell) +{ + gtk_text_buffer_move_mark (buffer, spell->mark_insert_start, iter); +} + +static void +insert_text_after (GtkTextBuffer *buffer, GtkTextIter *iter, + gchar *text, gint len, PlumaAutomaticSpellChecker *spell) +{ + GtkTextIter start; + + /* we need to check a range of text. */ + gtk_text_buffer_get_iter_at_mark (buffer, &start, spell->mark_insert_start); + + check_range (spell, start, *iter, FALSE); + + gtk_text_buffer_move_mark (buffer, spell->mark_insert_end, iter); +} + +/* deleting is more simple: we're given the range of deleted text. + * after deletion, the start and end iters should be at the same position + * (because all of the text between them was deleted!). + * this means we only really check the words immediately bounding the + * deletion. + */ + +static void +delete_range_after (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, + PlumaAutomaticSpellChecker *spell) +{ + check_range (spell, *start, *end, FALSE); +} + +static void +mark_set (GtkTextBuffer *buffer, + GtkTextIter *iter, + GtkTextMark *mark, + PlumaAutomaticSpellChecker *spell) +{ + /* if the cursor has moved and there is a deferred check so handle it now */ + if ((mark == gtk_text_buffer_get_insert (buffer)) && spell->deferred_check) + check_deferred_range (spell, FALSE); +} + +static void +get_word_extents_from_mark (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end, + GtkTextMark *mark) +{ + gtk_text_buffer_get_iter_at_mark(buffer, start, mark); + + if (!gtk_text_iter_starts_word (start)) + gtk_text_iter_backward_word_start (start); + + *end = *start; + + if (gtk_text_iter_inside_word (end)) + gtk_text_iter_forward_word_end (end); +} + +static void +remove_tag_to_word (PlumaAutomaticSpellChecker *spell, const gchar *word) +{ + GtkTextIter iter; + GtkTextIter match_start, match_end; + + gboolean found; + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (spell->doc), &iter, 0); + + found = TRUE; + + while (found) + { + found = gtk_text_iter_forward_search (&iter, + word, + GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY, + &match_start, + &match_end, + NULL); + + if (found) + { + if (gtk_text_iter_starts_word (&match_start) && + gtk_text_iter_ends_word (&match_end)) + { + gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + &match_start, + &match_end); + } + + iter = match_end; + } + } +} + +static void +add_to_dictionary (GtkWidget *menuitem, PlumaAutomaticSpellChecker *spell) +{ + gchar *word; + + GtkTextIter start, end; + + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), + &start, + &end, + FALSE); + + pluma_spell_checker_add_word_to_personal (spell->spell_checker, word, -1); + + g_free (word); +} + +static void +ignore_all (GtkWidget *menuitem, PlumaAutomaticSpellChecker *spell) +{ + gchar *word; + + GtkTextIter start, end; + + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), + &start, + &end, + FALSE); + + pluma_spell_checker_add_word_to_session (spell->spell_checker, word, -1); + + g_free (word); +} + +static void +replace_word (GtkWidget *menuitem, PlumaAutomaticSpellChecker *spell) +{ + gchar *oldword; + const gchar *newword; + + GtkTextIter start, end; + + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + oldword = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); + + newword = g_object_get_qdata (G_OBJECT (menuitem), suggestion_id); + g_return_if_fail (newword != NULL); + + gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (spell->doc)); + + gtk_text_buffer_delete (GTK_TEXT_BUFFER (spell->doc), &start, &end); + gtk_text_buffer_insert (GTK_TEXT_BUFFER (spell->doc), &start, newword, -1); + + gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (spell->doc)); + + pluma_spell_checker_set_correction (spell->spell_checker, + oldword, strlen (oldword), + newword, strlen (newword)); + + g_free (oldword); +} + +static GtkWidget * +build_suggestion_menu (PlumaAutomaticSpellChecker *spell, const gchar *word) +{ + GtkWidget *topmenu, *menu; + GtkWidget *mi; + GSList *suggestions; + GSList *list; + gchar *label_text; + + topmenu = menu = gtk_menu_new(); + + suggestions = pluma_spell_checker_get_suggestions (spell->spell_checker, word, -1); + + list = suggestions; + + if (suggestions == NULL) + { + /* no suggestions. put something in the menu anyway... */ + GtkWidget *label; + /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions for the current misspelled word */ + label = gtk_label_new (_("(no suggested words)")); + + mi = gtk_menu_item_new (); + gtk_widget_set_sensitive (mi, FALSE); + gtk_container_add (GTK_CONTAINER(mi), label); + gtk_widget_show_all (mi); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); + } + else + { + gint count = 0; + + /* build a set of menus with suggestions. */ + while (suggestions != NULL) + { + GtkWidget *label; + + if (count == 10) + { + /* Separator */ + mi = gtk_menu_item_new (); + gtk_widget_show (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + mi = gtk_menu_item_new_with_mnemonic (_("_More...")); + gtk_widget_show (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu); + count = 0; + } + + label_text = g_strdup_printf ("%s", (gchar*) suggestions->data); + + label = gtk_label_new (label_text); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + + mi = gtk_menu_item_new (); + gtk_container_add (GTK_CONTAINER(mi), label); + + gtk_widget_show_all (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + g_object_set_qdata_full (G_OBJECT (mi), + suggestion_id, + g_strdup (suggestions->data), + (GDestroyNotify)g_free); + + g_free (label_text); + g_signal_connect (mi, + "activate", + G_CALLBACK (replace_word), + spell); + + count++; + + suggestions = g_slist_next (suggestions); + } + } + + /* free the suggestion list */ + suggestions = list; + + while (list) + { + g_free (list->data); + list = g_slist_next (list); + } + + g_slist_free (suggestions); + + /* Separator */ + mi = gtk_menu_item_new (); + gtk_widget_show (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); + + /* Ignore all */ + mi = gtk_image_menu_item_new_with_mnemonic (_("_Ignore All")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), + gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, + GTK_ICON_SIZE_MENU)); + + g_signal_connect (mi, + "activate", + G_CALLBACK(ignore_all), + spell); + + gtk_widget_show_all (mi); + + gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); + + /* + Add to Dictionary */ + mi = gtk_image_menu_item_new_with_mnemonic (_("_Add")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), + gtk_image_new_from_stock (GTK_STOCK_ADD, + GTK_ICON_SIZE_MENU)); + + g_signal_connect (mi, + "activate", + G_CALLBACK (add_to_dictionary), + spell); + + gtk_widget_show_all (mi); + + gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); + + return topmenu; +} + +static void +populate_popup (GtkTextView *textview, GtkMenu *menu, PlumaAutomaticSpellChecker *spell) +{ + GtkWidget *img, *mi; + GtkTextIter start, end; + char *word; + + /* we need to figure out if they picked a misspelled word. */ + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + /* if our highlight algorithm ever messes up, + * this isn't correct, either. */ + if (!gtk_text_iter_has_tag (&start, spell->tag_highlight)) + return; /* word wasn't misspelled. */ + + /* menu separator comes first. */ + mi = gtk_menu_item_new (); + gtk_widget_show (mi); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); + + /* then, on top of it, the suggestions menu. */ + img = gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); + mi = gtk_image_menu_item_new_with_mnemonic (_("_Spelling Suggestions...")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img); + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), + build_suggestion_menu (spell, word)); + g_free(word); + + gtk_widget_show_all (mi); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); +} + +void +pluma_automatic_spell_checker_recheck_all (PlumaAutomaticSpellChecker *spell) +{ + GtkTextIter start, end; + + g_return_if_fail (spell != NULL); + + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end); + + check_range (spell, start, end, TRUE); +} + +static void +add_word_signal_cb (PlumaSpellChecker *checker, + const gchar *word, + gint len, + PlumaAutomaticSpellChecker *spell) +{ + gchar *w; + + if (len < 0) + w = g_strdup (word); + else + w = g_strndup (word, len); + + remove_tag_to_word (spell, w); + + g_free (w); +} + +static void +set_language_cb (PlumaSpellChecker *checker, + const PlumaSpellCheckerLanguage *lang, + PlumaAutomaticSpellChecker *spell) +{ + pluma_automatic_spell_checker_recheck_all (spell); +} + +static void +clear_session_cb (PlumaSpellChecker *checker, + PlumaAutomaticSpellChecker *spell) +{ + pluma_automatic_spell_checker_recheck_all (spell); +} + +/* When the user right-clicks on a word, they want to check that word. + * Here, we do NOT move the cursor to the location of the clicked-upon word + * since that prevents the use of edit functions on the context menu. + */ +static gboolean +button_press_event (GtkTextView *view, + GdkEventButton *event, + PlumaAutomaticSpellChecker *spell) +{ + if (event->button == 3) + { + gint x, y; + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer (view); + + /* handle deferred check if it exists */ + if (spell->deferred_check) + check_deferred_range (spell, TRUE); + + gtk_text_view_window_to_buffer_coords (view, + GTK_TEXT_WINDOW_TEXT, + event->x, event->y, + &x, &y); + + gtk_text_view_get_iter_at_location (view, &iter, x, y); + + gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); + } + + return FALSE; /* false: let gtk process this event, too. + we don't want to eat any events. */ +} + +/* Move the insert mark before popping up the menu, otherwise it + * will contain the wrong set of suggestions. + */ +static gboolean +popup_menu_event (GtkTextView *view, PlumaAutomaticSpellChecker *spell) +{ + GtkTextIter iter; + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer (view); + + /* handle deferred check if it exists */ + if (spell->deferred_check) + check_deferred_range (spell, TRUE); + + gtk_text_buffer_get_iter_at_mark (buffer, &iter, + gtk_text_buffer_get_insert (buffer)); + gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); + + return FALSE; +} + +static void +tag_table_changed (GtkTextTagTable *table, + PlumaAutomaticSpellChecker *spell) +{ + g_return_if_fail (spell->tag_highlight != NULL); + + gtk_text_tag_set_priority (spell->tag_highlight, + gtk_text_tag_table_get_size (table) - 1); +} + +static void +tag_added_or_removed (GtkTextTagTable *table, + GtkTextTag *tag, + PlumaAutomaticSpellChecker *spell) +{ + tag_table_changed (table, spell); +} + +static void +tag_changed (GtkTextTagTable *table, + GtkTextTag *tag, + gboolean size_changed, + PlumaAutomaticSpellChecker *spell) +{ + tag_table_changed (table, spell); +} + +static void +highlight_updated (GtkSourceBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end, + PlumaAutomaticSpellChecker *spell) +{ + check_range (spell, *start, *end, FALSE); +} + +static void +spell_tag_destroyed (PlumaAutomaticSpellChecker *spell, + GObject *where_the_object_was) +{ + spell->tag_highlight = NULL; +} + +PlumaAutomaticSpellChecker * +pluma_automatic_spell_checker_new (PlumaDocument *doc, + PlumaSpellChecker *checker) +{ + PlumaAutomaticSpellChecker *spell; + GtkTextTagTable *tag_table; + GtkTextIter start, end; + + g_return_val_if_fail (PLUMA_IS_DOCUMENT (doc), NULL); + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (checker), NULL); + g_return_val_if_fail ((spell = pluma_automatic_spell_checker_get_from_document (doc)) == NULL, + spell); + + /* attach to the widget */ + spell = g_new0 (PlumaAutomaticSpellChecker, 1); + + spell->doc = doc; + spell->spell_checker = g_object_ref (checker); + + if (automatic_spell_checker_id == 0) + { + automatic_spell_checker_id = + g_quark_from_string ("PlumaAutomaticSpellCheckerID"); + } + if (suggestion_id == 0) + { + suggestion_id = g_quark_from_string ("PlumaAutoSuggestionID"); + } + + g_object_set_qdata_full (G_OBJECT (doc), + automatic_spell_checker_id, + spell, + (GDestroyNotify)pluma_automatic_spell_checker_free_internal); + + g_signal_connect (doc, + "insert-text", + G_CALLBACK (insert_text_before), + spell); + g_signal_connect_after (doc, + "insert-text", + G_CALLBACK (insert_text_after), + spell); + g_signal_connect_after (doc, + "delete-range", + G_CALLBACK (delete_range_after), + spell); + g_signal_connect (doc, + "mark-set", + G_CALLBACK (mark_set), + spell); + + g_signal_connect (doc, + "highlight-updated", + G_CALLBACK (highlight_updated), + spell); + + g_signal_connect (spell->spell_checker, + "add_word_to_session", + G_CALLBACK (add_word_signal_cb), + spell); + g_signal_connect (spell->spell_checker, + "add_word_to_personal", + G_CALLBACK (add_word_signal_cb), + spell); + g_signal_connect (spell->spell_checker, + "clear_session", + G_CALLBACK (clear_session_cb), + spell); + g_signal_connect (spell->spell_checker, + "set_language", + G_CALLBACK (set_language_cb), + spell); + + spell->tag_highlight = gtk_text_buffer_create_tag ( + GTK_TEXT_BUFFER (doc), + "gtkspell-misspelled", + "underline", PANGO_UNDERLINE_ERROR, + NULL); + + g_object_weak_ref (G_OBJECT (spell->tag_highlight), + (GWeakNotify)spell_tag_destroyed, + spell); + + tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (doc)); + + gtk_text_tag_set_priority (spell->tag_highlight, + gtk_text_tag_table_get_size (tag_table) - 1); + + g_signal_connect (tag_table, + "tag-added", + G_CALLBACK (tag_added_or_removed), + spell); + g_signal_connect (tag_table, + "tag-removed", + G_CALLBACK (tag_added_or_removed), + spell); + g_signal_connect (tag_table, + "tag-changed", + G_CALLBACK (tag_changed), + spell); + + /* we create the mark here, but we don't use it until text is + * inserted, so we don't really care where iter points. */ + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end); + + spell->mark_insert_start = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-start"); + + if (spell->mark_insert_start == NULL) + { + spell->mark_insert_start = + gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-start", + &start, + TRUE); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + spell->mark_insert_start, + &start); + } + + spell->mark_insert_end = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-end"); + + if (spell->mark_insert_end == NULL) + { + spell->mark_insert_end = + gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-end", + &start, + TRUE); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + spell->mark_insert_end, + &start); + } + + spell->mark_click = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-click"); + + if (spell->mark_click == NULL) + { + spell->mark_click = + gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-click", + &start, + TRUE); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + spell->mark_click, + &start); + } + + spell->deferred_check = FALSE; + + return spell; +} + +PlumaAutomaticSpellChecker * +pluma_automatic_spell_checker_get_from_document (const PlumaDocument *doc) +{ + g_return_val_if_fail (PLUMA_IS_DOCUMENT (doc), NULL); + + if (automatic_spell_checker_id == 0) + return NULL; + + return g_object_get_qdata (G_OBJECT (doc), automatic_spell_checker_id); +} + +void +pluma_automatic_spell_checker_free (PlumaAutomaticSpellChecker *spell) +{ + g_return_if_fail (spell != NULL); + g_return_if_fail (pluma_automatic_spell_checker_get_from_document (spell->doc) == spell); + + if (automatic_spell_checker_id == 0) + return; + + g_object_set_qdata (G_OBJECT (spell->doc), automatic_spell_checker_id, NULL); +} + +static void +pluma_automatic_spell_checker_free_internal (PlumaAutomaticSpellChecker *spell) +{ + GtkTextTagTable *table; + GtkTextIter start, end; + GSList *list; + + g_return_if_fail (spell != NULL); + + table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (spell->doc)); + + if (table != NULL && spell->tag_highlight != NULL) + { + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), + &start, + &end); + gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + &start, + &end); + + g_signal_handlers_disconnect_matched (G_OBJECT (table), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + gtk_text_tag_table_remove (table, spell->tag_highlight); + } + + g_signal_handlers_disconnect_matched (G_OBJECT (spell->doc), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_signal_handlers_disconnect_matched (G_OBJECT (spell->spell_checker), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_object_unref (spell->spell_checker); + + list = spell->views; + while (list != NULL) + { + PlumaView *view = PLUMA_VIEW (list->data); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + list = g_slist_next (list); + } + + g_slist_free (spell->views); + + g_free (spell); +} + +void +pluma_automatic_spell_checker_attach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view) +{ + g_return_if_fail (spell != NULL); + g_return_if_fail (PLUMA_IS_VIEW (view)); + + g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == + GTK_TEXT_BUFFER (spell->doc)); + + g_signal_connect (view, + "button-press-event", + G_CALLBACK (button_press_event), + spell); + g_signal_connect (view, + "popup-menu", + G_CALLBACK (popup_menu_event), + spell); + g_signal_connect (view, + "populate-popup", + G_CALLBACK (populate_popup), + spell); + g_signal_connect (view, + "destroy", + G_CALLBACK (view_destroy), + spell); + + spell->views = g_slist_prepend (spell->views, view); +} + +void +pluma_automatic_spell_checker_detach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view) +{ + g_return_if_fail (spell != NULL); + g_return_if_fail (PLUMA_IS_VIEW (view)); + + g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == + GTK_TEXT_BUFFER (spell->doc)); + g_return_if_fail (spell->views != NULL); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + spell->views = g_slist_remove (spell->views, view); +} + diff --git a/plugins/spell/pluma-automatic-spell-checker.h b/plugins/spell/pluma-automatic-spell-checker.h new file mode 100755 index 00000000..3a5f2487 --- /dev/null +++ b/plugins/spell/pluma-automatic-spell-checker.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-automatic-spell-checker.h + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +/* This is a modified version of gtkspell 2.0.2 (gtkspell.sf.net) */ +/* gtkspell - a spell-checking addon for GTK's TextView widget + * Copyright (c) 2002 Evan Martin. + */ + +#ifndef __PLUMA_AUTOMATIC_SPELL_CHECKER_H__ +#define __PLUMA_AUTOMATIC_SPELL_CHECKER_H__ + +#include +#include + +#include "pluma-spell-checker.h" + +typedef struct _PlumaAutomaticSpellChecker PlumaAutomaticSpellChecker; + +PlumaAutomaticSpellChecker *pluma_automatic_spell_checker_new ( + PlumaDocument *doc, + PlumaSpellChecker *checker); + +PlumaAutomaticSpellChecker *pluma_automatic_spell_checker_get_from_document ( + const PlumaDocument *doc); + +void pluma_automatic_spell_checker_free ( + PlumaAutomaticSpellChecker *spell); + +void pluma_automatic_spell_checker_attach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view); + +void pluma_automatic_spell_checker_detach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view); + +void pluma_automatic_spell_checker_recheck_all ( + PlumaAutomaticSpellChecker *spell); + +#endif /* __PLUMA_AUTOMATIC_SPELL_CHECKER_H__ */ + diff --git a/plugins/spell/pluma-spell-checker-dialog.c b/plugins/spell/pluma-spell-checker-dialog.c new file mode 100755 index 00000000..067e79e7 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-dialog.c @@ -0,0 +1,722 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-dialog.c + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "pluma-spell-checker-dialog.h" +#include "pluma-spell-marshal.h" + +struct _PlumaSpellCheckerDialog +{ + GtkWindow parent_instance; + + PlumaSpellChecker *spell_checker; + + gchar *misspelled_word; + + GtkWidget *misspelled_word_label; + GtkWidget *word_entry; + GtkWidget *check_word_button; + GtkWidget *ignore_button; + GtkWidget *ignore_all_button; + GtkWidget *change_button; + GtkWidget *change_all_button; + GtkWidget *add_word_button; + GtkWidget *close_button; + GtkWidget *suggestions_list; + GtkWidget *language_label; + + GtkTreeModel *suggestions_list_model; +}; + +enum +{ + IGNORE, + IGNORE_ALL, + CHANGE, + CHANGE_ALL, + ADD_WORD_TO_PERSONAL, + LAST_SIGNAL +}; + +enum +{ + COLUMN_SUGGESTIONS, + NUM_COLUMNS +}; + +static void update_suggestions_list_model (PlumaSpellCheckerDialog *dlg, + GSList *suggestions); + +static void word_entry_changed_handler (GtkEditable *editable, + PlumaSpellCheckerDialog *dlg); +static void close_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void suggestions_list_selection_changed_handler (GtkTreeSelection *selection, + PlumaSpellCheckerDialog *dlg); +static void check_word_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void add_word_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void ignore_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void ignore_all_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void change_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void change_all_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void suggestions_list_row_activated_handler (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaSpellCheckerDialog *dlg); + + +static guint signals [LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(PlumaSpellCheckerDialog, pluma_spell_checker_dialog, GTK_TYPE_WINDOW) + +static void +pluma_spell_checker_dialog_destroy (GtkObject *object) +{ + PlumaSpellCheckerDialog *dlg = PLUMA_SPELL_CHECKER_DIALOG (object); + + if (dlg->spell_checker != NULL) + { + g_object_unref (dlg->spell_checker); + dlg->spell_checker = NULL; + } + + if (dlg->misspelled_word != NULL) + { + g_free (dlg->misspelled_word); + dlg->misspelled_word = NULL; + } + + GTK_OBJECT_CLASS (pluma_spell_checker_dialog_parent_class)->destroy (object); +} + +static void +pluma_spell_checker_dialog_class_init (PlumaSpellCheckerDialogClass * klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + GTK_OBJECT_CLASS (object_class)->destroy = pluma_spell_checker_dialog_destroy; + + signals[IGNORE] = + g_signal_new ("ignore", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, ignore), + NULL, NULL, + pluma_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + signals[IGNORE_ALL] = + g_signal_new ("ignore_all", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, ignore_all), + NULL, NULL, + pluma_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + signals[CHANGE] = + g_signal_new ("change", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, change), + NULL, NULL, + pluma_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + + signals[CHANGE_ALL] = + g_signal_new ("change_all", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, change_all), + NULL, NULL, + pluma_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + + signals[ADD_WORD_TO_PERSONAL] = + g_signal_new ("add_word_to_personal", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, add_word_to_personal), + NULL, NULL, + pluma_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + +static void +create_dialog (PlumaSpellCheckerDialog *dlg, + const gchar *data_dir) +{ + GtkWidget *error_widget; + GtkWidget *content; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkTreeSelection *selection; + gchar *root_objects[] = { + "content", + "check_word_image", + "add_word_image", + "ignore_image", + "change_image", + "ignore_all_image", + "change_all_image", + NULL + }; + gboolean ret; + gchar *ui_file; + + g_return_if_fail (dlg != NULL); + + dlg->spell_checker = NULL; + dlg->misspelled_word = NULL; + + ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + root_objects, + &error_widget, + + "content", &content, + "misspelled_word_label", &dlg->misspelled_word_label, + "word_entry", &dlg->word_entry, + "check_word_button", &dlg->check_word_button, + "ignore_button", &dlg->ignore_button, + "ignore_all_button", &dlg->ignore_all_button, + "change_button", &dlg->change_button, + "change_all_button", &dlg->change_all_button, + "add_word_button", &dlg->add_word_button, + "close_button", &dlg->close_button, + "suggestions_list", &dlg->suggestions_list, + "language_label", &dlg->language_label, + NULL); + g_free (ui_file); + + if (!ret) + { + gtk_widget_show (error_widget); + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + error_widget, TRUE, TRUE, 0); + + return; + } + + gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), ""); + gtk_widget_set_sensitive (dlg->word_entry, FALSE); + gtk_widget_set_sensitive (dlg->check_word_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); + gtk_widget_set_sensitive (dlg->change_button, FALSE); + gtk_widget_set_sensitive (dlg->change_all_button, FALSE); + gtk_widget_set_sensitive (dlg->add_word_button, FALSE); + + gtk_label_set_label (GTK_LABEL (dlg->language_label), ""); + + gtk_container_add (GTK_CONTAINER (dlg), content); + g_object_unref (content); + + gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE); + gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling")); + + /* Suggestion list */ + dlg->suggestions_list_model = GTK_TREE_MODEL ( + gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING)); + + gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list), + dlg->suggestions_list_model); + + /* Add the suggestions column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell, + "text", COLUMN_SUGGESTIONS, NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column); + + gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list), + COLUMN_SUGGESTIONS); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); + + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + /* Set default button */ + GTK_WIDGET_SET_FLAGS (dlg->change_button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (dlg->change_button); + + gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE); + + /* Connect signals */ + g_signal_connect (dlg->word_entry, "changed", + G_CALLBACK (word_entry_changed_handler), dlg); + g_signal_connect (dlg->close_button, "clicked", + G_CALLBACK (close_button_clicked_handler), dlg); + g_signal_connect (selection, "changed", + G_CALLBACK (suggestions_list_selection_changed_handler), + dlg); + g_signal_connect (dlg->check_word_button, "clicked", + G_CALLBACK (check_word_button_clicked_handler), dlg); + g_signal_connect (dlg->add_word_button, "clicked", + G_CALLBACK (add_word_button_clicked_handler), dlg); + g_signal_connect (dlg->ignore_button, "clicked", + G_CALLBACK (ignore_button_clicked_handler), dlg); + g_signal_connect (dlg->ignore_all_button, "clicked", + G_CALLBACK (ignore_all_button_clicked_handler), dlg); + g_signal_connect (dlg->change_button, "clicked", + G_CALLBACK (change_button_clicked_handler), dlg); + g_signal_connect (dlg->change_all_button, "clicked", + G_CALLBACK (change_all_button_clicked_handler), dlg); + g_signal_connect (dlg->suggestions_list, "row-activated", + G_CALLBACK (suggestions_list_row_activated_handler), dlg); +} + +static void +pluma_spell_checker_dialog_init (PlumaSpellCheckerDialog *dlg) +{ +} + +GtkWidget * +pluma_spell_checker_dialog_new (const gchar *data_dir) +{ + PlumaSpellCheckerDialog *dlg; + + dlg = PLUMA_SPELL_CHECKER_DIALOG ( + g_object_new (PLUMA_TYPE_SPELL_CHECKER_DIALOG, NULL)); + + g_return_val_if_fail (dlg != NULL, NULL); + + create_dialog (dlg, data_dir); + + return GTK_WIDGET (dlg); +} + +GtkWidget * +pluma_spell_checker_dialog_new_from_spell_checker (PlumaSpellChecker *spell, + const gchar *data_dir) +{ + PlumaSpellCheckerDialog *dlg; + + g_return_val_if_fail (spell != NULL, NULL); + + dlg = PLUMA_SPELL_CHECKER_DIALOG ( + g_object_new (PLUMA_TYPE_SPELL_CHECKER_DIALOG, NULL)); + + g_return_val_if_fail (dlg != NULL, NULL); + + create_dialog (dlg, data_dir); + + pluma_spell_checker_dialog_set_spell_checker (dlg, spell); + + return GTK_WIDGET (dlg); +} + +void +pluma_spell_checker_dialog_set_spell_checker (PlumaSpellCheckerDialog *dlg, PlumaSpellChecker *spell) +{ + const PlumaSpellCheckerLanguage* language; + const gchar *lang; + gchar *tmp; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (spell != NULL); + + if (dlg->spell_checker != NULL) + g_object_unref (dlg->spell_checker); + + dlg->spell_checker = spell; + g_object_ref (dlg->spell_checker); + + language = pluma_spell_checker_get_language (dlg->spell_checker); + + lang = pluma_spell_checker_language_to_string (language); + tmp = g_strdup_printf("%s", lang); + + gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp); + g_free (tmp); + + if (dlg->misspelled_word != NULL) + pluma_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1); + else + gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); + + /* TODO: reset all widgets */ +} + +void +pluma_spell_checker_dialog_set_misspelled_word (PlumaSpellCheckerDialog *dlg, + const gchar *word, + gint len) +{ + gchar *tmp; + GSList *sug; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (word != NULL); + + g_return_if_fail (dlg->spell_checker != NULL); + g_return_if_fail (!pluma_spell_checker_check_word (dlg->spell_checker, word, -1)); + + /* build_suggestions_list */ + if (dlg->misspelled_word != NULL) + g_free (dlg->misspelled_word); + + dlg->misspelled_word = g_strdup (word); + + tmp = g_strdup_printf("%s", word); + gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp); + g_free (tmp); + + sug = pluma_spell_checker_get_suggestions (dlg->spell_checker, + dlg->misspelled_word, + -1); + + update_suggestions_list_model (dlg, sug); + + /* free the suggestion list */ + g_slist_foreach (sug, (GFunc)g_free, NULL); + g_slist_free (sug); + + gtk_widget_set_sensitive (dlg->ignore_button, TRUE); + gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE); + gtk_widget_set_sensitive (dlg->add_word_button, TRUE); +} + +static void +update_suggestions_list_model (PlumaSpellCheckerDialog *dlg, GSList *suggestions) +{ + GtkListStore *store; + GtkTreeIter iter; + GtkTreeSelection *sel; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model)); + + store = GTK_LIST_STORE (dlg->suggestions_list_model); + gtk_list_store_clear (store); + + gtk_widget_set_sensitive (dlg->word_entry, TRUE); + + if (suggestions == NULL) + { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions + * for the current misspelled word */ + COLUMN_SUGGESTIONS, _("(no suggested words)"), + -1); + + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); + + gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); + + return; + } + + gtk_widget_set_sensitive (dlg->suggestions_list, TRUE); + + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data); + + while (suggestions != NULL) + { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COLUMN_SUGGESTIONS, (gchar*)suggestions->data, + -1); + + suggestions = g_slist_next (suggestions); + } + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); + gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter); + gtk_tree_selection_select_iter (sel, &iter); +} + +static void +word_entry_changed_handler (GtkEditable *editable, PlumaSpellCheckerDialog *dlg) +{ + const gchar *text; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); + + if (g_utf8_strlen (text, -1) > 0) + { + gtk_widget_set_sensitive (dlg->check_word_button, TRUE); + gtk_widget_set_sensitive (dlg->change_button, TRUE); + gtk_widget_set_sensitive (dlg->change_all_button, TRUE); + } + else + { + gtk_widget_set_sensitive (dlg->check_word_button, FALSE); + gtk_widget_set_sensitive (dlg->change_button, FALSE); + gtk_widget_set_sensitive (dlg->change_all_button, FALSE); + } +} + +static void +close_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + gtk_widget_destroy (GTK_WIDGET (dlg)); +} + +static void +suggestions_list_selection_changed_handler (GtkTreeSelection *selection, + PlumaSpellCheckerDialog *dlg) +{ + GtkTreeIter iter; + GValue value = {0, }; + const gchar *text; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) + return; + + gtk_tree_model_get_value (dlg->suggestions_list_model, &iter, + COLUMN_SUGGESTIONS, + &value); + + text = g_value_get_string (&value); + + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text); + + g_value_unset (&value); +} + +static void +check_word_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + const gchar *word; + gssize len; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); + len = strlen (word); + g_return_if_fail (len > 0); + + if (pluma_spell_checker_check_word (dlg->spell_checker, word, len)) + { + GtkListStore *store; + GtkTreeIter iter; + + store = GTK_LIST_STORE (dlg->suggestions_list_model); + gtk_list_store_clear (store); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + /* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */ + COLUMN_SUGGESTIONS, _("(correct spelling)"), + -1); + + gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); + } + else + { + GSList *sug; + + sug = pluma_spell_checker_get_suggestions (dlg->spell_checker, + word, + len); + + update_suggestions_list_model (dlg, sug); + + /* free the suggestion list */ + g_slist_foreach (sug, (GFunc)g_free, NULL); + g_slist_free (sug); + } +} + +static void +add_word_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + pluma_spell_checker_add_word_to_personal (dlg->spell_checker, + dlg->misspelled_word, + -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word); + + g_free (word); +} + +static void +ignore_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word); + + g_free (word); +} + +static void +ignore_all_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + pluma_spell_checker_add_word_to_session (dlg->spell_checker, + dlg->misspelled_word, + -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word); + + g_free (word); +} + +static void +change_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + gchar *change; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); + g_return_if_fail (change != NULL); + g_return_if_fail (*change != '\0'); + + pluma_spell_checker_set_correction (dlg->spell_checker, + dlg->misspelled_word, -1, + change, -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change); + + g_free (word); + g_free (change); +} + +/* double click on one of the suggestions is like clicking on "change" */ +static void +suggestions_list_row_activated_handler (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaSpellCheckerDialog *dlg) +{ + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg); +} + +static void +change_all_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + gchar *change; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); + g_return_if_fail (change != NULL); + g_return_if_fail (*change != '\0'); + + pluma_spell_checker_set_correction (dlg->spell_checker, + dlg->misspelled_word, -1, + change, -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change); + + g_free (word); + g_free (change); +} + +void +pluma_spell_checker_dialog_set_completed (PlumaSpellCheckerDialog *dlg) +{ + gchar *tmp; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + tmp = g_strdup_printf("%s", _("Completed spell checking")); + gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), + tmp); + g_free (tmp); + + gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); + + gtk_widget_set_sensitive (dlg->word_entry, FALSE); + gtk_widget_set_sensitive (dlg->check_word_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); + gtk_widget_set_sensitive (dlg->change_button, FALSE); + gtk_widget_set_sensitive (dlg->change_all_button, FALSE); + gtk_widget_set_sensitive (dlg->add_word_button, FALSE); + gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); +} + diff --git a/plugins/spell/pluma-spell-checker-dialog.h b/plugins/spell/pluma-spell-checker-dialog.h new file mode 100755 index 00000000..5a4082e3 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-dialog.h @@ -0,0 +1,92 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-dialog.h + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_CHECKER_DIALOG_H__ +#define __PLUMA_SPELL_CHECKER_DIALOG_H__ + +#include +#include "pluma-spell-checker.h" + +G_BEGIN_DECLS + +#define PLUMA_TYPE_SPELL_CHECKER_DIALOG (pluma_spell_checker_dialog_get_type ()) +#define PLUMA_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_SPELL_CHECKER_DIALOG, PlumaSpellCheckerDialog)) +#define PLUMA_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_SPELL_CHECKER_DIALOG, PlumaSpellCheckerDialog)) +#define PLUMA_IS_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_SPELL_CHECKER_DIALOG)) +#define PLUMA_IS_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_SPELL_CHECKER_DIALOG)) +#define PLUMA_SPELL_CHECKER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_SPELL_CHECKER_DIALOG, PlumaSpellCheckerDialog)) + + +typedef struct _PlumaSpellCheckerDialog PlumaSpellCheckerDialog; + +typedef struct _PlumaSpellCheckerDialogClass PlumaSpellCheckerDialogClass; + +struct _PlumaSpellCheckerDialogClass +{ + GtkWindowClass parent_class; + + /* Signals */ + void (*ignore) (PlumaSpellCheckerDialog *dlg, + const gchar *word); + void (*ignore_all) (PlumaSpellCheckerDialog *dlg, + const gchar *word); + void (*change) (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change_to); + void (*change_all) (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change_to); + void (*add_word_to_personal) (PlumaSpellCheckerDialog *dlg, + const gchar *word); + +}; + +GType pluma_spell_checker_dialog_get_type (void) G_GNUC_CONST; + +/* Constructors */ +GtkWidget *pluma_spell_checker_dialog_new (const gchar *data_dir); +GtkWidget *pluma_spell_checker_dialog_new_from_spell_checker + (PlumaSpellChecker *spell, + const gchar *data_dir); + +void pluma_spell_checker_dialog_set_spell_checker + (PlumaSpellCheckerDialog *dlg, + PlumaSpellChecker *spell); +void pluma_spell_checker_dialog_set_misspelled_word + (PlumaSpellCheckerDialog *dlg, + const gchar* word, + gint len); + +void pluma_spell_checker_dialog_set_completed + (PlumaSpellCheckerDialog *dlg); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_CHECKER_DIALOG_H__ */ + diff --git a/plugins/spell/pluma-spell-checker-language.c b/plugins/spell/pluma-spell-checker-language.c new file mode 100755 index 00000000..042e7706 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-language.c @@ -0,0 +1,439 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-language.c + * This file is part of pluma + * + * Copyright (C) 2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2006. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +/* Part of the code taked from Epiphany. + * + * Copyright (C) 2003, 2004 Christian Persch + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "pluma-spell-checker-language.h" + +#include + +#define ISO_639_DOMAIN "iso_639" +#define ISO_3166_DOMAIN "iso_3166" + +#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale" + +struct _PlumaSpellCheckerLanguage +{ + gchar *abrev; + gchar *name; +}; + +static gboolean available_languages_initialized = FALSE; +static GSList *available_languages = NULL; + +static GHashTable *iso_639_table = NULL; +static GHashTable *iso_3166_table = NULL; + +static void +bind_iso_domains (void) +{ + static gboolean bound = FALSE; + + if (bound == FALSE) + { + bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR); + bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8"); + + bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR); + bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8"); + + bound = TRUE; + } +} + +static void +read_iso_639_entry (xmlTextReaderPtr reader, + GHashTable *table) +{ + xmlChar *code, *name; + + code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code"); + name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); + + /* Get iso-639-2 code */ + if (code == NULL || code[0] == '\0') + { + xmlFree (code); + /* FIXME: use the 2T or 2B code? */ + code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code"); + } + + if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') + { + g_hash_table_insert (table, code, name); + } + else + { + xmlFree (code); + xmlFree (name); + } +} + +static void +read_iso_3166_entry (xmlTextReaderPtr reader, + GHashTable *table) +{ + xmlChar *code, *name; + + code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code"); + name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); + + if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') + { + char *lcode; + + lcode = g_ascii_strdown ((char *) code, -1); + xmlFree (code); + + /* g_print ("%s -> %s\n", lcode, name); */ + + g_hash_table_insert (table, lcode, name); + } + else + { + xmlFree (code); + xmlFree (name); + } +} + +typedef enum +{ + STATE_START, + STATE_STOP, + STATE_ENTRIES, +} ParserState; + +static void +load_iso_entries (int iso, + GFunc read_entry_func, + gpointer user_data) +{ + xmlTextReaderPtr reader; + ParserState state = STATE_START; + xmlChar iso_entries[32], iso_entry[32]; + char *filename; + int ret = -1; + + pluma_debug_message (DEBUG_PLUGINS, "Loading ISO-%d codes", iso); + + filename = g_strdup_printf (ISO_CODES_PREFIX "/share/xml/iso-codes/iso_%d.xml", iso); + reader = xmlNewTextReaderFilename (filename); + if (reader == NULL) goto out; + + xmlStrPrintf (iso_entries, sizeof (iso_entries), (const xmlChar *)"iso_%d_entries", iso); + xmlStrPrintf (iso_entry, sizeof (iso_entry), (const xmlChar *)"iso_%d_entry", iso); + + ret = xmlTextReaderRead (reader); + + while (ret == 1) + { + const xmlChar *tag; + xmlReaderTypes type; + + tag = xmlTextReaderConstName (reader); + type = xmlTextReaderNodeType (reader); + + if (state == STATE_ENTRIES && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, iso_entry)) + { + read_entry_func (reader, user_data); + } + else if (state == STATE_START && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, iso_entries)) + { + state = STATE_ENTRIES; + } + else if (state == STATE_ENTRIES && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, iso_entries)) + { + state = STATE_STOP; + } + else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE || + type == XML_READER_TYPE_WHITESPACE || + type == XML_READER_TYPE_TEXT || + type == XML_READER_TYPE_COMMENT) + { + /* eat it */ + } + else + { + /* ignore it */ + } + + ret = xmlTextReaderRead (reader); + } + + xmlFreeTextReader (reader); + +out: + if (ret < 0 || state != STATE_STOP) + { + g_warning ("Failed to load ISO-%d codes from %s!\n", + iso, filename); + } + + g_free (filename); +} + +static GHashTable * +create_iso_639_table (void) +{ + GHashTable *table; + + bind_iso_domains (); + table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) xmlFree, + (GDestroyNotify) xmlFree); + + load_iso_entries (639, (GFunc) read_iso_639_entry, table); + + return table; +} + +static GHashTable * +create_iso_3166_table (void) +{ + GHashTable *table; + + bind_iso_domains (); + table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) xmlFree); + + load_iso_entries (3166, (GFunc) read_iso_3166_entry, table); + + return table; +} + +static char * +create_name_for_language (const char *code) +{ + char **str; + char *name = NULL; + const char *langname, *localename; + int len; + + g_return_val_if_fail (iso_639_table != NULL, NULL); + g_return_val_if_fail (iso_3166_table != NULL, NULL); + + str = g_strsplit (code, "_", -1); + len = g_strv_length (str); + g_return_val_if_fail (len != 0, NULL); + + langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]); + + if (len == 1 && langname != NULL) + { + name = g_strdup (dgettext (ISO_639_DOMAIN, langname)); + } + else if (len == 2 && langname != NULL) + { + gchar *locale_code = g_ascii_strdown (str[1], -1); + + localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code); + g_free (locale_code); + + if (localename != NULL) + { + /* Translators: the first %s is the language name, and + * the second %s is the locale name. Example: + * "French (France)" + */ + name = g_strdup_printf (C_("language", "%s (%s)"), + dgettext (ISO_639_DOMAIN, langname), + dgettext (ISO_3166_DOMAIN, localename)); + } + else + { + name = g_strdup_printf (C_("language", "%s (%s)"), + dgettext (ISO_639_DOMAIN, langname), str[1]); + } + } + else + { + /* Translators: this refers to an unknown language code + * (one which isn't in our built-in list). + */ + name = g_strdup_printf (C_("language", "Unknown (%s)"), code); + } + + g_strfreev (str); + + return name; +} + +static void +enumerate_dicts (const char * const lang_tag, + const char * const provider_name, + const char * const provider_desc, + const char * const provider_file, + void * user_data) +{ + gchar *lang_name; + + GTree *dicts = (GTree *)user_data; + + lang_name = create_name_for_language (lang_tag); + g_return_if_fail (lang_name != NULL); + + /* g_print ("%s - %s\n", lang_tag, lang_name); */ + + g_tree_replace (dicts, g_strdup (lang_tag), lang_name); +} + +static gint +key_cmp (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return strcmp (a, b); +} + +static gint +lang_cmp (const PlumaSpellCheckerLanguage *a, + const PlumaSpellCheckerLanguage *b) +{ + return g_utf8_collate (a->name, b->name); +} + +static gboolean +build_langs_list (const gchar *key, + const gchar *value, + gpointer data) +{ + PlumaSpellCheckerLanguage *lang = g_new (PlumaSpellCheckerLanguage, 1); + + lang->abrev = g_strdup (key); + lang->name = g_strdup (value); + + available_languages = g_slist_insert_sorted (available_languages, + lang, + (GCompareFunc)lang_cmp); + + return FALSE; +} + +const GSList * +pluma_spell_checker_get_available_languages (void) +{ + EnchantBroker *broker; + GTree *dicts; + + if (available_languages_initialized) + return available_languages; + + g_return_val_if_fail (available_languages == NULL, NULL); + + available_languages_initialized = TRUE; + + broker = enchant_broker_init (); + g_return_val_if_fail (broker != NULL, NULL); + + /* Use a GTree to efficiently remove duplicates while building the list */ + dicts = g_tree_new_full (key_cmp, + NULL, + (GDestroyNotify)g_free, + (GDestroyNotify)g_free); + + iso_639_table = create_iso_639_table (); + iso_3166_table = create_iso_3166_table (); + + enchant_broker_list_dicts (broker, enumerate_dicts, dicts); + + enchant_broker_free (broker); + + g_hash_table_destroy (iso_639_table); + g_hash_table_destroy (iso_3166_table); + + iso_639_table = NULL; + iso_3166_table = NULL; + + g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL); + + g_tree_destroy (dicts); + + return available_languages; +} + +const gchar * +pluma_spell_checker_language_to_string (const PlumaSpellCheckerLanguage *lang) +{ + if (lang == NULL) + /* Translators: this refers the Default language used by the + * spell checker + */ + return C_("language", "Default"); + + return lang->name; +} + +const gchar * +pluma_spell_checker_language_to_key (const PlumaSpellCheckerLanguage *lang) +{ + g_return_val_if_fail (lang != NULL, NULL); + + return lang->abrev; +} + +const PlumaSpellCheckerLanguage * +pluma_spell_checker_language_from_key (const gchar *key) +{ + const GSList *langs; + + g_return_val_if_fail (key != NULL, NULL); + + langs = pluma_spell_checker_get_available_languages (); + + while (langs != NULL) + { + const PlumaSpellCheckerLanguage *l = (const PlumaSpellCheckerLanguage *)langs->data; + + if (g_ascii_strcasecmp (key, l->abrev) == 0) + return l; + + langs = g_slist_next (langs); + } + + return NULL; +} diff --git a/plugins/spell/pluma-spell-checker-language.h b/plugins/spell/pluma-spell-checker-language.h new file mode 100755 index 00000000..8bae47a4 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-language.h @@ -0,0 +1,51 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-language.h + * This file is part of pluma + * + * Copyright (C) 2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2006. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_CHECKER_LANGUAGE_H__ +#define __PLUMA_SPELL_CHECKER_LANGUAGE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PlumaSpellCheckerLanguage PlumaSpellCheckerLanguage; + +const gchar *pluma_spell_checker_language_to_string (const PlumaSpellCheckerLanguage *lang); + +const gchar *pluma_spell_checker_language_to_key (const PlumaSpellCheckerLanguage *lang); + +const PlumaSpellCheckerLanguage *pluma_spell_checker_language_from_key (const gchar *key); + +/* GSList contains "PlumaSpellCheckerLanguage*" items */ +const GSList *pluma_spell_checker_get_available_languages + (void); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_CHECKER_LANGUAGE_H__ */ diff --git a/plugins/spell/pluma-spell-checker.c b/plugins/spell/pluma-spell-checker.c new file mode 100755 index 00000000..24cfcdd5 --- /dev/null +++ b/plugins/spell/pluma-spell-checker.c @@ -0,0 +1,520 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker.c + * This file is part of pluma + * + * Copyright (C) 2002-2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002-2006. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "pluma-spell-checker.h" +#include "pluma-spell-utils.h" +#include "pluma-spell-marshal.h" + +struct _PlumaSpellChecker +{ + GObject parent_instance; + + EnchantDict *dict; + EnchantBroker *broker; + const PlumaSpellCheckerLanguage *active_lang; +}; + +/* GObject properties */ +enum { + PROP_0 = 0, + PROP_LANGUAGE, + LAST_PROP +}; + +/* Signals */ +enum { + ADD_WORD_TO_PERSONAL = 0, + ADD_WORD_TO_SESSION, + SET_LANGUAGE, + CLEAR_SESSION, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(PlumaSpellChecker, pluma_spell_checker, G_TYPE_OBJECT) + +static void +pluma_spell_checker_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + /* + PlumaSpellChecker *spell = PLUMA_SPELL_CHECKER (object); + */ + + switch (prop_id) + { + case PROP_LANGUAGE: + /* TODO */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +pluma_spell_checker_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + /* + PlumaSpellChecker *spell = PLUMA_SPELL_CHECKER (object); + */ + + switch (prop_id) + { + case PROP_LANGUAGE: + /* TODO */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +pluma_spell_checker_finalize (GObject *object) +{ + PlumaSpellChecker *spell_checker; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER (object)); + + spell_checker = PLUMA_SPELL_CHECKER (object); + + if (spell_checker->dict != NULL) + enchant_broker_free_dict (spell_checker->broker, spell_checker->dict); + + if (spell_checker->broker != NULL) + enchant_broker_free (spell_checker->broker); + + G_OBJECT_CLASS (pluma_spell_checker_parent_class)->finalize (object); +} + +static void +pluma_spell_checker_class_init (PlumaSpellCheckerClass * klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = pluma_spell_checker_set_property; + object_class->get_property = pluma_spell_checker_get_property; + + object_class->finalize = pluma_spell_checker_finalize; + + g_object_class_install_property (object_class, + PROP_LANGUAGE, + g_param_spec_pointer ("language", + "Language", + "The language used by the spell checker", + G_PARAM_READWRITE)); + + signals[ADD_WORD_TO_PERSONAL] = + g_signal_new ("add_word_to_personal", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, add_word_to_personal), + NULL, NULL, + pluma_marshal_VOID__STRING_INT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_INT); + + signals[ADD_WORD_TO_SESSION] = + g_signal_new ("add_word_to_session", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, add_word_to_session), + NULL, NULL, + pluma_marshal_VOID__STRING_INT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_INT); + + signals[SET_LANGUAGE] = + g_signal_new ("set_language", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, set_language), + NULL, NULL, + pluma_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + signals[CLEAR_SESSION] = + g_signal_new ("clear_session", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, clear_session), + NULL, NULL, + pluma_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +pluma_spell_checker_init (PlumaSpellChecker *spell_checker) +{ + spell_checker->broker = enchant_broker_init (); + spell_checker->dict = NULL; + spell_checker->active_lang = NULL; +} + +PlumaSpellChecker * +pluma_spell_checker_new (void) +{ + PlumaSpellChecker *spell; + + spell = PLUMA_SPELL_CHECKER ( + g_object_new (PLUMA_TYPE_SPELL_CHECKER, NULL)); + + g_return_val_if_fail (spell != NULL, NULL); + + return spell; +} + +static gboolean +lazy_init (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *language) +{ + if (spell->dict != NULL) + return TRUE; + + g_return_val_if_fail (spell->broker != NULL, FALSE); + + spell->active_lang = NULL; + + if (language != NULL) + { + spell->active_lang = language; + } + else + { + /* First try to get a default language */ + const PlumaSpellCheckerLanguage *l; + gint i = 0; + const gchar * const *lang_tags = g_get_language_names (); + + while (lang_tags [i]) + { + l = pluma_spell_checker_language_from_key (lang_tags [i]); + + if (l != NULL) + { + spell->active_lang = l; + break; + } + + i++; + } + } + + /* Second try to get a default language */ + if (spell->active_lang == NULL) + spell->active_lang = pluma_spell_checker_language_from_key ("en_US"); + + /* Last try to get a default language */ + if (spell->active_lang == NULL) + { + const GSList *langs; + langs = pluma_spell_checker_get_available_languages (); + if (langs != NULL) + spell->active_lang = (const PlumaSpellCheckerLanguage *)langs->data; + } + + if (spell->active_lang != NULL) + { + const gchar *key; + + key = pluma_spell_checker_language_to_key (spell->active_lang); + + spell->dict = enchant_broker_request_dict (spell->broker, + key); + } + + if (spell->dict == NULL) + { + spell->active_lang = NULL; + + if (language != NULL) + g_warning ("Spell checker plugin: cannot select a default language."); + + return FALSE; + } + + return TRUE; +} + +gboolean +pluma_spell_checker_set_language (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *language) +{ + gboolean ret; + + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + + if (spell->dict != NULL) + { + enchant_broker_free_dict (spell->broker, spell->dict); + spell->dict = NULL; + } + + ret = lazy_init (spell, language); + + if (ret) + g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language); + else + g_warning ("Spell checker plugin: cannot use language %s.", + pluma_spell_checker_language_to_string (language)); + + return ret; +} + +const PlumaSpellCheckerLanguage * +pluma_spell_checker_get_language (PlumaSpellChecker *spell) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), NULL); + + if (!lazy_init (spell, spell->active_lang)) + return NULL; + + return spell->active_lang; +} + +gboolean +pluma_spell_checker_check_word (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + gint enchant_result; + gboolean res = FALSE; + + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + if (len < 0) + len = strlen (word); + + if (strcmp (word, "pluma") == 0) + return TRUE; + + if (pluma_spell_utils_is_digit (word, len)) + return TRUE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + enchant_result = enchant_dict_check (spell->dict, word, len); + + switch (enchant_result) + { + case -1: + /* error */ + res = FALSE; + + g_warning ("Spell checker plugin: error checking word '%s' (%s).", + word, enchant_dict_get_error (spell->dict)); + + break; + case 1: + /* it is not in the directory */ + res = FALSE; + break; + case 0: + /* is is in the directory */ + res = TRUE; + break; + default: + g_return_val_if_reached (FALSE); + } + + return res; +} + + +/* return NULL on error or if no suggestions are found */ +GSList * +pluma_spell_checker_get_suggestions (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + gchar **suggestions; + size_t n_suggestions = 0; + GSList *suggestions_list = NULL; + gint i; + + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), NULL); + g_return_val_if_fail (word != NULL, NULL); + + if (!lazy_init (spell, spell->active_lang)) + return NULL; + + g_return_val_if_fail (spell->dict != NULL, NULL); + + if (len < 0) + len = strlen (word); + + suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions); + + if (n_suggestions == 0) + return NULL; + + g_return_val_if_fail (suggestions != NULL, NULL); + + for (i = 0; i < (gint)n_suggestions; i++) + { + suggestions_list = g_slist_prepend (suggestions_list, + suggestions[i]); + } + + /* The single suggestions will be freed by the caller */ + g_free (suggestions); + + suggestions_list = g_slist_reverse (suggestions_list); + + return suggestions_list; +} + +gboolean +pluma_spell_checker_add_word_to_personal (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + + if (len < 0) + len = strlen (word); + + enchant_dict_add_to_pwl (spell->dict, word, len); + + g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len); + + return TRUE; +} + +gboolean +pluma_spell_checker_add_word_to_session (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + + if (len < 0) + len = strlen (word); + + enchant_dict_add_to_session (spell->dict, word, len); + + g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len); + + return TRUE; +} + +gboolean +pluma_spell_checker_clear_session (PlumaSpellChecker *spell) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + + /* free and re-request dictionary */ + if (spell->dict != NULL) + { + enchant_broker_free_dict (spell->broker, spell->dict); + spell->dict = NULL; + } + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0); + + return TRUE; +} + +/* + * Informs dictionary, that word 'word' will be replaced/corrected by word + * 'replacement' + */ +gboolean +pluma_spell_checker_set_correction (PlumaSpellChecker *spell, + const gchar *word, + gssize w_len, + const gchar *replacement, + gssize r_len) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + g_return_val_if_fail (replacement != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + + if (w_len < 0) + w_len = strlen (word); + + if (r_len < 0) + r_len = strlen (replacement); + + enchant_dict_store_replacement (spell->dict, + word, + w_len, + replacement, + r_len); + + return TRUE; +} + diff --git a/plugins/spell/pluma-spell-checker.h b/plugins/spell/pluma-spell-checker.h new file mode 100755 index 00000000..ed8c1756 --- /dev/null +++ b/plugins/spell/pluma-spell-checker.h @@ -0,0 +1,109 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker.h + * This file is part of pluma + * + * Copyright (C) 2002-2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_CHECKER_H__ +#define __PLUMA_SPELL_CHECKER_H__ + +#include +#include + +#include "pluma-spell-checker-language.h" + +G_BEGIN_DECLS + +#define PLUMA_TYPE_SPELL_CHECKER (pluma_spell_checker_get_type ()) +#define PLUMA_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_SPELL_CHECKER, PlumaSpellChecker)) +#define PLUMA_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_SPELL_CHECKER, PlumaSpellChecker)) +#define PLUMA_IS_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_SPELL_CHECKER)) +#define PLUMA_IS_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_SPELL_CHECKER)) +#define PLUMA_SPELL_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_SPELL_CHECKER, PlumaSpellChecker)) + +typedef struct _PlumaSpellChecker PlumaSpellChecker; + +typedef struct _PlumaSpellCheckerClass PlumaSpellCheckerClass; + +struct _PlumaSpellCheckerClass +{ + GObjectClass parent_class; + + /* Signals */ + void (*add_word_to_personal) (PlumaSpellChecker *spell, + const gchar *word, + gint len); + + void (*add_word_to_session) (PlumaSpellChecker *spell, + const gchar *word, + gint len); + + void (*set_language) (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *lang); + + void (*clear_session) (PlumaSpellChecker *spell); +}; + + +GType pluma_spell_checker_get_type (void) G_GNUC_CONST; + +/* Constructors */ +PlumaSpellChecker *pluma_spell_checker_new (void); + +gboolean pluma_spell_checker_set_language (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *lang); +const PlumaSpellCheckerLanguage + *pluma_spell_checker_get_language (PlumaSpellChecker *spell); + +gboolean pluma_spell_checker_check_word (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +GSList *pluma_spell_checker_get_suggestions (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +gboolean pluma_spell_checker_add_word_to_personal + (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +gboolean pluma_spell_checker_add_word_to_session + (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +gboolean pluma_spell_checker_clear_session (PlumaSpellChecker *spell); + +gboolean pluma_spell_checker_set_correction (PlumaSpellChecker *spell, + const gchar *word, + gssize w_len, + const gchar *replacement, + gssize r_len); +G_END_DECLS + +#endif /* __PLUMA_SPELL_CHECKER_H__ */ + diff --git a/plugins/spell/pluma-spell-language-dialog.c b/plugins/spell/pluma-spell-language-dialog.c new file mode 100755 index 00000000..22a14373 --- /dev/null +++ b/plugins/spell/pluma-spell-language-dialog.c @@ -0,0 +1,309 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-language-dialog.c + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "pluma-spell-language-dialog.h" +#include "pluma-spell-checker-language.h" + + +enum +{ + COLUMN_LANGUAGE_NAME = 0, + COLUMN_LANGUAGE_POINTER, + ENCODING_NUM_COLS +}; + + +struct _PlumaSpellLanguageDialog +{ + GtkDialog dialog; + + GtkWidget *languages_treeview; + GtkTreeModel *model; +}; + +G_DEFINE_TYPE(PlumaSpellLanguageDialog, pluma_spell_language_dialog, GTK_TYPE_DIALOG) + + +static void +pluma_spell_language_dialog_class_init (PlumaSpellLanguageDialogClass *klass) +{ + /* GObjectClass *object_class = G_OBJECT_CLASS (klass); */ +} + +static void +dialog_response_handler (GtkDialog *dlg, + gint res_id) +{ + if (res_id == GTK_RESPONSE_HELP) + { + pluma_help_display (GTK_WINDOW (dlg), + NULL, + "pluma-spell-checker-plugin"); + + g_signal_stop_emission_by_name (dlg, "response"); + } +} + +static void +scroll_to_selected (GtkTreeView *tree_view) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (tree_view); + g_return_if_fail (model != NULL); + + /* Scroll to selected */ + selection = gtk_tree_view_get_selection (tree_view); + g_return_if_fail (selection != NULL); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GtkTreePath* path; + + path = gtk_tree_model_get_path (model, &iter); + g_return_if_fail (path != NULL); + + gtk_tree_view_scroll_to_cell (tree_view, + path, NULL, TRUE, 1.0, 0.0); + gtk_tree_path_free (path); + } +} + +static void +language_row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaSpellLanguageDialog *dialog) +{ + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + +static void +create_dialog (PlumaSpellLanguageDialog *dlg, + const gchar *data_dir) +{ + GtkWidget *error_widget; + GtkWidget *content; + gboolean ret; + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + gchar *ui_file; + gchar *root_objects[] = { + "content", + NULL + }; + + gtk_dialog_add_buttons (GTK_DIALOG (dlg), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + GTK_STOCK_HELP, + GTK_RESPONSE_HELP, + NULL); + + gtk_window_set_title (GTK_WINDOW (dlg), _("Set language")); + gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE); + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE); + + /* HIG defaults */ + gtk_container_set_border_width (GTK_CONTAINER (dlg), 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + 2); /* 2 * 5 + 2 = 12 */ + gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), + 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), + 6); + + g_signal_connect (dlg, + "response", + G_CALLBACK (dialog_response_handler), + NULL); + + ui_file = g_build_filename (data_dir, "languages-dialog.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + root_objects, + &error_widget, + "content", &content, + "languages_treeview", &dlg->languages_treeview, + NULL); + g_free (ui_file); + + if (!ret) + { + gtk_widget_show (error_widget); + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + error_widget, + TRUE, TRUE, 0); + + return; + } + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + content, TRUE, TRUE, 0); + g_object_unref (content); + gtk_container_set_border_width (GTK_CONTAINER (content), 5); + + dlg->model = GTK_TREE_MODEL (gtk_list_store_new (ENCODING_NUM_COLS, + G_TYPE_STRING, + G_TYPE_POINTER)); + + gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->languages_treeview), + dlg->model); + + g_object_unref (dlg->model); + + /* Add the encoding column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Languages"), + cell, + "text", + COLUMN_LANGUAGE_NAME, + NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->languages_treeview), + column); + + gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->languages_treeview), + COLUMN_LANGUAGE_NAME); + + g_signal_connect (dlg->languages_treeview, + "realize", + G_CALLBACK (scroll_to_selected), + dlg); + g_signal_connect (dlg->languages_treeview, + "row-activated", + G_CALLBACK (language_row_activated), + dlg); +} + +static void +pluma_spell_language_dialog_init (PlumaSpellLanguageDialog *dlg) +{ + +} + +static void +populate_language_list (PlumaSpellLanguageDialog *dlg, + const PlumaSpellCheckerLanguage *cur_lang) +{ + GtkListStore *store; + GtkTreeIter iter; + + const GSList* langs; + + /* create list store */ + store = GTK_LIST_STORE (dlg->model); + + langs = pluma_spell_checker_get_available_languages (); + + while (langs) + { + const gchar *name; + + name = pluma_spell_checker_language_to_string ((const PlumaSpellCheckerLanguage*)langs->data); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COLUMN_LANGUAGE_NAME, name, + COLUMN_LANGUAGE_POINTER, langs->data, + -1); + + if (langs->data == cur_lang) + { + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); + g_return_if_fail (selection != NULL); + + gtk_tree_selection_select_iter (selection, &iter); + } + + langs = g_slist_next (langs); + } +} + +GtkWidget * +pluma_spell_language_dialog_new (GtkWindow *parent, + const PlumaSpellCheckerLanguage *cur_lang, + const gchar *data_dir) +{ + PlumaSpellLanguageDialog *dlg; + + g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); + + dlg = g_object_new (PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, NULL); + + create_dialog (dlg, data_dir); + + populate_language_list (dlg, cur_lang); + + gtk_window_set_transient_for (GTK_WINDOW (dlg), parent); + gtk_widget_grab_focus (dlg->languages_treeview); + + return GTK_WIDGET (dlg); +} + +const PlumaSpellCheckerLanguage * +pluma_spell_language_get_selected_language (PlumaSpellLanguageDialog *dlg) +{ + GValue value = {0, }; + const PlumaSpellCheckerLanguage* lang; + + GtkTreeIter iter; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); + g_return_val_if_fail (selection != NULL, NULL); + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) + return NULL; + + gtk_tree_model_get_value (dlg->model, + &iter, + COLUMN_LANGUAGE_POINTER, + &value); + + lang = (const PlumaSpellCheckerLanguage* ) g_value_get_pointer (&value); + + return lang; +} + diff --git a/plugins/spell/pluma-spell-language-dialog.h b/plugins/spell/pluma-spell-language-dialog.h new file mode 100755 index 00000000..3fc32a0b --- /dev/null +++ b/plugins/spell/pluma-spell-language-dialog.h @@ -0,0 +1,67 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-language-dialog.h + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_LANGUAGE_DIALOG_H__ +#define __PLUMA_SPELL_LANGUAGE_DIALOG_H__ + +#include +#include "pluma-spell-checker-language.h" + +G_BEGIN_DECLS + +#define PLUMA_TYPE_SPELL_LANGUAGE_DIALOG (pluma_spell_language_dialog_get_type()) +#define PLUMA_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, PlumaSpellLanguageDialog)) +#define PLUMA_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, PlumaSpellLanguageDialogClass)) +#define PLUMA_IS_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG)) +#define PLUMA_IS_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG)) +#define PLUMA_SPELL_LANGUAGE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, PlumaSpellLanguageDialogClass)) + + +typedef struct _PlumaSpellLanguageDialog PlumaSpellLanguageDialog; + +typedef struct _PlumaSpellLanguageDialogClass PlumaSpellLanguageDialogClass; + +struct _PlumaSpellLanguageDialogClass +{ + GtkDialogClass parent_class; +}; + +GType pluma_spell_language_dialog_get_type (void) G_GNUC_CONST; + +GtkWidget *pluma_spell_language_dialog_new (GtkWindow *parent, + const PlumaSpellCheckerLanguage *cur_lang, + const gchar *data_dir); + +const PlumaSpellCheckerLanguage * + pluma_spell_language_get_selected_language (PlumaSpellLanguageDialog *dlg); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_LANGUAGE_DIALOG_H__ */ + diff --git a/plugins/spell/pluma-spell-marshal.list b/plugins/spell/pluma-spell-marshal.list new file mode 100755 index 00000000..007dcf7d --- /dev/null +++ b/plugins/spell/pluma-spell-marshal.list @@ -0,0 +1,6 @@ +VOID:STRING +VOID:STRING,STRING +VOID:STRING,INT +VOID:POINTER +VOID:VOID + diff --git a/plugins/spell/pluma-spell-plugin.c b/plugins/spell/pluma-spell-plugin.c new file mode 100755 index 00000000..e7dab44a --- /dev/null +++ b/plugins/spell/pluma-spell-plugin.c @@ -0,0 +1,1217 @@ +/* + * pluma-spell-plugin.c + * + * Copyright (C) 2002-2005 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-spell-plugin.h" +#include "pluma-spell-utils.h" + +#include /* For strlen */ + +#include +#include + +#include +#include +#include + +#include "pluma-spell-checker.h" +#include "pluma-spell-checker-dialog.h" +#include "pluma-spell-language-dialog.h" +#include "pluma-automatic-spell-checker.h" + +#ifdef G_OS_WIN32 +#include +#define PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE "spell-language" +#define PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED "spell-enabled" +#else +#define PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::pluma-spell-language" +#define PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::pluma-spell-enabled" +#endif + +#define WINDOW_DATA_KEY "PlumaSpellPluginWindowData" +#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1" + +#define PLUMA_SPELL_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + PLUMA_TYPE_SPELL_PLUGIN, \ + PlumaSpellPluginPrivate)) + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaSpellPlugin, pluma_spell_plugin) + +typedef struct +{ + GtkActionGroup *action_group; + guint ui_id; + guint message_cid; + gulong tab_added_id; + gulong tab_removed_id; +} WindowData; + +typedef struct +{ + PlumaPlugin *plugin; + PlumaWindow *window; +} ActionData; + +static void spell_cb (GtkAction *action, ActionData *action_data); +static void set_language_cb (GtkAction *action, ActionData *action_data); +static void auto_spell_cb (GtkAction *action, PlumaWindow *window); + +/* UI actions. */ +static const GtkActionEntry action_entries[] = +{ + { "CheckSpell", + GTK_STOCK_SPELL_CHECK, + N_("_Check Spelling..."), + "F7", + N_("Check the current document for incorrect spelling"), + G_CALLBACK (spell_cb) + }, + + { "ConfigSpell", + NULL, + N_("Set _Language..."), + NULL, + N_("Set the language of the current document"), + G_CALLBACK (set_language_cb) + } +}; + +static const GtkToggleActionEntry toggle_action_entries[] = +{ + { "AutoSpell", + NULL, + N_("_Autocheck Spelling"), + NULL, + N_("Automatically spell-check the current document"), + G_CALLBACK (auto_spell_cb), + FALSE + } +}; + +typedef struct _CheckRange CheckRange; + +struct _CheckRange +{ + GtkTextMark *start_mark; + GtkTextMark *end_mark; + + gint mw_start; /* misspelled word start */ + gint mw_end; /* end */ + + GtkTextMark *current_mark; +}; + +static GQuark spell_checker_id = 0; +static GQuark check_range_id = 0; + +static void +pluma_spell_plugin_init (PlumaSpellPlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaSpellPlugin initializing"); +} + +static void +pluma_spell_plugin_finalize (GObject *object) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaSpellPlugin finalizing"); + + G_OBJECT_CLASS (pluma_spell_plugin_parent_class)->finalize (object); +} + +static void +set_spell_language_cb (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *lang, + PlumaDocument *doc) +{ + const gchar *key; + + g_return_if_fail (PLUMA_IS_DOCUMENT (doc)); + g_return_if_fail (lang != NULL); + + key = pluma_spell_checker_language_to_key (lang); + g_return_if_fail (key != NULL); + + pluma_document_set_metadata (doc, PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE, + key, NULL); +} + +static void +set_language_from_metadata (PlumaSpellChecker *spell, + PlumaDocument *doc) +{ + const PlumaSpellCheckerLanguage *lang = NULL; + gchar *value = NULL; + + value = pluma_document_get_metadata (doc, PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE); + + if (value != NULL) + { + lang = pluma_spell_checker_language_from_key (value); + g_free (value); + } + + if (lang != NULL) + { + g_signal_handlers_block_by_func (spell, set_spell_language_cb, doc); + pluma_spell_checker_set_language (spell, lang); + g_signal_handlers_unblock_by_func (spell, set_spell_language_cb, doc); + } +} + +static PlumaSpellChecker * +get_spell_checker_from_document (PlumaDocument *doc) +{ + PlumaSpellChecker *spell; + gpointer data; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, NULL); + + data = g_object_get_qdata (G_OBJECT (doc), spell_checker_id); + + if (data == NULL) + { + spell = pluma_spell_checker_new (); + + set_language_from_metadata (spell, doc); + + g_object_set_qdata_full (G_OBJECT (doc), + spell_checker_id, + spell, + (GDestroyNotify) g_object_unref); + + g_signal_connect (spell, + "set_language", + G_CALLBACK (set_spell_language_cb), + doc); + } + else + { + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (data), NULL); + spell = PLUMA_SPELL_CHECKER (data); + } + + return spell; +} + +static CheckRange * +get_check_range (PlumaDocument *doc) +{ + CheckRange *range; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, NULL); + + range = (CheckRange *) g_object_get_qdata (G_OBJECT (doc), check_range_id); + + return range; +} + +static void +update_current (PlumaDocument *doc, + gint current) +{ + CheckRange *range; + GtkTextIter iter; + GtkTextIter end_iter; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (doc != NULL); + g_return_if_fail (current >= 0); + + range = get_check_range (doc); + g_return_if_fail (range != NULL); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), + &iter, current); + + if (!gtk_text_iter_inside_word (&iter)) + { + /* if we're not inside a word, + * we must be in some spaces. + * skip forward to the beginning of the next word. */ + if (!gtk_text_iter_is_end (&iter)) + { + gtk_text_iter_forward_word_end (&iter); + gtk_text_iter_backward_word_start (&iter); + } + } + else + { + if (!gtk_text_iter_starts_word (&iter)) + gtk_text_iter_backward_word_start (&iter); + } + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + &end_iter, + range->end_mark); + + if (gtk_text_iter_compare (&end_iter, &iter) < 0) + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->current_mark, + &end_iter); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->current_mark, + &iter); + } +} + +static void +set_check_range (PlumaDocument *doc, + GtkTextIter *start, + GtkTextIter *end) +{ + CheckRange *range; + GtkTextIter iter; + + pluma_debug (DEBUG_PLUGINS); + + range = get_check_range (doc); + + if (range == NULL) + { + pluma_debug_message (DEBUG_PLUGINS, "There was not a previous check range"); + + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter); + + range = g_new0 (CheckRange, 1); + + range->start_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "check_range_start_mark", &iter, TRUE); + + range->end_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "check_range_end_mark", &iter, FALSE); + + range->current_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "check_range_current_mark", &iter, TRUE); + + g_object_set_qdata_full (G_OBJECT (doc), + check_range_id, + range, + (GDestroyNotify)g_free); + } + + if (pluma_spell_utils_skip_no_spell_check (start, end)) + { + if (!gtk_text_iter_inside_word (end)) + { + /* if we're neither inside a word, + * we must be in some spaces. + * skip backward to the end of the previous word. */ + if (!gtk_text_iter_is_end (end)) + { + gtk_text_iter_backward_word_start (end); + gtk_text_iter_forward_word_end (end); + } + } + else + { + if (!gtk_text_iter_ends_word (end)) + gtk_text_iter_forward_word_end (end); + } + } + else + { + /* no spell checking in the specified range */ + start = end; + } + + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->start_mark, + start); + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->end_mark, + end); + + range->mw_start = -1; + range->mw_end = -1; + + update_current (doc, gtk_text_iter_get_offset (start)); +} + +static gchar * +get_current_word (PlumaDocument *doc, gint *start, gint *end) +{ + const CheckRange *range; + GtkTextIter end_iter; + GtkTextIter current_iter; + gint range_end; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, NULL); + g_return_val_if_fail (start != NULL, NULL); + g_return_val_if_fail (end != NULL, NULL); + + range = get_check_range (doc); + g_return_val_if_fail (range != NULL, NULL); + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + &end_iter, range->end_mark); + + range_end = gtk_text_iter_get_offset (&end_iter); + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + ¤t_iter, range->current_mark); + + end_iter = current_iter; + + if (!gtk_text_iter_is_end (&end_iter)) + { + pluma_debug_message (DEBUG_PLUGINS, "Current is not end"); + + gtk_text_iter_forward_word_end (&end_iter); + } + + *start = gtk_text_iter_get_offset (¤t_iter); + *end = MIN (gtk_text_iter_get_offset (&end_iter), range_end); + + pluma_debug_message (DEBUG_PLUGINS, "Current word extends [%d, %d]", *start, *end); + + if (!(*start < *end)) + return NULL; + + return gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), + ¤t_iter, + &end_iter, + TRUE); +} + +static gboolean +goto_next_word (PlumaDocument *doc) +{ + CheckRange *range; + GtkTextIter current_iter; + GtkTextIter old_current_iter; + GtkTextIter end_iter; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, FALSE); + + range = get_check_range (doc); + g_return_val_if_fail (range != NULL, FALSE); + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + ¤t_iter, + range->current_mark); + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end_iter); + + old_current_iter = current_iter; + + gtk_text_iter_forward_word_ends (¤t_iter, 2); + gtk_text_iter_backward_word_start (¤t_iter); + + if (pluma_spell_utils_skip_no_spell_check (¤t_iter, &end_iter) && + (gtk_text_iter_compare (&old_current_iter, ¤t_iter) < 0) && + (gtk_text_iter_compare (¤t_iter, &end_iter) < 0)) + { + update_current (doc, gtk_text_iter_get_offset (¤t_iter)); + return TRUE; + } + + return FALSE; +} + +static gchar * +get_next_misspelled_word (PlumaView *view) +{ + PlumaDocument *doc; + CheckRange *range; + gint start, end; + gchar *word; + PlumaSpellChecker *spell; + + g_return_val_if_fail (view != NULL, NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_val_if_fail (doc != NULL, NULL); + + range = get_check_range (doc); + g_return_val_if_fail (range != NULL, NULL); + + spell = get_spell_checker_from_document (doc); + g_return_val_if_fail (spell != NULL, NULL); + + word = get_current_word (doc, &start, &end); + if (word == NULL) + return NULL; + + pluma_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); + + while (pluma_spell_checker_check_word (spell, word, -1)) + { + g_free (word); + + if (!goto_next_word (doc)) + return NULL; + + /* may return null if we reached the end of the selection */ + word = get_current_word (doc, &start, &end); + if (word == NULL) + return NULL; + + pluma_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); + } + + if (!goto_next_word (doc)) + update_current (doc, gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc))); + + if (word != NULL) + { + GtkTextIter s, e; + + range->mw_start = start; + range->mw_end = end; + + pluma_debug_message (DEBUG_PLUGINS, "Select [%d, %d]", start, end); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &s, start); + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &e, end); + + gtk_text_buffer_select_range (GTK_TEXT_BUFFER (doc), &s, &e); + + pluma_view_scroll_to_cursor (view); + } + else + { + range->mw_start = -1; + range->mw_end = -1; + } + + return word; +} + +static void +ignore_cb (PlumaSpellCheckerDialog *dlg, + const gchar *w, + PlumaView *view) +{ + gchar *word = NULL; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (w != NULL); + g_return_if_fail (view != NULL); + + word = get_next_misspelled_word (view); + if (word == NULL) + { + pluma_spell_checker_dialog_set_completed (dlg); + + return; + } + + pluma_spell_checker_dialog_set_misspelled_word (PLUMA_SPELL_CHECKER_DIALOG (dlg), + word, + -1); + + g_free (word); +} + +static void +change_cb (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change, + PlumaView *view) +{ + PlumaDocument *doc; + CheckRange *range; + gchar *w = NULL; + GtkTextIter start, end; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (view != NULL); + g_return_if_fail (word != NULL); + g_return_if_fail (change != NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_if_fail (doc != NULL); + + range = get_check_range (doc); + g_return_if_fail (range != NULL); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); + if (range->mw_end < 0) + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); + else + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); + + w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); + g_return_if_fail (w != NULL); + + if (strcmp (w, word) != 0) + { + g_free (w); + return; + } + + g_free (w); + + gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER(doc)); + + gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), &start, &end); + gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), &start, change, -1); + + gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER(doc)); + + update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); + + /* go to next misspelled word */ + ignore_cb (dlg, word, view); +} + +static void +change_all_cb (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change, + PlumaView *view) +{ + PlumaDocument *doc; + CheckRange *range; + gchar *w = NULL; + GtkTextIter start, end; + gint flags = 0; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (view != NULL); + g_return_if_fail (word != NULL); + g_return_if_fail (change != NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_if_fail (doc != NULL); + + range = get_check_range (doc); + g_return_if_fail (range != NULL); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); + if (range->mw_end < 0) + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); + else + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); + + w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); + g_return_if_fail (w != NULL); + + if (strcmp (w, word) != 0) + { + g_free (w); + return; + } + + g_free (w); + + PLUMA_SEARCH_SET_CASE_SENSITIVE (flags, TRUE); + PLUMA_SEARCH_SET_ENTIRE_WORD (flags, TRUE); + + /* CHECK: currently this function does escaping etc */ + pluma_document_replace_all (doc, word, change, flags); + + update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); + + /* go to next misspelled word */ + ignore_cb (dlg, word, view); +} + +static void +add_word_cb (PlumaSpellCheckerDialog *dlg, + const gchar *word, + PlumaView *view) +{ + g_return_if_fail (view != NULL); + g_return_if_fail (word != NULL); + + /* go to next misspelled word */ + ignore_cb (dlg, word, view); +} + +static void +language_dialog_response (GtkDialog *dlg, + gint res_id, + PlumaSpellChecker *spell) +{ + if (res_id == GTK_RESPONSE_OK) + { + const PlumaSpellCheckerLanguage *lang; + + lang = pluma_spell_language_get_selected_language (PLUMA_SPELL_LANGUAGE_DIALOG (dlg)); + if (lang != NULL) + pluma_spell_checker_set_language (spell, lang); + } + + gtk_widget_destroy (GTK_WIDGET (dlg)); +} + +static void +set_language_cb (GtkAction *action, + ActionData *action_data) +{ + PlumaDocument *doc; + PlumaSpellChecker *spell; + const PlumaSpellCheckerLanguage *lang; + GtkWidget *dlg; + GtkWindowGroup *wg; + gchar *data_dir; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (action_data->window); + g_return_if_fail (doc != NULL); + + spell = get_spell_checker_from_document (doc); + g_return_if_fail (spell != NULL); + + lang = pluma_spell_checker_get_language (spell); + + data_dir = pluma_plugin_get_data_dir (action_data->plugin); + dlg = pluma_spell_language_dialog_new (GTK_WINDOW (action_data->window), + lang, + data_dir); + g_free (data_dir); + + wg = pluma_window_get_group (action_data->window); + + gtk_window_group_add_window (wg, GTK_WINDOW (dlg)); + + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + + g_signal_connect (dlg, + "response", + G_CALLBACK (language_dialog_response), + spell); + + gtk_widget_show (dlg); +} + +static void +spell_cb (GtkAction *action, + ActionData *action_data) +{ + PlumaView *view; + PlumaDocument *doc; + PlumaSpellChecker *spell; + GtkWidget *dlg; + GtkTextIter start, end; + gchar *word; + gchar *data_dir; + + pluma_debug (DEBUG_PLUGINS); + + view = pluma_window_get_active_view (action_data->window); + g_return_if_fail (view != NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_if_fail (doc != NULL); + + spell = get_spell_checker_from_document (doc); + g_return_if_fail (spell != NULL); + + if (gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc)) <= 0) + { + WindowData *data; + GtkWidget *statusbar; + + data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + statusbar = pluma_window_get_statusbar (action_data->window); + pluma_statusbar_flash_message (PLUMA_STATUSBAR (statusbar), + data->message_cid, + _("The document is empty.")); + + return; + } + + if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), + &start, + &end)) + { + /* no selection, get the whole doc */ + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), + &start, + &end); + } + + set_check_range (doc, &start, &end); + + word = get_next_misspelled_word (view); + if (word == NULL) + { + WindowData *data; + GtkWidget *statusbar; + + data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + statusbar = pluma_window_get_statusbar (action_data->window); + pluma_statusbar_flash_message (PLUMA_STATUSBAR (statusbar), + data->message_cid, + _("No misspelled words")); + + return; + } + + data_dir = pluma_plugin_get_data_dir (action_data->plugin); + dlg = pluma_spell_checker_dialog_new_from_spell_checker (spell, data_dir); + g_free (data_dir); + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + gtk_window_set_transient_for (GTK_WINDOW (dlg), + GTK_WINDOW (action_data->window)); + + g_signal_connect (dlg, "ignore", G_CALLBACK (ignore_cb), view); + g_signal_connect (dlg, "ignore_all", G_CALLBACK (ignore_cb), view); + + g_signal_connect (dlg, "change", G_CALLBACK (change_cb), view); + g_signal_connect (dlg, "change_all", G_CALLBACK (change_all_cb), view); + + g_signal_connect (dlg, "add_word_to_personal", G_CALLBACK (add_word_cb), view); + + pluma_spell_checker_dialog_set_misspelled_word (PLUMA_SPELL_CHECKER_DIALOG (dlg), + word, + -1); + + g_free (word); + + gtk_widget_show (dlg); +} + +static void +set_auto_spell (PlumaWindow *window, + PlumaDocument *doc, + gboolean active) +{ + PlumaAutomaticSpellChecker *autospell; + PlumaSpellChecker *spell; + + spell = get_spell_checker_from_document (doc); + g_return_if_fail (spell != NULL); + + autospell = pluma_automatic_spell_checker_get_from_document (doc); + + if (active) + { + if (autospell == NULL) + { + PlumaView *active_view; + + active_view = pluma_window_get_active_view (window); + g_return_if_fail (active_view != NULL); + + autospell = pluma_automatic_spell_checker_new (doc, spell); + pluma_automatic_spell_checker_attach_view (autospell, active_view); + pluma_automatic_spell_checker_recheck_all (autospell); + } + } + else + { + if (autospell != NULL) + pluma_automatic_spell_checker_free (autospell); + } +} + +static void +auto_spell_cb (GtkAction *action, + PlumaWindow *window) +{ + + PlumaDocument *doc; + gboolean active; + + pluma_debug (DEBUG_PLUGINS); + + active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + + pluma_debug_message (DEBUG_PLUGINS, active ? "Auto Spell activated" : "Auto Spell deactivated"); + + doc = pluma_window_get_active_document (window); + if (doc == NULL) + return; + + pluma_document_set_metadata (doc, + PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED, + active ? "1" : NULL, NULL); + + set_auto_spell (window, doc, active); +} + +static void +free_window_data (WindowData *data) +{ + g_return_if_fail (data != NULL); + + g_object_unref (data->action_group); + g_slice_free (WindowData, data); +} + +static void +free_action_data (gpointer data) +{ + g_return_if_fail (data != NULL); + + g_slice_free (ActionData, data); +} + +static void +update_ui_real (PlumaWindow *window, + WindowData *data) +{ + PlumaDocument *doc; + PlumaView *view; + gboolean autospell; + GtkAction *action; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (window); + view = pluma_window_get_active_view (window); + + autospell = (doc != NULL && + pluma_automatic_spell_checker_get_from_document (doc) != NULL); + + if (doc != NULL) + { + PlumaTab *tab; + PlumaTabState state; + + tab = pluma_window_get_active_tab (window); + state = pluma_tab_get_state (tab); + + /* If the document is loading we can't get the metadata so we + endup with an useless speller */ + if (state == PLUMA_TAB_STATE_NORMAL) + { + action = gtk_action_group_get_action (data->action_group, + "AutoSpell"); + + g_signal_handlers_block_by_func (action, auto_spell_cb, + window); + set_auto_spell (window, doc, autospell); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + autospell); + g_signal_handlers_unblock_by_func (action, auto_spell_cb, + window); + } + } + + gtk_action_group_set_sensitive (data->action_group, + (view != NULL) && + gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); +} + +static void +set_auto_spell_from_metadata (PlumaWindow *window, + PlumaDocument *doc, + GtkActionGroup *action_group) +{ + gboolean active = FALSE; + gchar *active_str; + PlumaDocument *active_doc; + + active_str = pluma_document_get_metadata (doc, + PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED); + + if (active_str) + { + active = *active_str == '1'; + + g_free (active_str); + } + + set_auto_spell (window, doc, active); + + /* In case that the doc is the active one we mark the spell action */ + active_doc = pluma_window_get_active_document (window); + + if (active_doc == doc && action_group != NULL) + { + GtkAction *action; + + action = gtk_action_group_get_action (action_group, + "AutoSpell"); + + g_signal_handlers_block_by_func (action, auto_spell_cb, + window); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + active); + g_signal_handlers_unblock_by_func (action, auto_spell_cb, + window); + } +} + +static void +on_document_loaded (PlumaDocument *doc, + const GError *error, + PlumaWindow *window) +{ + if (error == NULL) + { + WindowData *data; + PlumaSpellChecker *spell; + + spell = PLUMA_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), + spell_checker_id)); + if (spell != NULL) + { + set_language_from_metadata (spell, doc); + } + + data = g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + + set_auto_spell_from_metadata (window, doc, data->action_group); + } +} + +static void +on_document_saved (PlumaDocument *doc, + const GError *error, + PlumaWindow *window) +{ + PlumaAutomaticSpellChecker *autospell; + PlumaSpellChecker *spell; + const gchar *key; + + if (error != NULL) + { + return; + } + + /* Make sure to save the metadata here too */ + autospell = pluma_automatic_spell_checker_get_from_document (doc); + spell = PLUMA_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id)); + + if (spell != NULL) + { + key = pluma_spell_checker_language_to_key (pluma_spell_checker_get_language (spell)); + } + else + { + key = NULL; + } + + pluma_document_set_metadata (doc, + PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED, + autospell != NULL ? "1" : NULL, + PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE, + key, + NULL); +} + +static void +tab_added_cb (PlumaWindow *window, + PlumaTab *tab, + gpointer useless) +{ + PlumaDocument *doc; + PlumaView *view; + + doc = pluma_tab_get_document (tab); + view = pluma_tab_get_view (tab); + + g_signal_connect (doc, "loaded", + G_CALLBACK (on_document_loaded), + window); + + g_signal_connect (doc, "saved", + G_CALLBACK (on_document_saved), + window); +} + +static void +tab_removed_cb (PlumaWindow *window, + PlumaTab *tab, + gpointer useless) +{ + PlumaDocument *doc; + PlumaView *view; + + doc = pluma_tab_get_document (tab); + view = pluma_tab_get_view (tab); + + g_signal_handlers_disconnect_by_func (doc, on_document_loaded, window); + g_signal_handlers_disconnect_by_func (doc, on_document_saved, window); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + ActionData *action_data; + GList *docs, *l; + + pluma_debug (DEBUG_PLUGINS); + + data = g_slice_new (WindowData); + action_data = g_slice_new (ActionData); + action_data->plugin = plugin; + action_data->window = window; + + manager = pluma_window_get_ui_manager (window); + + data->action_group = gtk_action_group_new ("PlumaSpellPluginActions"); + gtk_action_group_set_translation_domain (data->action_group, + GETTEXT_PACKAGE); + gtk_action_group_add_actions_full (data->action_group, + action_entries, + G_N_ELEMENTS (action_entries), + action_data, + (GDestroyNotify) free_action_data); + gtk_action_group_add_toggle_actions (data->action_group, + toggle_action_entries, + G_N_ELEMENTS (toggle_action_entries), + window); + + gtk_ui_manager_insert_action_group (manager, data->action_group, -1); + + data->ui_id = gtk_ui_manager_new_merge_id (manager); + + data->message_cid = gtk_statusbar_get_context_id + (GTK_STATUSBAR (pluma_window_get_statusbar (window)), + "spell_plugin_message"); + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + (GDestroyNotify) free_window_data); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "CheckSpell", + "CheckSpell", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "AutoSpell", + "AutoSpell", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "ConfigSpell", + "ConfigSpell", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + update_ui_real (window, data); + + docs = pluma_window_get_documents (window); + for (l = docs; l != NULL; l = g_list_next (l)) + { + PlumaDocument *doc = PLUMA_DOCUMENT (l->data); + + set_auto_spell_from_metadata (window, doc, + data->action_group); + + g_signal_handlers_disconnect_by_func (doc, + on_document_loaded, + window); + + g_signal_handlers_disconnect_by_func (doc, + on_document_saved, + window); + } + + data->tab_added_id = + g_signal_connect (window, "tab-added", + G_CALLBACK (tab_added_cb), NULL); + data->tab_removed_id = + g_signal_connect (window, "tab-removed", + G_CALLBACK (tab_removed_cb), NULL); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + manager = pluma_window_get_ui_manager (window); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + gtk_ui_manager_remove_ui (manager, data->ui_id); + gtk_ui_manager_remove_action_group (manager, data->action_group); + + g_signal_handler_disconnect (window, data->tab_added_id); + g_signal_handler_disconnect (window, data->tab_removed_id); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + update_ui_real (window, data); +} + +static void +pluma_spell_plugin_class_init (PlumaSpellPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_spell_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; + + if (spell_checker_id == 0) + spell_checker_id = g_quark_from_string ("PlumaSpellCheckerID"); + + if (check_range_id == 0) + check_range_id = g_quark_from_string ("CheckRangeID"); +} diff --git a/plugins/spell/pluma-spell-plugin.h b/plugins/spell/pluma-spell-plugin.h new file mode 100755 index 00000000..44e70a66 --- /dev/null +++ b/plugins/spell/pluma-spell-plugin.h @@ -0,0 +1,75 @@ +/* + * pluma-spell-plugin.h + * + * Copyright (C) 2002-2005 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __PLUMA_SPELL_PLUGIN_H__ +#define __PLUMA_SPELL_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_SPELL_PLUGIN (pluma_spell_plugin_get_type ()) +#define PLUMA_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_SPELL_PLUGIN, PlumaSpellPlugin)) +#define PLUMA_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_SPELL_PLUGIN, PlumaSpellPluginClass)) +#define PLUMA_IS_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_SPELL_PLUGIN)) +#define PLUMA_IS_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_SPELL_PLUGIN)) +#define PLUMA_SPELL_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_SPELL_PLUGIN, PlumaSpellPluginClass)) + +/* Private structure type */ +typedef struct _PlumaSpellPluginPrivate PlumaSpellPluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaSpellPlugin PlumaSpellPlugin; + +struct _PlumaSpellPlugin +{ + PlumaPlugin parent_instance; +}; + +/* + * Class definition + */ +typedef struct _PlumaSpellPluginClass PlumaSpellPluginClass; + +struct _PlumaSpellPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_spell_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_PLUGIN_H__ */ diff --git a/plugins/spell/pluma-spell-utils.c b/plugins/spell/pluma-spell-utils.c new file mode 100755 index 00000000..504cf042 --- /dev/null +++ b/plugins/spell/pluma-spell-utils.c @@ -0,0 +1,94 @@ +/* + * pluma-spell-utils.c + * This file is part of pluma + * + * Copyright (C) 2010 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +#include "pluma-spell-utils.h" +#include + +gboolean +pluma_spell_utils_is_digit (const char *text, gssize length) +{ + gunichar c; + const gchar *p; + const gchar *end; + + g_return_val_if_fail (text != NULL, FALSE); + + if (length < 0) + length = strlen (text); + + p = text; + end = text + length; + + while (p != end) { + const gchar *next; + next = g_utf8_next_char (p); + + c = g_utf8_get_char (p); + + if (!g_unichar_isdigit (c) && c != '.' && c != ',') + return FALSE; + + p = next; + } + + return TRUE; +} + +gboolean +pluma_spell_utils_skip_no_spell_check (GtkTextIter *start, + GtkTextIter *end) +{ + GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (start)); + + while (gtk_source_buffer_iter_has_context_class (buffer, start, "no-spell-check")) + { + GtkTextIter last = *start; + + if (!gtk_source_buffer_iter_forward_to_context_class_toggle (buffer, start, "no-spell-check")) + { + return FALSE; + } + + if (gtk_text_iter_compare (start, &last) <= 0) + { + return FALSE; + } + + gtk_text_iter_forward_word_end (start); + gtk_text_iter_backward_word_start (start); + + if (gtk_text_iter_compare (start, &last) <= 0) + { + return FALSE; + } + + if (gtk_text_iter_compare (start, end) >= 0) + { + return FALSE; + } + } + + return TRUE; +} + diff --git a/plugins/spell/pluma-spell-utils.h b/plugins/spell/pluma-spell-utils.h new file mode 100755 index 00000000..a9d2eaf2 --- /dev/null +++ b/plugins/spell/pluma-spell-utils.h @@ -0,0 +1,37 @@ +/* + * pluma-spell-utils.h + * This file is part of pluma + * + * Copyright (C) 2010 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __PLUMA_SPELL_UTILS_H__ +#define __PLUMA_SPELL_UTILS_H__ + +#include + +G_BEGIN_DECLS + +gboolean pluma_spell_utils_is_digit (const char *text, gssize length); + +gboolean pluma_spell_utils_skip_no_spell_check (GtkTextIter *start, GtkTextIter *end); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_UTILS_H__ */ + diff --git a/plugins/spell/spell.gedit-plugin.desktop.in b/plugins/spell/spell.gedit-plugin.desktop.in deleted file mode 100755 index c75c9eee..00000000 --- a/plugins/spell/spell.gedit-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Gedit Plugin] -Module=spell -IAge=2 -_Name=Spell Checker -_Description=Checks the spelling of the current document. -Icon=gtk-spell-check -Authors=Paolo Maggi -Copyright=Copyright © 2002-2005 Paolo Maggi -Website=http://www.gedit.org diff --git a/plugins/spell/spell.pluma-plugin.desktop.in b/plugins/spell/spell.pluma-plugin.desktop.in new file mode 100755 index 00000000..c4400dc3 --- /dev/null +++ b/plugins/spell/spell.pluma-plugin.desktop.in @@ -0,0 +1,9 @@ +[Pluma Plugin] +Module=spell +IAge=2 +_Name=Spell Checker +_Description=Checks the spelling of the current document. +Icon=gtk-spell-check +Authors=Paolo Maggi +Copyright=Copyright © 2002-2005 Paolo Maggi +Website=http://www.pluma.org -- cgit v1.2.1