SF.net SVN: geany-plugins:[212] trunk/spellcheck

eht16 at users.sourceforge.net eht16 at xxxxx
Fri Oct 17 15:20:12 UTC 2008


Revision: 212
          http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=212&view=rev
Author:   eht16
Date:     2008-10-17 15:20:12 +0000 (Fri, 17 Oct 2008)

Log Message:
-----------
Split spellcheck.c into three source files.

Modified Paths:
--------------
    trunk/spellcheck/ChangeLog
    trunk/spellcheck/po/POTFILES.in
    trunk/spellcheck/src/Makefile.am

Added Paths:
-----------
    trunk/spellcheck/src/gui.c
    trunk/spellcheck/src/gui.h
    trunk/spellcheck/src/scplugin.c
    trunk/spellcheck/src/scplugin.h
    trunk/spellcheck/src/speller.c
    trunk/spellcheck/src/speller.h

Removed Paths:
-------------
    trunk/spellcheck/src/spellcheck.c

Modified: trunk/spellcheck/ChangeLog
===================================================================
--- trunk/spellcheck/ChangeLog	2008-10-16 16:21:41 UTC (rev 211)
+++ trunk/spellcheck/ChangeLog	2008-10-17 15:20:12 UTC (rev 212)
@@ -1,3 +1,11 @@
+2008-10-17  Enrico Tröger  <enrico(dot)troeger(at)uvena(dot)de>
+
+ * src/spellcheck.c, src/scplugin.c, src/gui.c, src/speller.c,
+   src/scplugin.h, src/gui.h, src/speller.h, src/Makefile.am,
+   po/POTFILES.in:
+   Split spellcheck.c into three source files.
+
+
 2008-10-16  Enrico Tröger  <enrico(dot)troeger(at)uvena(dot)de>
 
  * src/spellcheck.c:

Modified: trunk/spellcheck/po/POTFILES.in
===================================================================
--- trunk/spellcheck/po/POTFILES.in	2008-10-16 16:21:41 UTC (rev 211)
+++ trunk/spellcheck/po/POTFILES.in	2008-10-17 15:20:12 UTC (rev 212)
@@ -1,3 +1,5 @@
 # List of source files containing translatable strings.
 
-src/spellcheck.c
+src/scplugin.c
+src/gui.c
+src/speller.c

Modified: trunk/spellcheck/src/Makefile.am
===================================================================
--- trunk/spellcheck/src/Makefile.am	2008-10-16 16:21:41 UTC (rev 211)
+++ trunk/spellcheck/src/Makefile.am	2008-10-17 15:20:12 UTC (rev 212)
@@ -1,6 +1,6 @@
 
 lib_LTLIBRARIES = spellcheck.la
-spellcheck_la_SOURCES = spellcheck.c
+spellcheck_la_SOURCES = speller.c speller.h scplugin.c scplugin.h gui.c gui.h
 spellcheck_la_LDFLAGS = -module -avoid-version
 spellcheck_la_LIBADD  = @GEANY_LIBS@  $(INTLLIBS) @ENCHANT_LIBS@
 

