0.9.4claws47
[claws.git] / src / gtk / gtkaspell.c
index efaf39535606e01abe3546576a71054d9c5f2a10..c9eaae836cfd124aecaf070821c5bd92142cb174 100644 (file)
@@ -28,7 +28,7 @@
 #  include "config.h"
 #endif
 
-#if USE_ASPELL
+#ifdef USE_ASPELL
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -44,6 +44,8 @@
 #include <time.h>
 #include <dirent.h>
 
+#include <glib.h>
+
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 #include <gtk/gtkoptionmenu.h>
 #include <gtk/gtkmenuitem.h>
 #include <gdk/gdkkeysyms.h>
 
+#include <aspell.h>
+
 #include "intl.h"
 #include "gtkstext.h"
 #include "utils.h"
+
 #include "gtkaspell.h"
+#define ASPELL_FASTMODE       1
+#define ASPELL_NORMALMODE     2
+#define ASPELL_BADSPELLERMODE 3
+
+#define GTKASPELLWORDSIZE 1024
 
 /* size of the text buffer used in various word-processing routines. */
 #define BUFSIZE 1024
        RETURN_FALSE_IF_CONFIG_ERROR();                      \
        }
 
+typedef struct _GtkAspellCheckers {
+       GSList          *checkers;
+       GSList          *dictionary_list;
+       gchar           *error_message;
+} GtkAspellCheckers;
+
+typedef struct _Dictionary {
+       gchar *fullname;
+       gchar *dictname;
+       gchar *encoding;
+} Dictionary;
+
+typedef struct _GtkAspeller {
+       Dictionary      *dictionary;
+       gint             sug_mode;
+       AspellConfig    *config;
+       AspellSpeller   *checker;
+} GtkAspeller;
+
+typedef void (*ContCheckFunc) (gpointer *gtkaspell);
+
+struct _GtkAspell
+{
+       GtkAspeller     *gtkaspeller;
+       GtkAspeller     *alternate_speller;
+       gchar           *dictionary_path;
+       gchar            theword[GTKASPELLWORDSIZE];
+       gint             start_pos;
+       gint             end_pos;
+        gint            orig_pos;
+       gint             end_check_pos;
+       gboolean         misspelled;
+       gboolean         check_while_typing;
+       gboolean         use_alternate;
+
+       ContCheckFunc    continue_check; 
+
+       GtkWidget       *config_menu;
+       GtkWidget       *popup_config_menu;
+       GtkWidget       *sug_menu;
+       GtkWidget       *replace_entry;
+
+       gint             default_sug_mode;
+       gint             max_sug;
+       GList           *suggestions_list;
+
+       GtkSText        *gtktext;
+       GdkColor         highlight;
+};
+
+typedef AspellConfig GtkAspellConfig;
+
 /******************************************************************************/
 
-GtkAspellCheckers *gtkaspellcheckers;
+static GtkAspellCheckers *gtkaspellcheckers;
 
 /* Error message storage */
 static void gtkaspell_checkers_error_message   (gchar          *message);
@@ -191,25 +253,21 @@ GtkAspellConfig * gtkaspellconfig;
 
 /******************************************************************************/
 
-GtkAspellCheckers *gtkaspell_checkers_new(void)
+void gtkaspell_checkers_init(void)
 {
-       GtkAspellCheckers *gtkaspellcheckers;
-       
        gtkaspellcheckers                  = g_new(GtkAspellCheckers, 1);
        gtkaspellcheckers->checkers        = NULL;
        gtkaspellcheckers->dictionary_list = NULL;
        gtkaspellcheckers->error_message   = NULL;
-       
-       return gtkaspellcheckers;
 }
        
