diff options
author | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-08-07 13:41:43 +0200 |
---|---|---|
committer | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-08-07 13:41:43 +0200 |
commit | 08e5778b19abcde484056e0cac76c237c2180142 (patch) | |
tree | f1fb1cfccf79d5228374b484367bfbe61b47614f /src | |
parent | 19b7e2f062f6224be07beb7be964343e200ceb4e (diff) |
spell checker support for multiple languages
Diffstat (limited to 'src')
-rw-r--r-- | src/fe-gtk/makefile.mak | 2 | ||||
-rw-r--r-- | src/fe-gtk/sexy-iso-codes.c | 301 | ||||
-rw-r--r-- | src/fe-gtk/sexy-iso-codes.h | 37 | ||||
-rw-r--r-- | src/fe-gtk/sexy-marshal.c | 129 | ||||
-rw-r--r-- | src/fe-gtk/sexy-marshal.h | 28 | ||||
-rw-r--r-- | src/fe-gtk/sexy-spell-entry.c | 27 | ||||
-rw-r--r-- | src/makeinc.skel.mak | 2 |
7 files changed, 504 insertions, 22 deletions
diff --git a/src/fe-gtk/makefile.mak b/src/fe-gtk/makefile.mak index f210181a..27922405 100644 --- a/src/fe-gtk/makefile.mak +++ b/src/fe-gtk/makefile.mak @@ -25,6 +25,8 @@ rawlog.obj \ search.obj \ servlistgui.obj \ setup.obj \ +sexy-iso-codes.obj \ +sexy-marshal.obj \ sexy-spell-entry.obj \ textgui.obj \ urlgrab.obj \ diff --git a/src/fe-gtk/sexy-iso-codes.c b/src/fe-gtk/sexy-iso-codes.c new file mode 100644 index 00000000..3477cc30 --- /dev/null +++ b/src/fe-gtk/sexy-iso-codes.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2005 Nathan Fredrickson + * Borrowed from Galeon, renamed, and simplified to only use iso-codes with no + * fallback method. + * + * Copyright (C) 2004 Christian Persch + * Copyright (C) 2004 Crispin Flowerday + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "../../config.h" + +#include "sexy-iso-codes.h" + +#include <glib/gi18n.h> + +#include <string.h> + +#include <libxml/xmlreader.h> + +static GHashTable *iso_639_table = NULL; +static GHashTable *iso_3166_table = NULL; + +#define ISO_639_DOMAIN "iso_639" +#define ISO_3166_DOMAIN "iso_3166" + +#ifdef HAVE_ISO_CODES + +#define ISOCODESLOCALEDIR "/share/locale" + +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_hash_table_insert (table, lcode, name); + } + else + { + xmlFree (code); + xmlFree (name); + } + +} + +typedef enum +{ + STATE_START, + STATE_STOP, + STATE_ENTRIES, +} ParserState; + +static gboolean +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; + + filename = g_strdup_printf (".\\share\\xml\\iso-codes\\iso_%d.xml", iso); + reader = xmlNewTextReaderFilename (filename); + if (reader == NULL) goto out; + + xmlStrPrintf (iso_entries, sizeof (iso_entries), + (xmlChar *)"iso_%d_entries", iso); + xmlStrPrintf (iso_entry, sizeof (iso_entry), + (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) + { + /* This is not critical, we will fallback to our own code */ + g_free (filename); + return FALSE; + } + + g_free (filename); + + return TRUE; +} + +#endif /* HAVE_ISO_CODES */ + + +static void +ensure_iso_codes_initialised (void) +{ + static gboolean initialised = FALSE; + + if (initialised == TRUE) + { + return; + } + initialised = TRUE; + +#if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES) + 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"); +#endif + + iso_639_table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) xmlFree, + (GDestroyNotify) xmlFree); + + iso_3166_table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) xmlFree); + +#ifdef HAVE_ISO_CODES + load_iso_entries (639, (GFunc) read_iso_639_entry, iso_639_table); + load_iso_entries (3166, (GFunc) read_iso_3166_entry, iso_3166_table); +#endif +} + + +static char * +get_iso_name_for_lang_code (const char *code) +{ + char **str; + char *name = NULL; + const char *langname, *localename; + int len; + + str = g_strsplit (code, "_", -1); + + /* count the entries */ + for (len = 0; str[len]; len++ ) /* empty */; + + 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) + { + localename = (const char *) g_hash_table_lookup (iso_3166_table, str[1]); + + if (localename != NULL) + { + /* translators: the first %s is the language name, and the + * second %s is the locale name. Example: + * "French (France) + * + * Also: The text before the "|" is context to help you decide on + * the correct translation. You MUST OMIT it in the translated string. + */ + name = g_strdup_printf (Q_("language|%s (%s)"), + dgettext (ISO_639_DOMAIN, langname), + dgettext (ISO_3166_DOMAIN, localename)); + } + else + { + name = g_strdup_printf (Q_("language|%s (%s)"), + dgettext (ISO_639_DOMAIN, langname), str[1]); + } + } + + g_strfreev (str); + + return name; +} + +/** + * gtkspell_iso_codes_lookup_name_for_code: + * @code: A language code, e.g. en_CA + * + * Looks up a name to display to the user for a language code, + * this might use the iso-codes package if support was compiled + * in, and it is available + * + * Returns: the UTF-8 string to display to the user, or NULL if + * a name for the code could not be found + */ +char * +gtkspell_iso_codes_lookup_name_for_code (const char *code) +{ + char * lcode; + char * ret; + + g_return_val_if_fail (code != NULL, NULL); + + ensure_iso_codes_initialised (); + + lcode = g_ascii_strdown (code, -1); + + ret = get_iso_name_for_lang_code (lcode); + + g_free (lcode); + + return ret; +} + diff --git a/src/fe-gtk/sexy-iso-codes.h b/src/fe-gtk/sexy-iso-codes.h new file mode 100644 index 00000000..e5f37162 --- /dev/null +++ b/src/fe-gtk/sexy-iso-codes.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005 Nathan Fredrickson + * Borrowed from Galeon, renamed, and simplified to only use iso-codes with no + * fallback method. + * + * Copyright (C) 2004 Christian Persch + * Copyright (C) 2004 Crispin Flowerday + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef GTKSPELL_ISO_CODES_H +#define GTKSPELL_ISO_CODES_H + +#include <glib.h> + +G_BEGIN_DECLS + +char * gtkspell_iso_codes_lookup_name_for_code (const char *code); + +G_END_DECLS + +#endif diff --git a/src/fe-gtk/sexy-marshal.c b/src/fe-gtk/sexy-marshal.c new file mode 100644 index 00000000..10a629f2 --- /dev/null +++ b/src/fe-gtk/sexy-marshal.c @@ -0,0 +1,129 @@ + +#include <glib-object.h> + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* BOOLEAN:STRING (./marshal.list:1) */ +void +sexy_marshal_BOOLEAN__STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__STRING) (gpointer data1, + gpointer arg_1, + gpointer data2); + register GMarshalFunc_BOOLEAN__STRING callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__STRING) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_string (param_values + 1), + data2); + + g_value_set_boolean (return_value, v_return); +} + +/* OBJECT:OBJECT,OBJECT (./marshal.list:2) */ +void +sexy_marshal_OBJECT__OBJECT_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef GObject* (*GMarshalFunc_OBJECT__OBJECT_OBJECT) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_OBJECT__OBJECT_OBJECT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GObject* v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_OBJECT__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_object (param_values + 2), + data2); + + g_value_take_object (return_value, v_return); +} + diff --git a/src/fe-gtk/sexy-marshal.h b/src/fe-gtk/sexy-marshal.h new file mode 100644 index 00000000..f41eccbe --- /dev/null +++ b/src/fe-gtk/sexy-marshal.h @@ -0,0 +1,28 @@ + +#ifndef __sexy_marshal_MARSHAL_H__ +#define __sexy_marshal_MARSHAL_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +/* BOOLEAN:STRING (./marshal.list:1) */ +extern void sexy_marshal_BOOLEAN__STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* OBJECT:OBJECT,OBJECT (./marshal.list:2) */ +extern void sexy_marshal_OBJECT__OBJECT_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +G_END_DECLS + +#endif /* __sexy_marshal_MARSHAL_H__ */ + diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c index 6bc4f0b5..4977a567 100644 --- a/src/fe-gtk/sexy-spell-entry.c +++ b/src/fe-gtk/sexy-spell-entry.c @@ -30,8 +30,8 @@ #include <glib/gi18n.h> #include <sys/types.h> #include <sys/stat.h> -/*#include "gtkspell-iso-codes.h" -#include "sexy-marshal.h"*/ +#include "sexy-iso-codes.h" +#include "sexy-marshal.h" #include "typedef.h" @@ -211,14 +211,14 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass) * Returns: %FALSE to indicate that the word should be marked as * correct. */ -/* signals[WORD_CHECK] = g_signal_new("word_check", + signals[WORD_CHECK] = g_signal_new("word_check", G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(SexySpellEntryClass, word_check), (GSignalAccumulator) spell_accumulator, NULL, sexy_marshal_BOOLEAN__STRING, G_TYPE_BOOLEAN, - 1, G_TYPE_STRING);*/ + 1, G_TYPE_STRING); } static void @@ -495,10 +495,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) if (entry->priv->dict_list == NULL) return topmenu; -#if 1 - dict = (struct EnchantDict *) entry->priv->dict_list->data; - build_suggestion_menu(entry, topmenu, dict, word); -#else /* Suggestions */ if (g_slist_length(entry->priv->dict_list) == 1) { dict = (struct EnchantDict *) entry->priv->dict_list->data; @@ -527,7 +523,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) build_suggestion_menu(entry, menu, dict, word); } } -#endif /* Separator */ mi = gtk_separator_menu_item_new (); @@ -541,11 +536,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU)); -#if 1 - dict = (struct EnchantDict *) entry->priv->dict_list->data; - g_object_set_data(G_OBJECT(mi), "enchant-dict", dict); - g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(add_to_dictionary), entry); -#else if (g_slist_length(entry->priv->dict_list) == 1) { dict = (struct EnchantDict *) entry->priv->dict_list->data; g_object_set_data(G_OBJECT(mi), "enchant-dict", dict); @@ -577,7 +567,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) gtk_menu_shell_append(GTK_MENU_SHELL(menu), submi); } } -#endif gtk_widget_show_all(mi); gtk_menu_shell_append(GTK_MENU_SHELL(topmenu), mi); @@ -759,11 +748,7 @@ word_misspelled(SexySpellEntry *entry, int start, int end) g_strlcpy(word, text + start, end - start + 1); -#if 0 g_signal_emit(entry, signals[WORD_CHECK], 0, word, &ret); -#else - ret = default_word_check (entry, word); -#endif g_free(word); return ret; @@ -1121,8 +1106,8 @@ gchar * sexy_spell_entry_get_language_name(const SexySpellEntry *entry, const gchar *lang) { - /*if (have_enchant) - return gtkspell_iso_codes_lookup_name_for_code(lang);*/ + if (have_enchant) + return gtkspell_iso_codes_lookup_name_for_code(lang); return NULL; } diff --git a/src/makeinc.skel.mak b/src/makeinc.skel.mak index ad737b38..ec14b34a 100644 --- a/src/makeinc.skel.mak +++ b/src/makeinc.skel.mak @@ -9,7 +9,7 @@ LIBS = $(LIBS) gdi32.lib shell32.lib user32.lib advapi32.lib imm32.lib ole32.lib GLIB = /I$(DEV)\include\glib-2.0 /I$(DEV)\lib\glib-2.0\include GTK = /I$(DEV)\include\gtk-2.0 /I$(DEV)\lib\gtk-2.0\include /I$(DEV)\include\atk-1.0 /I$(DEV)\include\cairo /I$(DEV)\include\pango-1.0 /I$(DEV)\include\gdk-pixbuf-2.0 -LIBS = $(LIBS) /libpath:$(DEV)\lib gtk-win32-2.0.lib gdk-win32-2.0.lib atk-1.0.lib gio-2.0.lib gdk_pixbuf-2.0.lib pangowin32-1.0.lib pangocairo-1.0.lib pango-1.0.lib cairo.lib gobject-2.0.lib gmodule-2.0.lib glib-2.0.lib intl.lib +LIBS = $(LIBS) /libpath:$(DEV)\lib gtk-win32-2.0.lib gdk-win32-2.0.lib atk-1.0.lib gio-2.0.lib gdk_pixbuf-2.0.lib pangowin32-1.0.lib pangocairo-1.0.lib pango-1.0.lib cairo.lib gobject-2.0.lib gmodule-2.0.lib glib-2.0.lib intl.lib libxml2.lib LUALIB = lua51 LUAOUTPUT = xclua.dll |