Added: trunk/spellcheck/src/gui.c
===================================================================
--- trunk/spellcheck/src/gui.c	                        (rev 0)
+++ trunk/spellcheck/src/gui.c	2008-10-17 15:20:12 UTC (rev 212)
@@ -0,0 +1,377 @@
+/*
+ *      gui.c - this file is part of Spellcheck, a Geany plugin
+ *
+ *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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 Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+#include "geany.h"
+#include "support.h"
+
+
+#include "plugindata.h"
+
+#include "document.h"
+#include "editor.h"
+#include "msgwindow.h"
+#include "utils.h"
+#include "ui_utils.h"
+
+#include "pluginmacros.h"
+
+#include "gui.h"
+#include "scplugin.h"
+#include "speller.h"
+
+
+
+/* Flag to indicate that a callback function will be triggered by generating the appropriate event
+ * but the callback should be ignored. */
+static gboolean ignore_sc_callback = FALSE;
+
+
+
+void gui_perform_check(GeanyDocument *doc)
+{
+	p_editor->clear_indicators(doc->editor);
+	if (sc->use_msgwin)
+	{
+		p_msgwindow->clear_tab(MSG_MESSAGE);
+		p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
+	}
+
+	speller_check_document(doc);
+}
+
+
+static void toolbar_item_toggled_cb(GtkToggleToolButton *button, gpointer user_data)
+{
+	if (ignore_sc_callback)
+		return;
+
+	sc->check_while_typing = gtk_toggle_tool_button_get_active(button);
+
+	p_ui->set_statusbar(FALSE, _("Spell checking while typing is now %s"),
+		(sc->check_while_typing) ? _("enabled") : _("disabled"));
+}
+
+
+void gui_toolbar_update(void)
+{
+	/* toolbar item is not requested, so remove the item if it exists */
+	if (! sc->show_toolbar_item)
+	{
+		if (sc->toolbar_button != NULL)
+		{
+			gtk_widget_destroy(GTK_WIDGET(sc->toolbar_button));
+			sc->toolbar_button = NULL;
+		}
+	}
+	else
+	{
+		if (sc->toolbar_button == NULL)
+		{
+			sc->toolbar_button = gtk_toggle_tool_button_new_from_stock("gtk-spell-check");
+#if GTK_CHECK_VERSION(2, 12, 0)
+			gtk_widget_set_tooltip_text(GTK_WIDGET(sc->toolbar_button),
+				_("Toggle spell check while typing."));
+#endif
+			gtk_widget_show(GTK_WIDGET(sc->toolbar_button));
+			p_plugin->add_toolbar_item(geany_plugin, sc->toolbar_button);
+			p_ui->add_document_sensitive(GTK_WIDGET(sc->toolbar_button));
+
+			g_signal_connect(sc->toolbar_button, "toggled",
+				G_CALLBACK(toolbar_item_toggled_cb), NULL);
+		}
+
+		ignore_sc_callback = TRUE;
+		gtk_toggle_tool_button_set_active(
+			GTK_TOGGLE_TOOL_BUTTON(sc->toolbar_button), sc->check_while_typing);
+		ignore_sc_callback = FALSE;
+	}
+}
+
+
+static void clear_indicators_on_range(GeanyDocument *doc, gint start, gint len)
+{
+	g_return_if_fail(doc != NULL);
+
+	if (len > 0)
+	{
+		p_sci->indicator_clear(doc->editor->sci, start, start + len);
+	}
+}
+
+
+static void clear_indicators_on_line(GeanyDocument *doc, gint line_number)
+{
+	gint start_pos, length;
+
+	g_return_if_fail(doc != NULL);
+
+	start_pos = p_sci->get_position_from_line(doc->editor->sci, line_number);
+	length = p_sci->get_line_length(doc->editor->sci, line_number);
+
+	clear_indicators_on_range(doc, start_pos, length);
+}
+
+
+
+static void menu_suggestion_item_activate_cb(GtkMenuItem *menuitem, gpointer gdata)
+{
+	gchar *sugg = gdata;
+	gint startword, endword;
+
+	if (clickinfo.doc == NULL || clickinfo.pos == -1)
+	{
+		g_free(sugg);
+		return;
+	}
+
+	startword = p_sci->send_message(
+		clickinfo.doc->editor->sci, SCI_WORDSTARTPOSITION, clickinfo.pos, 0);
+	endword = p_sci->send_message(
+		clickinfo.doc->editor->sci, SCI_WORDENDPOSITION, clickinfo.pos, 0);
+
+	if (startword != endword)
+	{
+		p_sci->set_selection_start(clickinfo.doc->editor->sci, startword);
+		p_sci->set_selection_end(clickinfo.doc->editor->sci, endword);
+		p_sci->replace_sel(clickinfo.doc->editor->sci, sugg);
+
+		clear_indicators_on_range(clickinfo.doc, startword, endword - startword);
+	}
+}
+
+
+static void on_menu_addword_item_activate(GtkMenuItem *menuitem, gpointer gdata)
+{
+	gint startword, endword;
+
+	if (clickinfo.doc == NULL || clickinfo.word == NULL || clickinfo.pos == -1)
+		return;
+
+	/** TODO re-check the whole document */
+	speller_add_word(clickinfo.word);
+
+	startword = p_sci->send_message(
+		clickinfo.doc->editor->sci, SCI_WORDSTARTPOSITION, clickinfo.pos, 0);
+	endword = p_sci->send_message(
+		clickinfo.doc->editor->sci, SCI_WORDENDPOSITION, clickinfo.pos, 0);
+	if (startword != endword)
+	{
+		clear_indicators_on_range(clickinfo.doc, startword, endword - startword);
+	}
+}
+
+
+void gui_update_editor_menu_cb(GObject *obj, const gchar *word, gint pos,
+								  GeanyDocument *doc, gpointer user_data)
+{
+	gsize n_suggs, i;
+	gchar **tmp_suggs;
+
+	g_return_if_fail(doc != NULL && doc->is_valid);
+
+	/* hide the submenu in any case, we will reshow it again if we actually found something */
+	gtk_widget_hide(sc->edit_menu);
+	gtk_widget_hide(sc->edit_menu_sep);
+
+	if (! NZV(word) || speller_dict_check(word) == 0)
+		return;
+
+	tmp_suggs = speller_dict_suggest(word, &n_suggs);
+
+	if (tmp_suggs != NULL)
+	{
+		GtkWidget *menu_item, *image;
+		gchar *label;
+
+		clickinfo.pos = pos;
+		clickinfo.doc = doc;
+		setptr(clickinfo.word, g_strdup(word));
+
+		if (GTK_IS_WIDGET(sc->edit_menu_sub))
+			gtk_widget_destroy(sc->edit_menu_sub);
+
+		sc->edit_menu_sub = gtk_menu_new();
+		gtk_menu_item_set_submenu(GTK_MENU_ITEM(sc->edit_menu), sc->edit_menu_sub);
+
+		/* TODO do we need more than 10 suggestions? gtkspell offers additional suggestions
+		 * in another sub menu, should we too? */
+		for (i = 0; i < MIN(n_suggs, MAX_MENU_SUGGESTIONS); i++)
+		{
+			/* keep the suggestions in a static array for the callback function */
+			g_free(clickinfo.suggs[i]);
+			clickinfo.suggs[i] = g_strdup(tmp_suggs[i]);
+
+			menu_item = gtk_menu_item_new_with_label(clickinfo.suggs[i]);
+			gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item);
+			g_signal_connect((gpointer) menu_item, "activate",
+				G_CALLBACK(menu_suggestion_item_activate_cb), clickinfo.suggs[i]);
+		}
+		menu_item = gtk_separator_menu_item_new();
+		gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item);
+
+		image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
+
+		label = g_strdup_printf(_("Add \"%s\" to Dictionary"), word);
+		menu_item = gtk_image_menu_item_new_with_label(label);
+		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
+		gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item);
+		g_signal_connect((gpointer) menu_item, "activate",
+			G_CALLBACK(on_menu_addword_item_activate), NULL);
+
+		gtk_widget_show(sc->edit_menu);
+		gtk_widget_show(sc->edit_menu_sep);
+		gtk_widget_show_all(sc->edit_menu_sub);
+
+		speller_dict_free_string_list(tmp_suggs);
+
+		g_free(label);
+	}
+}
+
+
+/* Checks only the last word before the current cursor position -> check as you type. */
+gboolean gui_key_release_cb(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
+{
+	gint line_number;
+	GString *str = g_string_sized_new(256);
+	gchar *line;
+	GeanyDocument *doc;
+	static time_t time_prev = 0;
+	time_t time_now = time(NULL);
+	GtkWidget *focusw;
+
+	if (! sc->check_while_typing)
+		return FALSE;
+	/* check only once a second */
+	if (time_now == time_prev)
+		return FALSE;
+	/* set current time for the next key press */
+	time_prev = time_now;
+
+	doc = p_document->get_current();
+	/* bail out if we don't have a document or if we are not in the editor widget */
+	focusw = gtk_window_get_focus(GTK_WINDOW(geany->main_widgets->window));
+	if (doc == NULL || focusw != GTK_WIDGET(doc->editor->sci))
+		return FALSE;
+
+	if (ev->keyval == '\r' &&
+		p_sci->send_message(doc->editor->sci, SCI_GETEOLMODE, 0, 0) == SC_EOL_CRLF)
+	{	/* prevent double line checking */
+		return FALSE;
+	}
+
+	line_number = p_sci->get_current_line(doc->editor->sci);
+	if (ev->keyval == '\n' || ev->keyval == '\r')
+		line_number--; /* check previous line if we start a new one */
+	line = p_sci->get_line(doc->editor->sci, line_number);
+
+	clear_indicators_on_line(doc, line_number);
+	if (speller_process_line(doc, line_number, line) != 0)
+	{
+		if (sc->use_msgwin)
+			p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
+	}
+
+	g_string_free(str, TRUE);
+	g_free(line);
+
+	return FALSE;
+}
+
+
+static void menu_item_activate_cb(GtkMenuItem *menuitem, gpointer gdata)
+{
+	GeanyDocument *doc;
+
+	doc = p_document->get_current();
+
+	/* Another language was chosen from the menu item, so make it default for this session. */
+    if (gdata != NULL)
+		setptr(sc->default_language, g_strdup(gdata));
+
+	speller_reinit_enchant_dict();
+
+	p_editor->clear_indicators(doc->editor);
+	if (sc->use_msgwin)
+	{
+		p_msgwindow->clear_tab(MSG_MESSAGE);
+		p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
+	}
+
+	speller_check_document(doc);
+}
+
+
+void gui_kb_activate_cb(guint key_id)
+{
+	menu_item_activate_cb(NULL, NULL);
+}
+
+
+void gui_create_edit_menu(void)
+{
+	sc->edit_menu = gtk_image_menu_item_new_from_stock(GTK_STOCK_SPELL_CHECK, NULL);
+	gtk_container_add(GTK_CONTAINER(geany->main_widgets->editor_menu), sc->edit_menu);
+	gtk_menu_reorder_child(GTK_MENU(geany->main_widgets->editor_menu), sc->edit_menu, 0);
+
+	sc->edit_menu_sep = gtk_separator_menu_item_new();
+	gtk_container_add(GTK_CONTAINER(geany->main_widgets->editor_menu), sc->edit_menu_sep);
+	gtk_menu_reorder_child(GTK_MENU(geany->main_widgets->editor_menu), sc->edit_menu_sep, 1);
+
+	gtk_widget_show_all(sc->edit_menu);
+}
+
+
+GtkWidget *gui_create_menu(GtkWidget *sp_item)
+{
+	GtkWidget *menu, *subitem;
+	guint i;
+
+	gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), sp_item);
+
+	menu = gtk_menu_new();
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(sp_item), menu);
+
+	subitem = gtk_menu_item_new_with_mnemonic(_("Default"));
+	gtk_container_add(GTK_CONTAINER(menu), subitem);
+	g_signal_connect((gpointer) subitem, "activate", G_CALLBACK(menu_item_activate_cb), NULL);
+
+	subitem = gtk_separator_menu_item_new();
+	gtk_container_add(GTK_CONTAINER(menu), subitem);
+
+	for (i = 0; i < sc->dicts->len; i++)
+	{
+		GtkWidget *menu_item;
+
+		menu_item = gtk_menu_item_new_with_label(g_ptr_array_index(sc->dicts, i));
+		gtk_container_add(GTK_CONTAINER(menu), menu_item);
+		g_signal_connect((gpointer) menu_item, "activate",
+			G_CALLBACK(menu_item_activate_cb), g_ptr_array_index(sc->dicts, i));
+	}
+
+	return sp_item;
+}
+
+