-GtkAspellCheckers *gtkaspell_checkers_delete(void)
+void gtkaspell_checkers_quit(void)
 {
        GSList *checkers;
        GSList *dict_list;
 
        if (gtkaspellcheckers == NULL) 
-               return NULL;
+               return;
 
        if ((checkers  = gtkaspellcheckers->checkers)) {
                debug_print("Aspell: number of running checkers to delete %d\n",
@@ -229,7 +287,7 @@ GtkAspellCheckers *gtkaspell_checkers_delete(void)
 
        g_free(gtkaspellcheckers->error_message);
 
-       return NULL;
+       return;
 }
 
 static void gtkaspell_checkers_error_message (gchar *message)
@@ -245,6 +303,12 @@ static void gtkaspell_checkers_error_message (gchar *message)
                gtkaspellcheckers->error_message = message;
 }
 
+const char *gtkaspell_checkers_strerror(void)
+{
+       g_return_val_if_fail(gtkaspellcheckers, "");
+       return gtkaspellcheckers->error_message;
+}
+
 void gtkaspell_checkers_reset_error(void)
 {
        g_return_if_fail(gtkaspellcheckers);
@@ -364,6 +428,8 @@ static void entry_insert_cb(GtkSText *gtktext,
                            guint *ppos, 
                             GtkAspell *gtkaspell) 
 {
+       size_t wlen;
+
        g_return_if_fail(gtkaspell->gtkaspeller->checker);
 
        if (!gtkaspell->check_while_typing)
@@ -375,7 +441,16 @@ static void entry_insert_cb(GtkSText *gtktext,
         */
 
        gtk_stext_freeze(gtktext);
-       gtk_stext_backward_delete(GTK_STEXT(gtktext), len);
+       if (MB_CUR_MAX > 1) {
+               gchar *str;
+               Xstrndup_a(str, newtext, len, return);
+               wlen = mbstowcs(NULL, str, 0);
+               if (wlen < 0)
+                       return;
+       } else
+               wlen = len;
+       
+       gtk_stext_backward_delete(GTK_STEXT(gtktext), wlen);
        gtk_stext_insert(GTK_STEXT(gtktext), NULL, NULL, NULL, newtext, len);
        *ppos = gtk_stext_get_point(GTK_STEXT(gtktext));
               
@@ -1439,7 +1514,7 @@ GSList *gtkaspell_get_dictionary_list(const gchar *aspell_path, gint refresh)
        const AspellDictInfo *entry;
 
        if (!gtkaspellcheckers)
-               gtkaspellcheckers = gtkaspell_checkers_new();
+               gtkaspell_checkers_init();
 
        if (gtkaspellcheckers->dictionary_list && !refresh)
                return gtkaspellcheckers->dictionary_list;
@@ -1559,6 +1634,35 @@ gchar *gtkaspell_get_dictionary_menu_active_item(GtkWidget *menu)
   
 }
 
+gint gtkaspell_set_dictionary_menu_active_item(GtkWidget *menu, const gchar *dictionary)
+{
+       GList *cur;
+       gint n;
+
+       g_return_val_if_fail(menu != NULL, 0);
+       g_return_val_if_fail(dictionary != NULL, 0);
+       g_return_val_if_fail(GTK_IS_OPTION_MENU(menu), 0);
+
+       n = 0;
+       for (cur = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(menu)))->children;
+            cur != NULL; cur = cur->next) {
+               GtkWidget *menuitem;
+               gchar *dict_name;
+
+               menuitem = GTK_WIDGET(cur->data);
+               dict_name = gtk_object_get_data(GTK_OBJECT(menuitem), 
+                                               "dict_name");
+               if ((dict_name != NULL) && !strcmp2(dict_name, dictionary)) {
+                       gtk_option_menu_set_history(GTK_OPTION_MENU(menu), n);
+
+                       return 1;
+               }
+               n++;
+       }
+
+       return 0;
+}
+
 GtkWidget *gtkaspell_sugmode_option_menu_new(gint sugmode)
 {
        GtkWidget *menu;
@@ -2008,30 +2112,26 @@ static gboolean cancel_menu_cb(GtkMenuShell *w, gpointer data)
        
 }
 
-/* change_dict_cb() - Menu callback : change dict */
-static void change_dict_cb(GtkWidget *w, GtkAspell *gtkaspell)
+gboolean gtkaspell_change_dict(GtkAspell *gtkaspell, guchar *dictionary)
 {
        Dictionary      *dict;       
-       gchar           *fullname;
        GtkAspeller     *gtkaspeller;
        gint             sug_mode;
-  
-        fullname = (gchar *) gtk_object_get_data(GTK_OBJECT(w), "dict_name");
-       
-       if (!strcmp2(fullname, _("None")))
-               return;
 
+       g_return_val_if_fail(gtkaspell, FALSE);
+       g_return_val_if_fail(dictionary, FALSE);
+  
        sug_mode  = gtkaspell->default_sug_mode;
 
        dict = g_new0(Dictionary, 1);
-       dict->fullname = g_strdup(fullname);
+       dict->fullname = g_strdup(dictionary);
        dict->encoding = g_strdup(gtkaspell->gtkaspeller->dictionary->encoding);
 
        if (gtkaspell->use_alternate && gtkaspell->alternate_speller &&
            dict == gtkaspell->alternate_speller->dictionary) {
                use_alternate_dict(gtkaspell);
                dictionary_delete(dict);
-               return;
+               return TRUE;
        }
        
        gtkaspeller = gtkaspeller_new(dict);
@@ -2059,6 +2159,21 @@ static void change_dict_cb(GtkWidget *w, GtkAspell *gtkaspell)
 
        if (gtkaspell->config_menu)
                populate_submenu(gtkaspell, gtkaspell->config_menu);
+
+       return TRUE;    
+}
+
+/* change_dict_cb() - Menu callback : change dict */
+static void change_dict_cb(GtkWidget *w, GtkAspell *gtkaspell)
+{
+       gchar           *fullname;
+  
+        fullname = (gchar *) gtk_object_get_data(GTK_OBJECT(w), "dict_name");
+       
+       if (!strcmp2(fullname, _("None")))
+               return;
+
+       gtkaspell_change_dict(gtkaspell, fullname);
 }
 
 static void switch_to_alternate_cb(GtkWidget *w,