2012-09-19 [colin] 3.8.1cvs64
[claws.git] / src / gtk / gtkaspell.c
index 18cd509a9b01b5e6a2544c5f509f6057d452f051..fce20c4bc3422bde138593bfb4ef81739a06249b 100644 (file)
@@ -25,6 +25,7 @@
  
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
+#include "claws-features.h"
 #endif
 
 #ifdef USE_ENCHANT
@@ -88,6 +89,9 @@ static GtkAspellCheckers *gtkaspellcheckers;
 static void gtkaspell_checkers_error_message   (gchar  *message);
 
 /* Callbacks */
+static gboolean key_press_cb                   (GtkWidget    *text_view,
+                                                GdkEventKey  *event,
+                                                 GtkAspell      *gtkaspell);
 static void entry_insert_cb                    (GtkTextBuffer  *textbuf,
                                                 GtkTextIter    *iter,
                                                 gchar          *newtext, 
@@ -187,8 +191,6 @@ static Dictionary * dictionary_dup                  (const Dictionary *dict);
 static void            reset_theword_data              (GtkAspell *gtkaspell);
 static void            free_checkers                   (gpointer elt, 
                                                         gpointer data);
-static gint            find_gtkaspeller                (gconstpointer aa, 
-                                                        gconstpointer bb);
 
 static void destroy_menu(GtkWidget *widget, gpointer user_data);       
 
@@ -422,6 +424,8 @@ GtkAspell *gtkaspell_new(const gchar *dictionary,
 
        allocate_color(gtkaspell, misspelled_color);
 
+       g_signal_connect(G_OBJECT(gtktext), "key_press_event",
+                              G_CALLBACK(key_press_cb), gtkaspell);
        g_signal_connect_after(G_OBJECT(buffer), "insert-text",
                               G_CALLBACK(entry_insert_cb), gtkaspell);
        g_signal_connect_after(G_OBJECT(buffer), "delete-range",
@@ -441,6 +445,9 @@ void gtkaspell_delete(GtkAspell *gtkaspell)
 {
        GtkTextView *gtktext = gtkaspell->gtktext;
        
+        g_signal_handlers_disconnect_by_func(G_OBJECT(gtktext),
+                                            G_CALLBACK(key_press_cb),
+                                            gtkaspell);
         g_signal_handlers_disconnect_by_func(G_OBJECT(gtktext),
                                             G_CALLBACK(entry_insert_cb),
                                             gtkaspell);
@@ -477,6 +484,40 @@ void gtkaspell_dict_changed(GtkAspell *gtkaspell)
        gtkaspell->dict_changed_cb(gtkaspell->menu_changed_data);
 }
 
+static gboolean key_press_cb                   (GtkWidget    *text_view,
+                                                GdkEventKey  *event,
+                                                 GtkAspell    *gtkaspell)
+{
+       gint pos;
+
+       cm_return_val_if_fail(gtkaspell->gtkaspeller->speller, FALSE);
+
+       if (!gtkaspell->check_while_typing)
+               return FALSE;
+
+       switch (event->keyval) {
+               case GDK_KEY_Home:
+               case GDK_KEY_Left:
+               case GDK_KEY_Up:
+               case GDK_KEY_Right:
+               case GDK_KEY_Down:
+               case GDK_KEY_Page_Up:
+               case GDK_KEY_Page_Down:
+               case GDK_KEY_End:
+               case GDK_KEY_Begin:
+                       pos = get_textview_buffer_offset(GTK_TEXT_VIEW(text_view));
+                       if (pos > 0)
+                               check_at(gtkaspell, pos - 1);
+                       else
+                               check_at(gtkaspell, pos);
+                       break;
+               default:
+                       break;
+       }
+
+       return FALSE;
+}
+
 static void entry_insert_cb(GtkTextBuffer *textbuf,
                            GtkTextIter *iter,
                            gchar *newtext,
@@ -517,7 +558,7 @@ static void entry_delete_cb(GtkTextBuffer *textbuf,
                            GtkAspell *gtkaspell)
 {
        int origpos;
-       gint start, end;
+       gint start;
     
        cm_return_if_fail(gtkaspell->gtkaspeller->speller);
 
@@ -525,7 +566,6 @@ static void entry_delete_cb(GtkTextBuffer *textbuf,
                return;
 
        start = gtk_text_iter_get_offset(startiter);
-       end = gtk_text_iter_get_offset(enditer);
        origpos = get_textview_buffer_offset(gtkaspell->gtktext);
        if (start) {
                check_at(gtkaspell, start - 1);
@@ -606,7 +646,6 @@ static void button_press_intercept_cb(GtkTextView *gtktext,
 /* Checker creation */
 static GtkAspeller *gtkaspeller_new(Dictionary *dictionary)
 {
-       GSList          *exist;
        GtkAspeller     *gtkaspeller = NULL;
        GtkAspeller     *tmp;
        Dictionary      *dict;
@@ -626,9 +665,6 @@ static GtkAspeller *gtkaspeller_new(Dictionary *dictionary)
        tmp = g_new0(GtkAspeller, 1);
        tmp->dictionary = dict;
 
-       exist = g_slist_find_custom(gtkaspellcheckers->checkers, tmp, 
-                                   find_gtkaspeller);
-       
        g_free(tmp);
 
        if ((gtkaspeller = gtkaspeller_real_new(dict)) != NULL) {
@@ -917,12 +953,9 @@ static gboolean check_at(GtkAspell *gtkaspell, gint from_pos)
 {
        gint          start, end;
        char buf[GTKASPELLWORDSIZE];
-       GtkTextView     *gtktext;
 
        cm_return_val_if_fail(from_pos >= 0, FALSE);
     
-       gtktext = gtkaspell->gtktext;
-
        if (!get_word_from_pos(gtkaspell, from_pos, buf, sizeof(buf), 
                               &start, &end))
                return FALSE;
@@ -1196,6 +1229,9 @@ void gtkaspell_block_check(GtkAspell *gtkaspell)
                return;
                
        gtktext = gtkaspell->gtktext;
+       g_signal_handlers_block_by_func(G_OBJECT(gtktext),
+                                        G_CALLBACK(key_press_cb),
+                                        gtkaspell);
        g_signal_handlers_block_by_func(G_OBJECT(gtktext),
                                         G_CALLBACK(entry_insert_cb),
                                         gtkaspell);
@@ -1212,6 +1248,9 @@ void gtkaspell_unblock_check(GtkAspell *gtkaspell)
                return;
                
        gtktext = gtkaspell->gtktext;
+       g_signal_handlers_unblock_by_func(G_OBJECT(gtktext),
+                                        G_CALLBACK(key_press_cb),
+                                        gtkaspell);
        g_signal_handlers_unblock_by_func(G_OBJECT(gtktext),
                                         G_CALLBACK(entry_insert_cb),
                                         gtkaspell);
@@ -1222,7 +1261,7 @@ void gtkaspell_unblock_check(GtkAspell *gtkaspell)
 
 static void replace_real_word(GtkAspell *gtkaspell, const gchar *newword)
 {
-       int             oldlen, newlen, wordlen;
+       int             oldlen, newlen;
        gint            origpos;
        gint            pos;
        GtkTextView     *gtktext;
@@ -1237,16 +1276,10 @@ static void replace_real_word(GtkAspell *gtkaspell, const gchar *newword)
        origpos = gtkaspell->orig_pos;
        pos     = origpos;
        oldlen  = gtkaspell->end_pos - gtkaspell->start_pos;
-       wordlen = strlen(gtkaspell->theword);
 
        newlen = strlen(newword); /* FIXME: multybyte characters? */
 
-       g_signal_handlers_block_by_func(G_OBJECT(gtktext),
-                                        G_CALLBACK(entry_insert_cb),
-                                        gtkaspell);
-       g_signal_handlers_block_by_func(G_OBJECT(gtktext),
-                                        G_CALLBACK(entry_delete_cb),
-                                        gtkaspell);
+       gtkaspell_block_check(gtkaspell);
 
        gtk_text_buffer_get_iter_at_offset(textbuf, &startiter,
                                           gtkaspell->start_pos);
@@ -1257,12 +1290,7 @@ static void replace_real_word(GtkAspell *gtkaspell, const gchar *newword)
        g_signal_emit_by_name(G_OBJECT(textbuf), "insert-text",
                              &startiter, newword, newlen, gtkaspell);
 
-       g_signal_handlers_unblock_by_func(G_OBJECT(gtktext),
-                                          G_CALLBACK(entry_insert_cb),
-                                          gtkaspell);
-       g_signal_handlers_unblock_by_func(G_OBJECT(gtktext),
-                                          G_CALLBACK(entry_delete_cb),
-                                          gtkaspell);
+       gtkaspell_unblock_check(gtkaspell);
 
        /* Put the point and the position where we clicked with the mouse
         * It seems to be a hack, as I must thaw,freeze,thaw the widget
@@ -1302,10 +1330,7 @@ static void replace_real_word_cb(gpointer data, const gchar *newword)
 /* Accept this word for this session */
 static void add_word_to_session_cb(GtkWidget *w, gpointer data)
 {
-       GtkTextView *gtktext;
        GtkAspell *gtkaspell = (GtkAspell *) data; 
-       gtktext = gtkaspell->gtktext;
-
 
        enchant_dict_add_to_session(gtkaspell->gtkaspeller->speller, gtkaspell->theword, strlen(gtkaspell->theword));
 
@@ -1396,7 +1421,6 @@ static void replace_with_create_dialog_cb(GtkWidget *w, gpointer data)
        static PangoFontDescription *font_desc;
        GtkWidget *dialog;
        GtkWidget *label;
-       GtkWidget *w_hbox;
        GtkWidget *hbox;
        GtkWidget *vbox;
        GtkWidget *entry;
@@ -1434,8 +1458,6 @@ static void replace_with_create_dialog_cb(GtkWidget *w, gpointer data)
        thelabel = g_strdup_printf(_("<span weight=\"bold\" "
                                        "size=\"larger\">Replace \"%s\" with: </span>"), 
                                   utf8buf);
-       /* for title label */
-       w_hbox = gtk_hbox_new(FALSE, 0);
        
        icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,
                                        GTK_ICON_SIZE_DIALOG); 
@@ -1484,8 +1506,6 @@ static void replace_with_create_dialog_cb(GtkWidget *w, gpointer data)
        gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
        gtk_widget_show(label);
 
-       hbox = gtk_hbox_new(TRUE, 0);
-
        gtkut_stock_button_set_create(&confirm_area,
                                      &cancel_button, GTK_STOCK_CANCEL,
                                      &ok_button, GTK_STOCK_OK,
@@ -1761,19 +1781,75 @@ static gboolean aspell_key_pressed(GtkWidget *widget,
        return FALSE;
 }
 
+/* Create a paged submenu with choice of available dictionaries */
+static GtkWidget *make_dictionary_list_submenu(GtkAspell *gtkaspell)
+{
+       GtkWidget *menu, *curmenu, *moremenu, *item;
+       int count = 2;
+       Dictionary *dict;
+       GSList *tmp;
+
+       /* Dict list */
+       if (gtkaspellcheckers->dictionary_list == NULL)
+               gtkaspell_get_dictionary_list(FALSE);
+
+       menu = gtk_menu_new();
+       curmenu = menu;
+
+       item = gtk_menu_item_new_with_label(_("Change to..."));
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+       item = gtk_separator_menu_item_new();
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+       for (tmp = gtkaspellcheckers->dictionary_list; tmp != NULL; 
+                       tmp = g_slist_next(tmp)) {
+               if (count == MENUCOUNT) {
+
+                       moremenu = gtk_menu_new();
+                       item = gtk_menu_item_new_with_label(_("More..."));
+                       gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), 
+                                                 moremenu);
+
+                       gtk_menu_shell_append(GTK_MENU_SHELL(curmenu), item);
+                       curmenu = moremenu;
+                       count = 0;
+               }
+               dict = (Dictionary *) tmp->data;
+               item = gtk_check_menu_item_new_with_label(dict->fullname);
+               g_object_set_data(G_OBJECT(item), "dict_name",
+                                 dict->dictname); 
+               if (strcmp2(dict->fullname,
+                   gtkaspell->gtkaspeller->dictionary->fullname))
+                       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE);
+               else {
+                       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
+                       gtk_widget_set_sensitive(GTK_WIDGET(item),
+                                                FALSE);
+               }
+               g_signal_connect(G_OBJECT(item), "activate",
+                                G_CALLBACK(change_dict_cb),
+                                gtkaspell);
+               gtk_menu_shell_append(GTK_MENU_SHELL(curmenu), item);
+
+               count++;
+       }
+
+       gtk_widget_show_all(menu);
+       return menu;
+}
+
 /* make_sug_menu() - Add menus to accept this word for this session 
  * and to add it to personal dictionary 
  */
 static GSList *make_sug_menu(GtkAspell *gtkaspell) 
 {
-       GtkWidget       *item;
+       GtkWidget       *item, *submenu;
        char    *caption;
-       GtkTextView     *gtktext;
        GtkAccelGroup   *accel;
        GList           *l = gtkaspell->suggestions_list;
        gchar           *utf8buf;
        GSList *list = NULL;
-       gtktext = gtkaspell->gtktext;
 
        if (l == NULL)
                return NULL;
@@ -1787,10 +1863,12 @@ static GSList *make_sug_menu(GtkAspell *gtkaspell)
        }
 
        utf8buf  = g_strdup(l->data);
-       caption = g_strdup_printf(_("\"%s\" unknown in %s"), 
+       caption = g_strdup_printf(_("\"%s\" unknown in dictionary '%s'"), 
                                  utf8buf, 
                                  gtkaspell->gtkaspeller->dictionary->dictname);
        item = gtk_menu_item_new_with_label(caption);
+       submenu = make_dictionary_list_submenu(gtkaspell);
+       gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
        g_free(utf8buf);
        gtk_widget_show(item);
        list = g_slist_append(list, item);
@@ -1935,6 +2013,8 @@ static GSList *populate_submenu(GtkAspell *gtkaspell)
        item = gtk_menu_item_new_with_label(dictname);
        gtk_misc_set_alignment(GTK_MISC(gtk_bin_get_child(GTK_BIN((item)))), 0.5, 0.5);
        g_free(dictname);
+       submenu = make_dictionary_list_submenu(gtkaspell);
+       gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
        gtk_widget_show(item);
        list = g_slist_append(list, item);
 
@@ -1979,62 +2059,6 @@ static GSList *populate_submenu(GtkAspell *gtkaspell)
        gtk_widget_show(item);
        list = g_slist_append(list, item);
 
-       item = gtk_menu_item_new();
-        gtk_widget_show(item);
-        list = g_slist_append(list, item);
-
-       submenu = gtk_menu_new();
-        item = gtk_menu_item_new_with_label(_("Change dictionary"));
-        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),submenu);
-        gtk_widget_show(item);
-        list = g_slist_append(list, item);
-
-       /* Dict list */
-        if (gtkaspellcheckers->dictionary_list == NULL)
-               gtkaspell_get_dictionary_list(FALSE);
-        {
-               GtkWidget * curmenu = submenu;
-               int count = 0;
-               Dictionary *dict;
-               GSList *tmp;
-               tmp = gtkaspellcheckers->dictionary_list;
-               
-               for (tmp = gtkaspellcheckers->dictionary_list; tmp != NULL; 
-                               tmp = g_slist_next(tmp)) {
-                       if (count == MENUCOUNT) {
-                               GtkWidget *newmenu;
-                               
-                               newmenu = gtk_menu_new();
-                               item = gtk_menu_item_new_with_label(_("More..."));
-                               gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), 
-                                                         newmenu);
-                               
-                               gtk_menu_shell_append(GTK_MENU_SHELL(curmenu), item);
-                               gtk_widget_show(item);
-                               curmenu = newmenu;
-                               count = 0;
-                       }
-                       dict = (Dictionary *) tmp->data;
-                       item = gtk_check_menu_item_new_with_label(dict->dictname);
-                       g_object_set_data(G_OBJECT(item), "dict_name",
-                                         dict->fullname); 
-                       if (strcmp2(dict->fullname,
-                           gtkaspell->gtkaspeller->dictionary->fullname))
-                               gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), FALSE);
-                       else {
-                               gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
-                               gtk_widget_set_sensitive(GTK_WIDGET(item),
-                                                        FALSE);
-                       }
-                       g_signal_connect(G_OBJECT(item), "activate",
-                                        G_CALLBACK(change_dict_cb),
-                                        gtkaspell);
-                       gtk_widget_show(item);
-                       gtk_menu_shell_append(GTK_MENU_SHELL(curmenu), item);
-                       
-                       count++;
-               }
-        }  
        return list;
 }
 
@@ -2226,10 +2250,6 @@ static void switch_to_alternate_cb(GtkWidget *w,
 
 static void set_point_continue(GtkAspell *gtkaspell)
 {
-       GtkTextView  *gtktext;
-
-       gtktext = gtkaspell->gtktext;
-
        gtkaspell->ctx.set_position(gtkaspell->ctx.data, gtkaspell->orig_pos);
 
        if (gtkaspell->continue_check)
@@ -2362,17 +2382,6 @@ static void free_checkers(gpointer elt, gpointer data)
        gtkaspeller_real_delete(gtkaspeller);
 }
 
-static gint find_gtkaspeller(gconstpointer aa, gconstpointer bb)
-{
-       Dictionary *a = ((GtkAspeller *) aa)->dictionary;
-       Dictionary *b = ((GtkAspeller *) bb)->dictionary;
-
-       if (a && b && a->fullname && b->fullname)
-               return strcmp(a->fullname, b->fullname);
-
-       return 1;
-}
-
 gchar *gtkaspell_get_default_dictionary(GtkAspell *gtkaspell)
 {
        if (gtkaspell && gtkaspell->gtkaspeller &&