Property changes on: trunk/spellcheck/src/gui.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Added: trunk/spellcheck/src/gui.h
===================================================================
--- trunk/spellcheck/src/gui.h	                        (rev 0)
+++ trunk/spellcheck/src/gui.h	2008-10-17 15:20:12 UTC (rev 212)
@@ -0,0 +1,48 @@
+/*
+ *      gui.h - this file is part of Spellcheck, a Geany plugin
+ *
+ *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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 Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+#ifndef SC_GUI_H
+#define SC_GUI_H 1
+
+
+
+void gui_update_editor_menu_cb(GObject *obj, const gchar *word, gint pos,
+						   GeanyDocument *doc, gpointer user_data);
+
+gboolean gui_key_release_cb(GtkWidget *widget, GdkEventKey *ev, gpointer user_data);
+
+void gui_kb_activate_cb(guint key_id);
+
+
+void gui_create_edit_menu(void);
+
+GtkWidget *gui_create_menu(GtkWidget *sp_item);
+
+void gui_update_editor_menu_cb(GObject *obj, const gchar *word, gint pos,
+								  GeanyDocument *doc, gpointer user_data);
+
+void gui_toolbar_update(void);
+
+#endif


Property changes on: trunk/spellcheck/src/gui.h
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Added: trunk/spellcheck/src/scplugin.c
===================================================================
--- trunk/spellcheck/src/scplugin.c	                        (rev 0)
+++ trunk/spellcheck/src/scplugin.c	2008-10-17 15:20:12 UTC (rev 212)
@@ -0,0 +1,312 @@
+/*
+ *      scplugin.c - this file is part of Spellcheck, a Geany plugin
+ *
+ *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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 Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+#include "geany.h"
+#include "support.h"
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+/*
+#ifdef G_OS_WIN32
+# include <windows.h>
+#endif
+*/
+
+#include "plugindata.h"
+
+#include "keybindings.h"
+#include "utils.h"
+#include "ui_utils.h"
+
+#include "pluginmacros.h"
+
+#include "scplugin.h"
+#include "gui.h"
+#include "speller.h"
+
+
+GeanyPlugin		*geany_plugin;
+GeanyData		*geany_data;
+GeanyFunctions	*geany_functions;
+
+
+PLUGIN_VERSION_CHECK(100)
+PLUGIN_SET_INFO(_("Spell Check"), _("Checks the spelling of the current document."), "0.2",
+			_("The Geany developer team"))
+
+
+SpellCheck *sc = NULL;
+SpellClickInfo clickinfo;
+
+
+
+/* Keybinding(s) */
+enum
+{
+	KB_SPELL_CHECK,
+	KB_COUNT
+};
+PLUGIN_KEY_GROUP(spellcheck, KB_COUNT)
+
+
+
+PluginCallback plugin_callbacks[] =
+{
+    { "update-editor-menu", (GCallback) &gui_update_editor_menu_cb, FALSE, NULL },
+    { NULL, NULL, FALSE, NULL }
+};
+
+
+/* currently unused */
+#ifdef G_OS_WIN32
+#warning TODO check Windows support
+/* On Windows we need to find the Aspell installation prefix via the Windows Registry
+ * and then set the prefix in the Aspell config object. */
+static void set_up_aspell_prefix(AspellConfig *config)
+{
+	char sTemp[1024];
+	HKEY hkey;
+	DWORD len = sizeof(sTemp);
+
+	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Aspell"), 0,
+			KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
+		return;
+
+	if (RegQueryValueEx(hkey, NULL, 0, NULL, (LPBYTE)sTemp, &len) == ERROR_SUCCESS)
+		aspell_config_replace(config, "prefix", sTemp);
+
+	RegCloseKey(hkey);
+}
+#endif
+
+
+static void locale_init(void)
+{
+#ifdef ENABLE_NLS
+	gchar *locale_dir = NULL;
+
+#ifdef HAVE_LOCALE_H
+	setlocale(LC_ALL, "");
+#endif
+
+#ifdef G_OS_WIN32
+	gchar *install_dir = g_win32_get_package_installation_directory("geany", NULL);
+	/* e.g. C:\Program Files\geany\lib\locale */
+	locale_dir = g_strconcat(install_dir, "\\share\\locale", NULL);
+	g_free(install_dir);
+#else
+	locale_dir = g_strdup(LOCALEDIR);
+#endif
+
+	bindtextdomain(GETTEXT_PACKAGE, locale_dir);
+	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+	textdomain(GETTEXT_PACKAGE);
+	g_free(locale_dir);
+#endif
+}
+
+
+static void configure_response_cb(GtkDialog *dialog, gint response, gpointer user_data)
+{
+	if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
+	{
+		GKeyFile *config = g_key_file_new();
+		gchar *data;
+		gchar *config_dir = g_path_get_dirname(sc->config_file);
+
+		setptr(sc->default_language, gtk_combo_box_get_active_text(GTK_COMBO_BOX(
+			g_object_get_data(G_OBJECT(dialog), "combo"))));
+		speller_reinit_enchant_dict();
+
+		sc->check_while_typing = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+			g_object_get_data(G_OBJECT(dialog), "check_type"))));
+
+		sc->use_msgwin = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+			g_object_get_data(G_OBJECT(dialog), "check_msgwin"))));
+
+		sc->show_toolbar_item = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+			g_object_get_data(G_OBJECT(dialog), "check_toolbar"))));
+
+		g_key_file_load_from_file(config, sc->config_file, G_KEY_FILE_NONE, NULL);
+		if (sc->default_language != NULL) /* lang may be NULL */
+			g_key_file_set_string(config, "spellcheck", "language", sc->default_language);
+		g_key_file_set_boolean(config, "spellcheck", "check_while_typing", sc->check_while_typing);
+		g_key_file_set_boolean(config, "spellcheck", "use_msgwin", sc->use_msgwin);
+		g_key_file_set_boolean(config, "spellcheck", "show_toolbar_item", sc->show_toolbar_item);
+
+		gui_toolbar_update();
+
+		if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
+		{
+			p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
+				_("Plugin configuration directory could not be created."));
+		}
+		else
+		{
+			/* write config to file */
+			data = g_key_file_to_data(config, NULL, NULL);
+			p_utils->write_file(sc->config_file, data);
+			g_free(data);
+		}
+		g_free(config_dir);
+		g_key_file_free(config);
+	}
+}
+
+
+void plugin_init(GeanyData *data)
+{
+	GtkWidget *sp_item;
+	GKeyFile *config = g_key_file_new();
+	guint i;
+
+	sc = g_new0(SpellCheck, 1);
+
+	sc->config_file = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
+		"spellcheck", G_DIR_SEPARATOR_S, "spellcheck.conf", NULL);
+
+	g_key_file_load_from_file(config, sc->config_file, G_KEY_FILE_NONE, NULL);
+	sc->default_language = p_utils->get_setting_string(config,
+		"spellcheck", "language", speller_get_default_lang());
+	sc->check_while_typing = p_utils->get_setting_boolean(config,
+		"spellcheck", "check_while_typing", FALSE);
+	sc->show_toolbar_item = p_utils->get_setting_boolean(config,
+		"spellcheck", "show_toolbar_item", TRUE);
+	sc->use_msgwin = p_utils->get_setting_boolean(config, "spellcheck", "use_msgwin", FALSE);
+	g_key_file_free(config);
+
+	locale_init();
+
+	sc->menu_item = gtk_image_menu_item_new_from_stock("gtk-spell-check", NULL);
+	p_ui->add_document_sensitive(sc->menu_item);
+
+	gui_toolbar_update();
+
+	speller_init();
+
+	for (i = 0; i < MAX_MENU_SUGGESTIONS; i++)
+	{
+		clickinfo.suggs[i] = NULL;
+	}
+	clickinfo.word = NULL;
+
+	gui_create_edit_menu();
+	sp_item = gui_create_menu(sc->menu_item);
+	gtk_widget_show_all(sp_item);
+
+	sc->signal_id = g_signal_connect(geany->main_widgets->window,
+		"key-release-event", G_CALLBACK(gui_key_release_cb), NULL);
+
+	/* setup keybindings */
+	p_keybindings->set_item(plugin_key_group, KB_SPELL_CHECK, gui_kb_activate_cb,
+		0, 0, "spell_check", _("Run Spell Check"), NULL);
+}
+
+
+GtkWidget *plugin_configure(GtkDialog *dialog)
+{
+	GtkWidget *label, *vbox, *combo, *check_type, *check_msgwin, *check_toolbar;
+	guint i;
+
+	vbox = gtk_vbox_new(FALSE, 6);
+
+	check_type = gtk_check_button_new_with_label(_("Check spelling while typing"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_type), sc->check_while_typing);
+	gtk_box_pack_start(GTK_BOX(vbox), check_type, FALSE, FALSE, 6);
+
+	check_toolbar = gtk_check_button_new_with_label(_("Show toolbar item to toggle spell checking"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_toolbar), sc->show_toolbar_item);
+	gtk_box_pack_start(GTK_BOX(vbox), check_toolbar, FALSE, FALSE, 3);
+
+	check_msgwin = gtk_check_button_new_with_label(
+		_("Print misspelled words and suggestions in the messages window"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_msgwin), sc->use_msgwin);
+	gtk_box_pack_start(GTK_BOX(vbox), check_msgwin, FALSE, FALSE, 3);
+
+	label = gtk_label_new(_("Language to use for the spell check:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3);
+
+	combo = gtk_combo_box_new_text();
+
+	for (i = 0; i < sc->dicts->len; i++)
+	{
+		gtk_combo_box_append_text(GTK_COMBO_BOX(combo), g_ptr_array_index(sc->dicts, i));
+
+		if (p_utils->str_equal(g_ptr_array_index(sc->dicts, i), sc->default_language))
+			gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
+	}
+	/* if the default language couldn't be selected, select the first available language */
+	if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) == -1)
+		gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
+
+	if (sc->dicts->len > 20)
+		gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 3);
+	else if (sc->dicts->len > 10)
+		gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 2);
+	gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 6);
+
+	g_object_set_data(G_OBJECT(dialog), "combo", combo);
+	g_object_set_data(G_OBJECT(dialog), "check_type", check_type);
+	g_object_set_data(G_OBJECT(dialog), "check_msgwin", check_msgwin);
+	g_object_set_data(G_OBJECT(dialog), "check_toolbar", check_toolbar);
+	g_signal_connect(dialog, "response", G_CALLBACK(configure_response_cb), NULL);
+
+	gtk_widget_show_all(vbox);
+
+	return vbox;
+}
+
+
+void plugin_cleanup(void)
+{
+	guint i;
+	for (i = 0; i < MAX_MENU_SUGGESTIONS; i++)
+	{
+		clickinfo.suggs[i] = NULL;
+	}
+	g_free(clickinfo.word);
+	for (i = 0; i < sc->dicts->len; i++)
+	{
+		g_free(g_ptr_array_index(sc->dicts, i));
+	}
+	g_ptr_array_free(sc->dicts, TRUE);
+
+	g_signal_handler_disconnect(geany->main_widgets->window, sc->signal_id);
+
+	gtk_widget_destroy(sc->edit_menu);
+	gtk_widget_destroy(sc->edit_menu_sep);
+	if (sc->toolbar_button != NULL)
+		gtk_widget_destroy(GTK_WIDGET(sc->toolbar_button));
+
+	speller_free();
+
+	g_free(sc->default_language);
+	g_free(sc->config_file);
+	gtk_widget_destroy(sc->menu_item);
+	g_free(sc);
+}


Property changes on: trunk/spellcheck/src/scplugin.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Added: trunk/spellcheck/src/scplugin.h
===================================================================
--- trunk/spellcheck/src/scplugin.h	                        (rev 0)
+++ trunk/spellcheck/src/scplugin.h	2008-10-17 15:20:12 UTC (rev 212)
@@ -0,0 +1,67 @@
+/*
+ *      scplugin.h - this file is part of Spellcheck, a Geany plugin
+ *
+ *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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 Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+#ifndef SC_PLUGIN_H
+#define SC_PLUGIN_H 1
+
+
+
+typedef struct
+{
+	gchar *config_file;
+	gchar *default_language;
+	gboolean use_msgwin;
+	gboolean check_while_typing;
+	gboolean show_toolbar_item;
+	gulong signal_id;
+	GPtrArray *dicts;
+	GtkWidget *menu_item;
+	GtkWidget *edit_menu;
+	GtkWidget *edit_menu_sep;
+	GtkWidget *edit_menu_sub;
+	GtkToolItem *toolbar_button;
+} SpellCheck;
+
+
+#define MAX_MENU_SUGGESTIONS 10
+
+typedef struct
+{
+	gint pos;
+	GeanyDocument *doc;
+	/* static array to keep suggestions for use as callback user data for the editing menu items */
+	gchar *suggs[MAX_MENU_SUGGESTIONS];
+	/* static storage for the misspelled word under the cursor when using the editing menu */
+	gchar *word;
+} SpellClickInfo;
+
+
+extern SpellCheck *sc;
+extern SpellClickInfo clickinfo;
+extern GeanyPlugin		*geany_plugin;
+extern GeanyData		*geany_data;
+extern GeanyFunctions	*geany_functions;
+
+#endif


Property changes on: trunk/spellcheck/src/scplugin.h
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Deleted: trunk/spellcheck/src/spellcheck.c
===================================================================
--- trunk/spellcheck/src/spellcheck.c	2008-10-16 16:21:41 UTC (rev 211)
+++ trunk/spellcheck/src/spellcheck.c	2008-10-17 15:20:12 UTC (rev 212)
@@ -1,934 +0,0 @@
-/*
- *      spellcheck.c - this file is part of Geany, a fast and lightweight IDE
- *
- *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
- *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
- *
- *      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 Street, Fifth Floor, Boston,
- *      MA 02110-1301, USA.
- *
- * $Id$
- */
-
-
-#include "geany.h"
-#include "support.h"
-
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-#ifdef G_OS_WIN32
-# include <windows.h>
-#endif
-
-#include <string.h>
-#include <ctype.h>
-#include <enchant.h>
-
-#include "plugindata.h"
-
-#include "document.h"
-#include "editor.h"
-#include "msgwindow.h"
-#include "keybindings.h"
-#include "utils.h"
-#include "ui_utils.h"
-
-#include "pluginmacros.h"
-
-
-GeanyPlugin		*geany_plugin;
-GeanyData		*geany_data;
-GeanyFunctions	*geany_functions;
-
-
-PLUGIN_VERSION_CHECK(100)
-PLUGIN_SET_INFO(_("Spell Check"), _("Checks the spelling of the current document."), "0.2",
-			_("The Geany developer team"))
-
-
-typedef struct
-{
-	gchar *config_file;
-	gchar *default_language;
-	gboolean use_msgwin;
-	gboolean check_while_typing;
-	gboolean show_toolbar_item;
-	gulong signal_id;
-	GPtrArray *dicts;
-	GtkWidget *menu_item;
-	GtkWidget *edit_menu;
-	GtkWidget *edit_menu_sep;
-	GtkWidget *edit_menu_sub;
-	GtkToolItem *toolbar_button;
-	EnchantBroker *broker;
-	EnchantDict *dict;
-} SpellCheck;
-static SpellCheck *sc;
-
-
-#define MAX_MENU_SUGGESTIONS 10
-typedef struct
-{
-	gint pos;
-	GeanyDocument *doc;
-	/* static array to keep suggestions for use as callback user data for the editing menu items */
-	gchar *suggs[MAX_MENU_SUGGESTIONS];
-	/* static storage for the misspelled word under the cursor when using the editing menu */
-	gchar *word;
-} SpellClickInfo;
-static SpellClickInfo clickinfo;
-
-
-/* Flag to indicate that a callback function will be triggered by generating the appropriate event
- * but the callback should be ignored. */
-static gboolean ignore_sc_callback = FALSE;
-
-
-static void on_update_editor_menu(GObject *obj, const gchar *word, gint pos,
-								  GeanyDocument *doc, gpointer user_data);
-
-/* Keybinding(s) */
-enum
-{
-	KB_SPELL_CHECK,
-	KB_COUNT
-};
-PLUGIN_KEY_GROUP(spellcheck, KB_COUNT)
-
-
-
-PluginCallback plugin_callbacks[] =
-{
-    { "update-editor-menu", (GCallback) &on_update_editor_menu, FALSE, NULL },
-    { NULL, NULL, FALSE, NULL }
-};
-
-
-/* currently unused */
-#ifdef G_OS_WIN32
-#warning TODO check Windows support
-/* On Windows we need to find the Aspell installation prefix via the Windows Registry
- * and then set the prefix in the Aspell config object. */
-static void set_up_aspell_prefix(AspellConfig *config)
-{
-	char sTemp[1024];
-	HKEY hkey;
-	DWORD len = sizeof(sTemp);
-
-	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Aspell"), 0,
-			KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
-		return;
-
-	if (RegQueryValueEx(hkey, NULL, 0, NULL, (LPBYTE)sTemp, &len) == ERROR_SUCCESS)
-		aspell_config_replace(config, "prefix", sTemp);
-
-	RegCloseKey(hkey);
-}
-#endif
-
-
-static void toolbar_item_toggled_cb(GtkToggleToolButton *button, gpointer user_data)
-{
-	if (ignore_sc_callback)
-		return;
-
-	sc->check_while_typing = gtk_toggle_tool_button_get_active(button);
-
-	p_ui->set_statusbar(FALSE, _("Spell checking while typing is now %s"),
-		(sc->check_while_typing) ? _("enabled") : _("disabled"));
-}
-
-
-static void toolbar_update(void)
-{
-	/* toolbar item is not requested, so remove the item if it exists */
-	if (! sc->show_toolbar_item)
-	{
-		if (sc->toolbar_button != NULL)
-		{
-			gtk_widget_destroy(GTK_WIDGET(sc->toolbar_button));
-			sc->toolbar_button = NULL;
-		}
-	}
-	else
-	{
-		if (sc->toolbar_button == NULL)
-		{
-			sc->toolbar_button = gtk_toggle_tool_button_new_from_stock("gtk-spell-check");
-	#if GTK_CHECK_VERSION(2, 12, 0)
-			gtk_widget_set_tooltip_text(GTK_WIDGET(sc->toolbar_button),
-				_("Toggle spell check while typing."));
-	#endif
-			gtk_widget_show(GTK_WIDGET(sc->toolbar_button));
-			p_plugin->add_toolbar_item(geany_plugin, sc->toolbar_button);
-			p_ui->add_document_sensitive(GTK_WIDGET(sc->toolbar_button));
-
-			g_signal_connect(sc->toolbar_button, "toggled",
-				G_CALLBACK(toolbar_item_toggled_cb), NULL);
-		}
-
-		ignore_sc_callback = TRUE;
-		gtk_toggle_tool_button_set_active(
-			GTK_TOGGLE_TOOL_BUTTON(sc->toolbar_button), sc->check_while_typing);
-		ignore_sc_callback = FALSE;
-	}
-}
-
-
-static void clear_indicators_on_range(GeanyDocument *doc, gint start, gint len)
-{
-	g_return_if_fail(doc != NULL);
-
-	if (len > 0)
-	{
-		p_sci->indicator_clear(doc->editor->sci, start, start + len);
-	}
-}
-
-
-static void clear_indicators_on_line(GeanyDocument *doc, gint line_number)
-{
-	gint start_pos, length;
-
-	g_return_if_fail(doc != NULL);
-
-	start_pos = p_sci->get_position_from_line(doc->editor->sci, line_number);
-	length = p_sci->get_line_length(doc->editor->sci, line_number);
-
-	clear_indicators_on_range(doc, start_pos, length);
-}
-
-
-
-static void on_menu_suggestion_item_activate(GtkMenuItem *menuitem, gpointer gdata)
-{
-	gchar *sugg = gdata;
-	gint startword, endword;
-
-	if (clickinfo.doc == NULL || clickinfo.pos == -1)
-	{
-		g_free(sugg);
-		return;
-	}
-
-	startword = p_sci->send_message(
-		clickinfo.doc->editor->sci, SCI_WORDSTARTPOSITION, clickinfo.pos, 0);
-	endword = p_sci->send_message(
-		clickinfo.doc->editor->sci, SCI_WORDENDPOSITION, clickinfo.pos, 0);
-
-	if (startword != endword)
-	{
-		p_sci->set_selection_start(clickinfo.doc->editor->sci, startword);
-		p_sci->set_selection_end(clickinfo.doc->editor->sci, endword);
-		p_sci->replace_sel(clickinfo.doc->editor->sci, sugg);
-
-		clear_indicators_on_range(clickinfo.doc, startword, endword - startword);
-	}
-}
-
-
-static void on_menu_addword_item_activate(GtkMenuItem *menuitem, gpointer gdata)
-{
-	gint startword, endword;
-
-	if (clickinfo.doc == NULL || clickinfo.word == NULL || clickinfo.pos == -1)
-		return;
-
-	enchant_dict_add_to_pwl(sc->dict, clickinfo.word, -1);
-
-	startword = p_sci->send_message(
-		clickinfo.doc->editor->sci, SCI_WORDSTARTPOSITION, clickinfo.pos, 0);
-	endword = p_sci->send_message(
-		clickinfo.doc->editor->sci, SCI_WORDENDPOSITION, clickinfo.pos, 0);
-	if (startword != endword)
-	{
-		clear_indicators_on_range(clickinfo.doc, startword, endword - startword);
-	}
-}
-
-
-static void on_update_editor_menu(GObject *obj, const gchar *word, gint pos,
-								  GeanyDocument *doc, gpointer user_data)
-{
-	gsize n_suggs, i;
-	gchar **tmp_suggs;
-
-	g_return_if_fail(doc != NULL && doc->is_valid);
-
-	/* hide the submenu in any case, we will reshow it again if we actually found something */
-	gtk_widget_hide(sc->edit_menu);
-	gtk_widget_hide(sc->edit_menu_sep);
-
-	if (! NZV(word) || enchant_dict_check(sc->dict, word, -1) == 0)
-		return;
-
-	tmp_suggs = enchant_dict_suggest(sc->dict, word, -1, &n_suggs);
-
-	if (tmp_suggs != NULL)
-	{
-		GtkWidget *menu_item, *image;
-		gchar *label;
-
-		clickinfo.pos = pos;
-		clickinfo.doc = doc;
-		setptr(clickinfo.word, g_strdup(word));
-
-		if (GTK_IS_WIDGET(sc->edit_menu_sub))
-			gtk_widget_destroy(sc->edit_menu_sub);
-
-		sc->edit_menu_sub = gtk_menu_new();
-		gtk_menu_item_set_submenu(GTK_MENU_ITEM(sc->edit_menu), sc->edit_menu_sub);
-
-		/* TODO do we need more than 10 suggestions? gtkspell offers additional suggestions
-		 * in another sub menu, should we too? */
-		for (i = 0; i < MIN(n_suggs, MAX_MENU_SUGGESTIONS); i++)
-		{
-			/* keep the suggestions in a static array for the callback function */
-			g_free(clickinfo.suggs[i]);
-			clickinfo.suggs[i] = g_strdup(tmp_suggs[i]);
-
-			menu_item = gtk_menu_item_new_with_label(clickinfo.suggs[i]);
-			gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item);
-			g_signal_connect((gpointer) menu_item, "activate",
-				G_CALLBACK(on_menu_suggestion_item_activate), clickinfo.suggs[i]);
-		}
-		menu_item = gtk_separator_menu_item_new();
-		gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item);
-
-		image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
-
-		label = g_strdup_printf(_("Add \"%s\" to Dictionary"), word);
-		menu_item = gtk_image_menu_item_new_with_label(label);
-		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
-		gtk_container_add(GTK_CONTAINER(sc->edit_menu_sub), menu_item);
-		g_signal_connect((gpointer) menu_item, "activate",
-			G_CALLBACK(on_menu_addword_item_activate), NULL);
-
-		gtk_widget_show(sc->edit_menu);
-		gtk_widget_show(sc->edit_menu_sep);
-		gtk_widget_show_all(sc->edit_menu_sub);
-
-		enchant_dict_free_string_list(sc->dict, tmp_suggs);
-		g_free(label);
-	}
-}
-
-
-static void dict_describe(const gchar* const lang, const gchar* const name,
-						  const gchar* const desc, const gchar* const file, void *target)
-{
-	gchar **result = (gchar**) target;
-	*result = g_strdup_printf("\"%s\" (%s)", lang, name);
-}
-
-
-static gint check_word(GeanyDocument *doc, gint line_number, const gchar *word,
-					   gint start_pos, gint end_pos)
-{
-	gsize j;
-	gsize n_suggs = 0;
-	gchar **suggs;
-	GString *str = g_string_sized_new(256);
-
-	/* ignore numbers or words starting with digits */
-	if (isdigit(*word))
-		return 0;
-
-	/* early out if the word is spelled correctly */
-	if (enchant_dict_check(sc->dict, word, -1) == 0)
-		return 0;
-
-	suggs = enchant_dict_suggest(sc->dict, word, -1, &n_suggs);
-
-	if (suggs != NULL)
-	{
-		g_string_append_printf(str, "line %d: %s | ",  line_number + 1, word);
-
-		g_string_append(str, _("Try: "));
-
-		/* Now find the misspellings in the line, limit suggestions to a maximum of 15 (for now) */
-		for (j = 0; j < MIN(n_suggs, 15); j++)
-		{
-			g_string_append(str, suggs[j]);
-			g_string_append_c(str, ' ');
-		}
-
-		if (start_pos == -1)
-			start_pos = end_pos - strlen(word);
-
-		p_editor->set_indicator(doc->editor, start_pos, end_pos);
-		if (sc->use_msgwin)
-			p_msgwindow->msg_add(COLOR_RED, line_number + 1, doc, "%s", str->str);
-
-		if (suggs != NULL && n_suggs)
-			enchant_dict_free_string_list(sc->dict, suggs);
-	}
-	g_string_free(str, TRUE);
-
-	return n_suggs;
-}
-
-
-static gint process_line(GeanyDocument *doc, gint line_number, const gchar *line)
-{
-	gint pos_start, pos_end;
-	gint wstart, wend;
-	GString *str = g_string_sized_new(256);
-	gint suggestions_found = 0;
-	gchar c;
-
-	pos_start = p_sci->get_position_from_line(doc->editor->sci, line_number);
-	/* TODO use SCI_GETLINEENDPOSITION */
-	pos_end = p_sci->get_position_from_line(doc->editor->sci, line_number + 1);
-
-	while (pos_start < pos_end)
-	{
-		wstart = p_sci->send_message(doc->editor->sci, SCI_WORDSTARTPOSITION, pos_start, TRUE);
-		wend = p_sci->send_message(doc->editor->sci, SCI_WORDENDPOSITION, wstart, FALSE);
-		if (wstart == wend)
-			break;
-		c = p_sci->get_char_at(doc->editor->sci, wstart);
-		/* hopefully it's enough to check for these both */
-		if (ispunct(c) || isspace(c))
-		{
-			pos_start++;
-			continue;
-		}
-
-		/* ensure the string has enough allocated memory */
-		if (str->len < (guint)(wend - wstart))
-			g_string_set_size(str, wend - wstart);
-
-		p_sci->get_text_range(doc->editor->sci, wstart, wend, str->str);
-
-		suggestions_found += check_word(doc, line_number, str->str, wstart, wend);
-
-		pos_start = wend + 1;
-	}
-
-	g_string_free(str, TRUE);
-	return suggestions_found;
-}
-
-
-static void check_document(GeanyDocument *doc)
-{
-	gchar *line;
-	gint i;
-	gint first_line, last_line;
-	gchar *dict_string = NULL;
-	gint suggestions_found = 0;
-
-	enchant_dict_describe(sc->dict, dict_describe, &dict_string);
-
-	if (p_sci->has_selection(doc->editor->sci))
-	{
-		first_line = p_sci->get_line_from_position(
-			doc->editor->sci, p_sci->get_selection_start(doc->editor->sci));
-		last_line = p_sci->get_line_from_position(
-			doc->editor->sci, p_sci->get_selection_end(doc->editor->sci));
-
-		if (sc->use_msgwin)
-			p_msgwindow->msg_add(COLOR_BLUE, -1, NULL,
-				_("Checking file \"%s\" (lines %d to %d using %s):"),
-				DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
-		g_message("Checking file \"%s\" (lines %d to %d using %s):",
-			DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
-	}
-	else
-	{
-		first_line = 0;
-		last_line = p_sci->get_line_count(doc->editor->sci);
-		if (sc->use_msgwin)
-			p_msgwindow->msg_add(COLOR_BLUE, -1, NULL, _("Checking file \"%s\" (using %s):"),
-				DOC_FILENAME(doc), dict_string);
-		g_message("Checking file \"%s\" (using %s):", DOC_FILENAME(doc), dict_string);
-	}
-	g_free(dict_string);
-
-	for (i = first_line; i < last_line; i++)
-	{
-		line = p_sci->get_line(doc->editor->sci, i);
-
-		suggestions_found += process_line(doc, i, line);
-
-		g_free(line);
-	}
-
-	if (suggestions_found == 0 && sc->use_msgwin)
-		p_msgwindow->msg_add(COLOR_BLUE, -1, NULL, _("The checked text is spelled correctly."));
-}
-
-
-static void perform_check(GeanyDocument *doc)
-{
-	p_editor->clear_indicators(doc->editor);
-	if (sc->use_msgwin)
-	{
-		p_msgwindow->clear_tab(MSG_MESSAGE);
-		p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
-	}
-
-	check_document(doc);
-}
-
-
-/* Checks only the last word before the current cursor position -> check as you type. */
-static gboolean on_key_release(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
-{
-	gint line_number;
-	GString *str = g_string_sized_new(256);
-	gchar *line;
-	GeanyDocument *doc;
-	static time_t time_prev = 0;
-	time_t time_now = time(NULL);
-	GtkWidget *focusw;
-
-	if (! sc->check_while_typing)
-		return FALSE;
-	/* check only once a second */
-	if (time_now == time_prev)
-		return FALSE;
-	/* set current time for the next key press */
-	time_prev = time_now;
-
-	doc = p_document->get_current();
-	/* bail out if we don't have a document or if we are not in the editor widget */
-	focusw = gtk_window_get_focus(GTK_WINDOW(geany->main_widgets->window));
-	if (doc == NULL || focusw != GTK_WIDGET(doc->editor->sci))
-		return FALSE;
-
-	if (ev->keyval == '\r' &&
-		p_sci->send_message(doc->editor->sci, SCI_GETEOLMODE, 0, 0) == SC_EOL_CRLF)
-	{	/* prevent double line checking */
-		return FALSE;
-	}
-
-	line_number = p_sci->get_current_line(doc->editor->sci);
-	if (ev->keyval == '\n' || ev->keyval == '\r')
-		line_number--; /* check previous line if we start a new one */
-	line = p_sci->get_line(doc->editor->sci, line_number);
-
-	clear_indicators_on_line(doc, line_number);
-	if (process_line(doc, line_number, line) != 0)
-	{
-		if (sc->use_msgwin)
-			p_msgwindow->switch_tab(MSG_MESSAGE, FALSE);
-	}
-
-	g_string_free(str, TRUE);
-	g_free(line);
-
-	return FALSE;
-}
-
-
-static void broker_init_failed(void)
-{
-	const gchar *err = enchant_broker_get_error(sc->broker);
-	p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
-		_("The Enchant library couldn't be initialized (%s)."),
-		(err != NULL) ? err : _("unknown error (maybe the chosen language is not available)"));
-}
-
-
-static void dict_compare(gpointer data, gpointer user_data)
-{
-	gboolean *supported = user_data;
-
-	if (p_utils->str_equal(sc->default_language, data))
-		*supported = TRUE;
-}
-
-
-static gboolean check_default_lang(void)
-{
-	gboolean supported = FALSE;
-
-	g_ptr_array_foreach(sc->dicts, dict_compare, &supported);
-
-	return supported;
-}
-
-
-static void init_enchant_dict(void)
-{
-	gchar *lang = sc->default_language;
-
-	/* Release a previous dict object */
-	if (sc->dict != NULL)
-		enchant_broker_free_dict(sc->broker, sc->dict);
-
-	/* Check if the stored default dictionary is (still) avaiable, fall back to the first
-	 * one in the list if not */
-	if (! check_default_lang())
-	{
-		lang = g_ptr_array_index(sc->dicts, 0);
-		g_warning("Stored language ('%s') could not be loaded. Falling back to '%s'",
-			sc->default_language, lang);
-	}
-
-	/* Request new dict object */
-	sc->dict = enchant_broker_request_dict(sc->broker, lang);
-	if (sc->dict == NULL)
-	{
-		broker_init_failed();
-		gtk_widget_set_sensitive(sc->menu_item, FALSE);
-	}
-	else
-	{
-		gtk_widget_set_sensitive(sc->menu_item, TRUE);
-	}
-}
-
-
-static void on_menu_item_activate(GtkMenuItem *menuitem, gpointer gdata)
-{
-	GeanyDocument *doc;
-
-	if (sc->dict == NULL)
-		return;
-
-	doc = p_document->get_current();
-
-	/* Another language was chosen from the menu item, so make it default for this session. */
-    if (gdata != NULL)
-		setptr(sc->default_language, g_strdup(gdata));
-
-	init_enchant_dict();
-
-	perform_check(doc);
-}
-
-
-static void kb_activate(guint key_id)
-{
-	on_menu_item_activate(NULL, NULL);
-}
-
-
-static void locale_init(void)
-{
-#ifdef ENABLE_NLS
-	gchar *locale_dir = NULL;
-
-#ifdef HAVE_LOCALE_H
-	setlocale(LC_ALL, "");
-#endif
-
-#ifdef G_OS_WIN32
-	gchar *install_dir = g_win32_get_package_installation_directory("geany", NULL);
-	/* e.g. C:\Program Files\geany\lib\locale */
-	locale_dir = g_strconcat(install_dir, "\\share\\locale", NULL);
-	g_free(install_dir);
-#else
-	locale_dir = g_strdup(LOCALEDIR);
-#endif
-
-	bindtextdomain(GETTEXT_PACKAGE, locale_dir);
-	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
-	textdomain(GETTEXT_PACKAGE);
-	g_free(locale_dir);
-#endif
-}
-
-
-static const gchar *get_default_lang(void)
-{
-	const gchar *lang = g_getenv("LANG");
-	if (NZV(lang))
-	{
-		if (g_ascii_strncasecmp(lang, "C", 1) == 0)
-			lang = "en";
-	}
-	else
-		lang = "en";
-
-	return lang;
-}
-
-
-static void add_dict_array(const gchar* const lang_tag, const gchar* const provider_name,
-						   const gchar* const provider_desc, const gchar* const provider_file,
-						   gpointer user_data)
-{
-	guint i;
-	gchar *result = g_strdup(lang_tag);
-
-	/* sometimes dictionaries are named lang-LOCALE instead of lang_LOCALE, so replace the
-	 * hyphen by a dash, enchant seems to not care about it. */
-	for (i = 0; i < strlen(result); i++)
-	{
-		if (result[i] == '-')
-			result[i] = '_';
-	}
-
-	/* find duplicates and skip them */
-	for (i = 0; i < sc->dicts->len; i++)
-	{
-		if (p_utils->str_equal(g_ptr_array_index(sc->dicts, i), result))
-			return;
-	}
-
-	g_ptr_array_add(sc->dicts, result);
-}
-
-
-static void on_configure_response(GtkDialog *dialog, gint response, gpointer user_data)
-{
-	if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
-	{
-		GKeyFile *config = g_key_file_new();
-		gchar *data;
-		gchar *config_dir = g_path_get_dirname(sc->config_file);
-
-		setptr(sc->default_language, gtk_combo_box_get_active_text(GTK_COMBO_BOX(
-			g_object_get_data(G_OBJECT(dialog), "combo"))));
-		init_enchant_dict();
-
-		sc->check_while_typing = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
-			g_object_get_data(G_OBJECT(dialog), "check_type"))));
-
-		sc->use_msgwin = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
-			g_object_get_data(G_OBJECT(dialog), "check_msgwin"))));
-
-		sc->show_toolbar_item = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
-			g_object_get_data(G_OBJECT(dialog), "check_toolbar"))));
-
-		g_key_file_load_from_file(config, sc->config_file, G_KEY_FILE_NONE, NULL);
-		if (sc->default_language != NULL) /* lang may be NULL */
-			g_key_file_set_string(config, "spellcheck", "language", sc->default_language);
-		g_key_file_set_boolean(config, "spellcheck", "check_while_typing", sc->check_while_typing);
-		g_key_file_set_boolean(config, "spellcheck", "use_msgwin", sc->use_msgwin);
-		g_key_file_set_boolean(config, "spellcheck", "show_toolbar_item", sc->show_toolbar_item);
-
-		toolbar_update();
-
-		if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
-		{
-			p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
-				_("Plugin configuration directory could not be created."));
-		}
-		else
-		{
-			/* write config to file */
-			data = g_key_file_to_data(config, NULL, NULL);
-			p_utils->write_file(sc->config_file, data);
-			g_free(data);
-		}
-		g_free(config_dir);
-		g_key_file_free(config);
-	}
-}
-
-
-static gint sort_dicts(gconstpointer a, gconstpointer b)
-{	/* casting mania ;-) */
-	return strcmp((gchar*)((GPtrArray*)a)->pdata, (gchar*)((GPtrArray*)b)->pdata);
-}
-
-
-static void create_dicts_array(void)
-{
-	sc->dicts = g_ptr_array_new();
-
-	enchant_broker_list_dicts(sc->broker, add_dict_array, sc->dicts);
-
-	g_ptr_array_sort(sc->dicts, sort_dicts);
-}
-
-
-static void create_edit_menu(void)
-{
-	sc->edit_menu = gtk_image_menu_item_new_from_stock(GTK_STOCK_SPELL_CHECK, NULL);
-	gtk_container_add(GTK_CONTAINER(geany->main_widgets->editor_menu), sc->edit_menu);
-	gtk_menu_reorder_child(GTK_MENU(geany->main_widgets->editor_menu), sc->edit_menu, 0);
-
-	sc->edit_menu_sep = gtk_separator_menu_item_new();
-	gtk_container_add(GTK_CONTAINER(geany->main_widgets->editor_menu), sc->edit_menu_sep);
-	gtk_menu_reorder_child(GTK_MENU(geany->main_widgets->editor_menu), sc->edit_menu_sep, 1);
-
-	gtk_widget_show_all(sc->edit_menu);
-}
-
-
-static GtkWidget *create_menu(GtkWidget *sp_item)
-{
-	GtkWidget *menu, *subitem;
-	guint i;
-
-	gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), sp_item);
-
-	menu = gtk_menu_new();
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(sp_item), menu);
-
-	subitem = gtk_menu_item_new_with_mnemonic(_("Default"));
-	gtk_container_add(GTK_CONTAINER(menu), subitem);
-	g_signal_connect((gpointer) subitem, "activate", G_CALLBACK(on_menu_item_activate), NULL);
-
-	subitem = gtk_separator_menu_item_new();
-	gtk_container_add(GTK_CONTAINER(menu), subitem);
-
-	for (i = 0; i < sc->dicts->len; i++)
-	{
-		GtkWidget *menu_item;
-
-		menu_item = gtk_menu_item_new_with_label(g_ptr_array_index(sc->dicts, i));
-		gtk_container_add(GTK_CONTAINER(menu), menu_item);
-		g_signal_connect((gpointer) menu_item, "activate",
-			G_CALLBACK(on_menu_item_activate), g_ptr_array_index(sc->dicts, i));
-	}
-
-	return sp_item;
-}
-
-
-void plugin_init(GeanyData *data)
-{
-	GtkWidget *sp_item;
-	GKeyFile *config = g_key_file_new();
-	guint i;
-
-	sc = g_new0(SpellCheck, 1);
-
-	sc->config_file = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
-		"spellcheck", G_DIR_SEPARATOR_S, "spellcheck.conf", NULL);
-
-	g_key_file_load_from_file(config, sc->config_file, G_KEY_FILE_NONE, NULL);
-	sc->default_language = p_utils->get_setting_string(config,
-		"spellcheck", "language", get_default_lang());
-	sc->check_while_typing = p_utils->get_setting_boolean(config,
-		"spellcheck", "check_while_typing", FALSE);
-	sc->show_toolbar_item = p_utils->get_setting_boolean(config,
-		"spellcheck", "show_toolbar_item", TRUE);
-	sc->use_msgwin = p_utils->get_setting_boolean(config, "spellcheck", "use_msgwin", FALSE);
-	g_key_file_free(config);
-
-	locale_init();
-
-	sc->menu_item = gtk_image_menu_item_new_from_stock("gtk-spell-check", NULL);
-	p_ui->add_document_sensitive(sc->menu_item);
-
-	toolbar_update();
-
-	sc->broker = enchant_broker_init();
-	create_dicts_array();
-	init_enchant_dict();
-
-	for (i = 0; i < MAX_MENU_SUGGESTIONS; i++)
-	{
-		clickinfo.suggs[i] = NULL;
-	}
-	clickinfo.word = NULL;
-
-	create_edit_menu();
-	sp_item = create_menu(sc->menu_item);
-	gtk_widget_show_all(sp_item);
-
-	sc->signal_id = g_signal_connect(geany->main_widgets->window,
-		"key-release-event", G_CALLBACK(on_key_release), NULL);
-
-	/* setup keybindings */
-	p_keybindings->set_item(plugin_key_group, KB_SPELL_CHECK, kb_activate,
-		0, 0, "spell_check", _("Run Spell Check"), NULL);
-}
-
-
-GtkWidget *plugin_configure(GtkDialog *dialog)
-{
-	GtkWidget *label, *vbox, *combo, *check_type, *check_msgwin, *check_toolbar;
-	guint i;
-
-	vbox = gtk_vbox_new(FALSE, 6);
-
-	check_type = gtk_check_button_new_with_label(_("Check spelling while typing"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_type), sc->check_while_typing);
-	gtk_box_pack_start(GTK_BOX(vbox), check_type, FALSE, FALSE, 6);
-
-	check_toolbar = gtk_check_button_new_with_label(_("Show toolbar item to toggle spell checking"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_toolbar), sc->show_toolbar_item);
-	gtk_box_pack_start(GTK_BOX(vbox), check_toolbar, FALSE, FALSE, 3);
-
-	check_msgwin = gtk_check_button_new_with_label(
-		_("Print misspelled words and suggestions in the messages window"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_msgwin), sc->use_msgwin);
-	gtk_box_pack_start(GTK_BOX(vbox), check_msgwin, FALSE, FALSE, 3);
-
-	label = gtk_label_new(_("Language to use for the spell check:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3);
-
-	combo = gtk_combo_box_new_text();
-
-	for (i = 0; i < sc->dicts->len; i++)
-	{
-		gtk_combo_box_append_text(GTK_COMBO_BOX(combo), g_ptr_array_index(sc->dicts, i));
-
-		if (p_utils->str_equal(g_ptr_array_index(sc->dicts, i), sc->default_language))
-			gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);
-	}
-	/* if the default language couldn't be selected, select the first available language */
-	if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) == -1)
-		gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
-
-	if (sc->dicts->len > 20)
-		gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 3);
-	else if (sc->dicts->len > 10)
-		gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 2);
-	gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 6);
-
-	g_object_set_data(G_OBJECT(dialog), "combo", combo);
-	g_object_set_data(G_OBJECT(dialog), "check_type", check_type);
-	g_object_set_data(G_OBJECT(dialog), "check_msgwin", check_msgwin);
-	g_object_set_data(G_OBJECT(dialog), "check_toolbar", check_toolbar);
-	g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
-
-	gtk_widget_show_all(vbox);
-
-	return vbox;
-}
-
-
-void plugin_cleanup(void)
-{
-	guint i;
-	for (i = 0; i < MAX_MENU_SUGGESTIONS; i++)
-	{
-		clickinfo.suggs[i] = NULL;
-	}
-	g_free(clickinfo.word);
-	for (i = 0; i < sc->dicts->len; i++)
-	{
-		g_free(g_ptr_array_index(sc->dicts, i));
-	}
-	g_ptr_array_free(sc->dicts, TRUE);
-
-	g_signal_handler_disconnect(geany->main_widgets->window, sc->signal_id);
-
-	gtk_widget_destroy(sc->edit_menu);
-	gtk_widget_destroy(sc->edit_menu_sep);
-	if (sc->toolbar_button != NULL)
-		gtk_widget_destroy(GTK_WIDGET(sc->toolbar_button));
-
-	enchant_broker_free_dict(sc->broker, sc->dict);
-	enchant_broker_free(sc->broker);
-
-	g_free(sc->default_language);
-	g_free(sc->config_file);
-	gtk_widget_destroy(sc->menu_item);
-	g_free(sc);
-}

Added: trunk/spellcheck/src/speller.c
===================================================================
--- trunk/spellcheck/src/speller.c	                        (rev 0)
+++ trunk/spellcheck/src/speller.c	2008-10-17 15:20:12 UTC (rev 212)
@@ -0,0 +1,352 @@
+/*
+ *      speller.c - this file is part of Spellcheck, a Geany plugin
+ *
+ *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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 Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+#include "geany.h"
+#include "support.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <enchant.h>
+
+#include "plugindata.h"
+
+#include "document.h"
+#include "editor.h"
+#include "msgwindow.h"
+#include "utils.h"
+
+#include "pluginmacros.h"
+
+#include "speller.h"
+#include "scplugin.h"
+
+
+
+static EnchantBroker *speller_broker = NULL;
+static EnchantDict *speller_dict = NULL;
+
+
+
+static void dict_describe(const gchar* const lang, const gchar* const name,
+						  const gchar* const desc, const gchar* const file, void *target)
+{
+	gchar **result = (gchar**) target;
+	*result = g_strdup_printf("\"%s\" (%s)", lang, name);
+}
+
+
+gint speller_check_word(GeanyDocument *doc, gint line_number, const gchar *word,
+					    gint start_pos, gint end_pos)
+{
+	gsize j;
+	gsize n_suggs = 0;
+	gchar **suggs;
+	GString *str = g_string_sized_new(256);
+
+	/* ignore numbers or words starting with digits */
+	if (isdigit(*word))
+		return 0;
+
+	/* early out if the word is spelled correctly */
+	if (enchant_dict_check(speller_dict, word, -1) == 0)
+		return 0;
+
+	suggs = enchant_dict_suggest(speller_dict, word, -1, &n_suggs);
+
+	if (suggs != NULL)
+	{
+		g_string_append_printf(str, "line %d: %s | ",  line_number + 1, word);
+
+		g_string_append(str, _("Try: "));
+
+		/* Now find the misspellings in the line, limit suggestions to a maximum of 15 (for now) */
+		for (j = 0; j < MIN(n_suggs, 15); j++)
+		{
+			g_string_append(str, suggs[j]);
+			g_string_append_c(str, ' ');
+		}
+
+		if (start_pos == -1)
+			start_pos = end_pos - strlen(word);
+
+		p_editor->set_indicator(doc->editor, start_pos, end_pos);
+		if (sc->use_msgwin)
+			p_msgwindow->msg_add(COLOR_RED, line_number + 1, doc, "%s", str->str);
+
+		if (suggs != NULL && n_suggs)
+			enchant_dict_free_string_list(speller_dict, suggs);
+	}
+	g_string_free(str, TRUE);
+
+	return n_suggs;
+}
+
+
+gint speller_process_line(GeanyDocument *doc, gint line_number, const gchar *line)
+{
+	gint pos_start, pos_end;
+	gint wstart, wend;
+	GString *str = g_string_sized_new(256);
+	gint suggestions_found = 0;
+	gchar c;
+
+	pos_start = p_sci->get_position_from_line(doc->editor->sci, line_number);
+	/* TODO use SCI_GETLINEENDPOSITION */
+	pos_end = p_sci->get_position_from_line(doc->editor->sci, line_number + 1);
+
+	while (pos_start < pos_end)
+	{
+		wstart = p_sci->send_message(doc->editor->sci, SCI_WORDSTARTPOSITION, pos_start, TRUE);
+		wend = p_sci->send_message(doc->editor->sci, SCI_WORDENDPOSITION, wstart, FALSE);
+		if (wstart == wend)
+			break;
+		c = p_sci->get_char_at(doc->editor->sci, wstart);
+		/* hopefully it's enough to check for these both */
+		if (ispunct(c) || isspace(c))
+		{
+			pos_start++;
+			continue;
+		}
+
+		/* ensure the string has enough allocated memory */
+		if (str->len < (guint)(wend - wstart))
+			g_string_set_size(str, wend - wstart);
+
+		p_sci->get_text_range(doc->editor->sci, wstart, wend, str->str);
+
+		suggestions_found += speller_check_word(doc, line_number, str->str, wstart, wend);
+
+		pos_start = wend + 1;
+	}
+
+	g_string_free(str, TRUE);
+	return suggestions_found;
+}
+
+
+void speller_check_document(GeanyDocument *doc)
+{
+	gchar *line;
+	gint i;
+	gint first_line, last_line;
+	gchar *dict_string = NULL;
+	gint suggestions_found = 0;
+
+	enchant_dict_describe(speller_dict, dict_describe, &dict_string);
+
+	if (p_sci->has_selection(doc->editor->sci))
+	{
+		first_line = p_sci->get_line_from_position(
+			doc->editor->sci, p_sci->get_selection_start(doc->editor->sci));
+		last_line = p_sci->get_line_from_position(
+			doc->editor->sci, p_sci->get_selection_end(doc->editor->sci));
+
+		if (sc->use_msgwin)
+			p_msgwindow->msg_add(COLOR_BLUE, -1, NULL,
+				_("Checking file \"%s\" (lines %d to %d using %s):"),
+				DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
+		g_message("Checking file \"%s\" (lines %d to %d using %s):",
+			DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string);
+	}
+	else
+	{
+		first_line = 0;
+		last_line = p_sci->get_line_count(doc->editor->sci);
+		if (sc->use_msgwin)
+			p_msgwindow->msg_add(COLOR_BLUE, -1, NULL, _("Checking file \"%s\" (using %s):"),
+				DOC_FILENAME(doc), dict_string);
+		g_message("Checking file \"%s\" (using %s):", DOC_FILENAME(doc), dict_string);
+	}
+	g_free(dict_string);
+
+	for (i = first_line; i < last_line; i++)
+	{
+		line = p_sci->get_line(doc->editor->sci, i);
+
+		suggestions_found += speller_process_line(doc, i, line);
+
+		g_free(line);
+	}
+
+	if (suggestions_found == 0 && sc->use_msgwin)
+		p_msgwindow->msg_add(COLOR_BLUE, -1, NULL, _("The checked text is spelled correctly."));
+}
+
+
+static void broker_init_failed(void)
+{
+	const gchar *err = enchant_broker_get_error(speller_broker);
+	p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
+		_("The Enchant library couldn't be initialized (%s)."),
+		(err != NULL) ? err : _("unknown error (maybe the chosen language is not available)"));
+}
+
+
+static void dict_compare(gpointer data, gpointer user_data)
+{
+	gboolean *supported = user_data;
+
+	if (p_utils->str_equal(sc->default_language, data))
+		*supported = TRUE;
+}
+
+
+static gboolean check_default_lang(void)
+{
+	gboolean supported = FALSE;
+
+	g_ptr_array_foreach(sc->dicts, dict_compare, &supported);
+
+	return supported;
+}
+
+
+void speller_reinit_enchant_dict(void)
+{
+	gchar *lang = sc->default_language;
+
+	/* Release a previous dict object */
+	if (speller_dict != NULL)
+		enchant_broker_free_dict(speller_broker, speller_dict);
+
+	/* Check if the stored default dictionary is (still) avaiable, fall back to the first
+	 * one in the list if not */
+	if (! check_default_lang())
+	{
+		lang = g_ptr_array_index(sc->dicts, 0);
+		g_warning("Stored language ('%s') could not be loaded. Falling back to '%s'",
+			sc->default_language, lang);
+	}
+
+	/* Request new dict object */
+	speller_dict = enchant_broker_request_dict(speller_broker, lang);
+	if (speller_dict == NULL)
+	{
+		broker_init_failed();
+		gtk_widget_set_sensitive(sc->menu_item, FALSE);
+	}
+	else
+	{
+		gtk_widget_set_sensitive(sc->menu_item, TRUE);
+	}
+}
+
+
+const gchar *speller_get_default_lang(void)
+{
+	const gchar *lang = g_getenv("LANG");
+	if (NZV(lang))
+	{
+		if (g_ascii_strncasecmp(lang, "C", 1) == 0)
+			lang = "en";
+	}
+	else
+		lang = "en";
+
+	return lang;
+}
+
+
+static void add_dict_array(const gchar* const lang_tag, const gchar* const provider_name,
+						   const gchar* const provider_desc, const gchar* const provider_file,
+						   gpointer user_data)
+{
+	guint i;
+	gchar *result = g_strdup(lang_tag);
+
+	/* sometimes dictionaries are named lang-LOCALE instead of lang_LOCALE, so replace the
+	 * hyphen by a dash, enchant seems to not care about it. */
+	for (i = 0; i < strlen(result); i++)
+	{
+		if (result[i] == '-')
+			result[i] = '_';
+	}
+
+	/* find duplicates and skip them */
+	for (i = 0; i < sc->dicts->len; i++)
+	{
+		if (p_utils->str_equal(g_ptr_array_index(sc->dicts, i), result))
+			return;
+	}
+
+	g_ptr_array_add(sc->dicts, result);
+}
+
+
+static gint sort_dicts(gconstpointer a, gconstpointer b)
+{	/* casting mania ;-) */
+	return strcmp((gchar*)((GPtrArray*)a)->pdata, (gchar*)((GPtrArray*)b)->pdata);
+}
+
+
+static void create_dicts_array(void)
+{
+	sc->dicts = g_ptr_array_new();
+
+	enchant_broker_list_dicts(speller_broker, add_dict_array, sc->dicts);
+
+	g_ptr_array_sort(sc->dicts, sort_dicts);
+}
+
+
+void speller_dict_free_string_list(gchar **tmp_suggs)
+{
+	enchant_dict_free_string_list(speller_dict, tmp_suggs);
+}
+
+
+void speller_add_word(const gchar *word)
+{
+	enchant_dict_add_to_pwl(speller_dict, clickinfo.word, -1);
+
+}
+
+gboolean speller_dict_check(const gchar *word)
+{
+	return enchant_dict_check(speller_dict, word, -1);
+}
+
+
+gchar **speller_dict_suggest(const gchar *word, gsize *n_suggs)
+{
+	return enchant_dict_suggest(speller_dict, word, -1, n_suggs);
+}
+
+
+void speller_init(void)
+{
+	speller_broker = enchant_broker_init();
+
+	create_dicts_array();
+
+	speller_reinit_enchant_dict();
+}
+
+
+void speller_free(void)
+{
+	enchant_broker_free_dict(speller_broker, speller_dict);
+	enchant_broker_free(speller_broker);
+}


Property changes on: trunk/spellcheck/src/speller.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Added: trunk/spellcheck/src/speller.h
===================================================================
--- trunk/spellcheck/src/speller.h	                        (rev 0)
+++ trunk/spellcheck/src/speller.h	2008-10-17 15:20:12 UTC (rev 212)
@@ -0,0 +1,53 @@
+/*
+ *      speller.h - this file is part of Spellcheck, a Geany plugin
+ *
+ *      Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2008 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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 Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+#ifndef SC_SPELLER_H
+#define SC_SPELLER_H 1
+
+
+gint speller_check_word(GeanyDocument *doc, gint line_number, const gchar *word,
+					    gint start_pos, gint end_pos);
+
+gint speller_process_line(GeanyDocument *doc, gint line_number, const gchar *line);
+
+void speller_check_document(GeanyDocument *doc);
+
+void speller_reinit_enchant_dict(void);
+
+const gchar *speller_get_default_lang(void);
+
+void speller_dict_free_string_list(gchar **tmp_suggs);
+
+void speller_add_word(const gchar *word);
+
+gboolean speller_dict_check(const gchar *word);
+
+gchar **speller_dict_suggest(const gchar *word, gsize *n_suggs);
+
+void speller_init(void);
+
+void speller_free(void);
+
+#endif


Property changes on: trunk/spellcheck/src/speller.h
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Plugins-Commits mailing list