spell-plugin: Port to gspell

This commit is contained in:
JosephMcc 2018-02-08 23:26:23 -08:00
parent 19354f86c1
commit bd32e81f13
19 changed files with 365 additions and 4924 deletions

View File

@ -94,49 +94,25 @@ dnl ================================================================
dnl spell plugins checks: enchant and iso-codes
dnl ================================================================
ENCHANT_REQUIRED=1.6.0
ISO_CODES_REQUIRED=0.35
GSPELL_REQUIRED=0.2.5
AC_ARG_ENABLE([spell],
AS_HELP_STRING([--disable-spell],[Disable spell plugin (default: enabled)]),
[enable_enchant=$enableval],
[enable_enchant=yes])
[enable_spell=$enableval],
[enable_spell=yes])
if test "x$enable_enchant" = "xyes" ; then
if test "x$enable_spell" = "xyes" ; then
PKG_CHECK_MODULES(ENCHANT, enchant >= $ENCHANT_REQUIRED, \
have_enchant=yes, have_enchant=no)
PKG_CHECK_MODULES(GSPELL, gspell-1 >= $GSPELL_REQUIRED, \
have_gspell=yes, have_gspell=no)
if test "x$have_enchant" = "xyes"; then
PKG_CHECK_EXISTS([iso-codes >= $ISO_CODES_REQUIRED],
[have_iso_codes=yes],[have_iso_codes=no])
if test "x$have_iso_codes" = "xyes"; then
AC_MSG_CHECKING([whether iso-codes has iso-639 and iso-3166 domains])
if $PKG_CONFIG --variable=domains iso-codes | grep 639 > /dev/null && \
$PKG_CONFIG --variable=domains iso-codes | grep 3166 > /dev/null ; then
result=yes
else
result=no
have_iso_codes=no
fi
AC_MSG_RESULT([$result])
fi
if test "x$have_iso_codes" = "xyes"; then
AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix])
AC_DEFINE([HAVE_ISO_CODES],[1],[Define if you have the iso-codes package])
else
AC_MSG_ERROR([iso-codes is required to build the spell plugin. Use --disable-spell to build without spell plugin.])
fi
else
enable_enchant=no
AC_MSG_ERROR([Enchant library not found or too old. Use --disable-spell to build without spell plugin.])
if test "x$have_gspell" = "xno"; then
enable_spell=no
AC_MSG_ERROR([gspell library not found or too old. Use --disable-spell to build without spell plugin.])
fi
fi
AM_CONDITIONAL(ENABLE_ENCHANT, test x"$enable_enchant" = "xyes")
AM_CONDITIONAL(ENABLE_SPELL, test x"$enable_spell" = "xyes")
dnl ================================================================
dnl Start of pkg-config checks
@ -255,7 +231,7 @@ Configuration:
Source code location: ${srcdir}
Compiler: ${CC}
Spell Plugin enabled: $enable_enchant
Spell Plugin enabled: $enable_spell
Gvfs metadata enabled: $enable_gvfs_metadata
GObject Introspection: ${enable_introspection}
"

3
debian/control vendored
View File

@ -7,10 +7,9 @@ Build-Depends: autotools-dev,
gobject-introspection,
gtk-doc-tools,
intltool,
iso-codes,
libenchant-dev,
libgirepository1.0-dev,
libglib2.0-dev,
libgspell-1-dev,
libgtk-3-dev,
libgtksourceview-3.0-dev,
libpeas-dev,

View File

@ -19,7 +19,7 @@ SUBDIRS = \
time \
trailsave
if ENABLE_ENCHANT
if ENABLE_SPELL
SUBDIRS += spell
endif

View File

@ -4,7 +4,7 @@ plugindir = $(XED_PLUGINS_LIBS_DIR)
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(XED_CFLAGS) \
$(ENCHANT_CFLAGS) \
$(GSPELL_CFLAGS) \
$(WARN_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS)
@ -17,25 +17,13 @@ plugin_LTLIBRARIES = libspell.la
libspell_la_SOURCES = \
xed-spell-plugin.c \
xed-spell-plugin.h \
xed-spell-checker.c \
xed-spell-checker.h \
xed-spell-checker-dialog.c \
xed-spell-checker-dialog.h \
xed-spell-checker-language.c \
xed-spell-checker-language.h \
xed-spell-language-dialog.c \
xed-spell-language-dialog.h \
xed-automatic-spell-checker.c \
xed-automatic-spell-checker.h \
xed-spell-utils.c \
xed-spell-utils.h \
$(BUILT_SOURCES)
libspell_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
libspell_la_LIBADD = $(XED_LIBS) $(ENCHANT_LIBS)
libspell_la_LIBADD = $(XED_LIBS) $(GSPELL_LIBS)
uidir = $(XED_PLUGINS_DATA_DIR)/spell
ui_DATA = spell-checker.ui languages-dialog.ui xed-spell-setup-dialog.ui
ui_DATA = xed-spell-setup-dialog.ui
xed-spell-marshal.h: xed-spell-marshal.list $(GLIB_GENMARSHAL)
$(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=xed_marshal > $@

View File

@ -1,140 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!--*- mode: xml -*-->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Set language</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="helpbutton1">
<property name="label">gtk-help</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="closebutton1">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="content">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="border_width">5</property>
<property name="orientation">vertical</property>
<property name="spacing">11</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Select the _language of the current document.</property>
<property name="use_underline">True</property>
<property name="wrap">True</property>
<property name="mnemonic_widget">languages_treeview</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="height_request">180</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">etched-in</property>
<child>
<object class="GtkTreeView" id="languages_treeview">
<property name="height_request">180</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-11">helpbutton1</action-widget>
<action-widget response="-6">closebutton1</action-widget>
<action-widget response="-5">button1</action-widget>
</action-widgets>
</object>
</interface>

View File

@ -1,369 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="check_spelling_window">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="startup_id">Check spelling</property>
<child>
<object class="GtkBox" id="content">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Misspelled word:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="misspelled_word_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">word</property>
<property name="use_markup">True</property>
<property name="justify">center</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Change _to:</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="spacing">12</property>
<child>
<object class="GtkEntry" id="word_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="check_word_button">
<property name="label" translatable="yes">Check _Word</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Suggestions:</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="suggestions_list">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">6</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkGrid" id="grid3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">12</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkButton" id="ignore_button">
<property name="label" translatable="yes">_Ignore</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ignore_all_button">
<property name="label" translatable="yes">Ignore _All</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="change_button">
<property name="label" translatable="yes">Cha_nge</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="change_all_button">
<property name="label" translatable="yes">Change A_ll</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">11</property>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">User dictionary:</property>
<property name="use_markup">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="add_word_button">
<property name="label" translatable="yes">Add w_ord</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Language:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="language_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Language</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="close_button">
<property name="label" translatable="yes">_Close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">end</property>
<property name="use_underline">True</property>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -1,967 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-automatic-spell-checker.c
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
/* This is a modified version of gtkspell 2.0.5 (gtkspell.sf.net) */
/* gtkspell - a spell-checking addon for GTK's TextView widget
* Copyright (c) 2002 Evan Martin.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <glib/gi18n.h>
#include "xed-automatic-spell-checker.h"
#include "xed-spell-utils.h"
struct _XedAutomaticSpellChecker
{
XedDocument *doc;
GSList *views;
GtkTextMark *mark_insert_start;
GtkTextMark *mark_insert_end;
gboolean deferred_check;
GtkTextTag *tag_highlight;
GtkTextMark *mark_click;
XedSpellChecker *spell_checker;
};
static GQuark automatic_spell_checker_id = 0;
static GQuark suggestion_id = 0;
static void xed_automatic_spell_checker_free_internal (XedAutomaticSpellChecker *spell);
static void
view_destroy (XedView *view,
XedAutomaticSpellChecker *spell)
{
xed_automatic_spell_checker_detach_view (spell, view);
}
static void
check_word (XedAutomaticSpellChecker *spell,
GtkTextIter *start,
GtkTextIter *end)
{
gchar *word;
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), start, end, FALSE);
/*
g_print ("Check word: %s [%d - %d]\n", word, gtk_text_iter_get_offset (start),
gtk_text_iter_get_offset (end));
*/
if (!xed_spell_checker_check_word (spell->spell_checker, word, -1))
{
/*
g_print ("Apply tag: [%d - %d]\n", gtk_text_iter_get_offset (start),
gtk_text_iter_get_offset (end));
*/
gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (spell->doc), spell->tag_highlight, start, end);
}
g_free (word);
}
static void
check_range (XedAutomaticSpellChecker *spell,
GtkTextIter start,
GtkTextIter end,
gboolean force_all)
{
/* we need to "split" on word boundaries.
* luckily, Pango knows what "words" are
* so we don't have to figure it out. */
GtkTextIter wstart;
GtkTextIter wend;
GtkTextIter cursor;
GtkTextIter precursor;
gboolean highlight;
/*
g_print ("Check range: [%d - %d]\n", gtk_text_iter_get_offset (&start),
gtk_text_iter_get_offset (&end));
*/
if (gtk_text_iter_inside_word (&end))
{
gtk_text_iter_forward_word_end (&end);
}
if (!gtk_text_iter_starts_word (&start))
{
if (gtk_text_iter_inside_word (&start) || gtk_text_iter_ends_word (&start))
{
gtk_text_iter_backward_word_start (&start);
}
else
{
/* if we're neither at the beginning nor inside a word,
* me must be in some spaces.
* skip forward to the beginning of the next word. */
if (gtk_text_iter_forward_word_end (&start))
{
gtk_text_iter_backward_word_start (&start);
}
}
}
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc),
&cursor,
gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (spell->doc)));
precursor = cursor;
gtk_text_iter_backward_char (&precursor);
highlight = gtk_text_iter_has_tag (&cursor, spell->tag_highlight) ||
gtk_text_iter_has_tag (&precursor, spell->tag_highlight);
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), spell->tag_highlight, &start, &end);
/* Fix a corner case when replacement occurs at beginning of buffer:
* An iter at offset 0 seems to always be inside a word,
* even if it's not. Possibly a pango bug.
*/
if (gtk_text_iter_get_offset (&start) == 0)
{
gtk_text_iter_forward_word_end(&start);
gtk_text_iter_backward_word_start(&start);
}
wstart = start;
while (xed_spell_utils_skip_no_spell_check (&wstart, &end) && gtk_text_iter_compare (&wstart, &end) < 0)
{
gboolean inword;
/* move wend to the end of the current word. */
wend = wstart;
gtk_text_iter_forward_word_end (&wend);
inword = (gtk_text_iter_compare (&wstart, &cursor) < 0) && (gtk_text_iter_compare (&cursor, &wend) <= 0);
if (inword && !force_all)
{
/* this word is being actively edited,
* only check if it's already highligted,
* otherwise defer this check until later. */
if (highlight)
{
check_word (spell, &wstart, &wend);
}
else
{
spell->deferred_check = TRUE;
}
}
else
{
check_word (spell, &wstart, &wend);
spell->deferred_check = FALSE;
}
/* now move wend to the beginning of the next word, */
gtk_text_iter_forward_word_end (&wend);
gtk_text_iter_backward_word_start (&wend);
/* make sure we've actually advanced
* (we don't advance in some corner cases), */
if (gtk_text_iter_equal (&wstart, &wend))
{
break; /* we're done in these cases.. */
}
/* and then pick this as the new next word beginning. */
wstart = wend;
}
}
static void
check_deferred_range (XedAutomaticSpellChecker *spell,
gboolean force_all)
{
GtkTextIter start, end;
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), &start, spell->mark_insert_start);
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), &end, spell->mark_insert_end);
check_range (spell, start, end, force_all);
}
/* insertion works like this:
* - before the text is inserted, we mark the position in the buffer.
* - after the text is inserted, we see where our mark is and use that and
* the current position to check the entire range of inserted text.
*
* this may be overkill for the common case (inserting one character). */
static void
insert_text_before (GtkTextBuffer *buffer,
GtkTextIter *iter,
gchar *text,
gint len,
XedAutomaticSpellChecker *spell)
{
gtk_text_buffer_move_mark (buffer, spell->mark_insert_start, iter);
}
static void
insert_text_after (GtkTextBuffer *buffer,
GtkTextIter *iter,
gchar *text,
gint len,
XedAutomaticSpellChecker *spell)
{
GtkTextIter start;
/* we need to check a range of text. */
gtk_text_buffer_get_iter_at_mark (buffer, &start, spell->mark_insert_start);
check_range (spell, start, *iter, FALSE);
gtk_text_buffer_move_mark (buffer, spell->mark_insert_end, iter);
}
/* deleting is more simple: we're given the range of deleted text.
* after deletion, the start and end iters should be at the same position
* (because all of the text between them was deleted!).
* this means we only really check the words immediately bounding the
* deletion.
*/
static void
delete_range_after (GtkTextBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end,
XedAutomaticSpellChecker *spell)
{
check_range (spell, *start, *end, FALSE);
}
static void
mark_set (GtkTextBuffer *buffer,
GtkTextIter *iter,
GtkTextMark *mark,
XedAutomaticSpellChecker *spell)
{
/* if the cursor has moved and there is a deferred check so handle it now */
if ((mark == gtk_text_buffer_get_insert (buffer)) && spell->deferred_check)
{
check_deferred_range (spell, FALSE);
}
}
static void
get_word_extents_from_mark (GtkTextBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end,
GtkTextMark *mark)
{
gtk_text_buffer_get_iter_at_mark(buffer, start, mark);
if (!gtk_text_iter_starts_word (start))
{
gtk_text_iter_backward_word_start (start);
}
*end = *start;
if (gtk_text_iter_inside_word (end))
{
gtk_text_iter_forward_word_end (end);
}
}
static void
remove_tag_to_word (XedAutomaticSpellChecker *spell,
const gchar *word)
{
GtkTextIter iter;
GtkTextIter match_start, match_end;
gboolean found;
gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (spell->doc), &iter, 0);
found = TRUE;
while (found)
{
found = gtk_text_iter_forward_search (&iter,
word,
GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY,
&match_start,
&match_end,
NULL);
if (found)
{
if (gtk_text_iter_starts_word (&match_start) && gtk_text_iter_ends_word (&match_end))
{
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc),
spell->tag_highlight,
&match_start,
&match_end);
}
iter = match_end;
}
}
}
static void
add_to_dictionary (GtkWidget *menuitem,
XedAutomaticSpellChecker *spell)
{
gchar *word;
GtkTextIter start, end;
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
xed_spell_checker_add_word_to_personal (spell->spell_checker, word, -1);
g_free (word);
}
static void
ignore_all (GtkWidget *menuitem,
XedAutomaticSpellChecker *spell)
{
gchar *word;
GtkTextIter start, end;
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
xed_spell_checker_add_word_to_session (spell->spell_checker, word, -1);
g_free (word);
}
static void
replace_word (GtkWidget *menuitem,
XedAutomaticSpellChecker *spell)
{
gchar *oldword;
const gchar *newword;
GtkTextIter start, end;
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
oldword = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
newword = g_object_get_qdata (G_OBJECT (menuitem), suggestion_id);
g_return_if_fail (newword != NULL);
gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (spell->doc));
gtk_text_buffer_delete (GTK_TEXT_BUFFER (spell->doc), &start, &end);
gtk_text_buffer_insert (GTK_TEXT_BUFFER (spell->doc), &start, newword, -1);
gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (spell->doc));
xed_spell_checker_set_correction (spell->spell_checker,
oldword, strlen (oldword),
newword, strlen (newword));
g_free (oldword);
}
static GtkWidget *
build_suggestion_menu (XedAutomaticSpellChecker *spell,
const gchar *word)
{
GtkWidget *topmenu, *menu;
GtkWidget *mi;
GSList *suggestions;
GSList *list;
gchar *label_text;
topmenu = menu = gtk_menu_new();
suggestions = xed_spell_checker_get_suggestions (spell->spell_checker, word, -1);
list = suggestions;
if (suggestions == NULL)
{
/* no suggestions. put something in the menu anyway... */
GtkWidget *label;
/* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions for the current misspelled word */
label = gtk_label_new (_("(no suggested words)"));
mi = gtk_menu_item_new ();
gtk_widget_set_sensitive (mi, FALSE);
gtk_container_add (GTK_CONTAINER(mi), label);
gtk_widget_show_all (mi);
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
}
else
{
gint count = 0;
/* build a set of menus with suggestions. */
while (suggestions != NULL)
{
GtkWidget *label;
if (count == 10)
{
/* Separator */
mi = gtk_menu_item_new ();
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
mi = gtk_menu_item_new_with_mnemonic (_("_More..."));
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
menu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu);
count = 0;
}
label_text = g_strdup_printf ("<b>%s</b>", (gchar*) suggestions->data);
label = gtk_label_new (label_text);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_widget_set_halign (label, GTK_ALIGN_START);
mi = gtk_menu_item_new ();
gtk_container_add (GTK_CONTAINER (mi), label);
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
g_object_set_qdata_full (G_OBJECT (mi),
suggestion_id,
g_strdup (suggestions->data),
(GDestroyNotify)g_free);
g_free (label_text);
g_signal_connect (mi, "activate",
G_CALLBACK (replace_word), spell);
count++;
suggestions = g_slist_next (suggestions);
}
}
/* free the suggestion list */
suggestions = list;
while (list)
{
g_free (list->data);
list = g_slist_next (list);
}
g_slist_free (suggestions);
/* Separator */
mi = gtk_menu_item_new ();
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
/* Ignore all */
mi = gtk_menu_item_new_with_mnemonic (_("_Ignore All"));
g_signal_connect (mi, "activate",
G_CALLBACK(ignore_all), spell);
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
/* + Add to Dictionary */
mi = gtk_menu_item_new_with_mnemonic (_("_Add"));
g_signal_connect (mi, "activate",
G_CALLBACK (add_to_dictionary), spell);
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
return topmenu;
}
static void
populate_popup (GtkTextView *textview,
GtkMenu *menu,
XedAutomaticSpellChecker *spell)
{
GtkWidget *mi;
GtkTextIter start, end;
char *word;
/* we need to figure out if they picked a misspelled word. */
get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click);
/* if our highlight algorithm ever messes up,
* this isn't correct, either. */
if (!gtk_text_iter_has_tag (&start, spell->tag_highlight))
{
return; /* word wasn't misspelled. */
}
/* menu separator comes first. */
mi = gtk_menu_item_new ();
gtk_widget_show (mi);
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
/* then, on top of it, the suggestions menu. */
mi = gtk_menu_item_new_with_mnemonic (_("_Spelling Suggestions..."));
word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), build_suggestion_menu (spell, word));
g_free(word);
gtk_widget_show_all (mi);
gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi);
}
void
xed_automatic_spell_checker_recheck_all (XedAutomaticSpellChecker *spell)
{
GtkTextIter start, end;
g_return_if_fail (spell != NULL);
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end);
check_range (spell, start, end, TRUE);
}
static void
add_word_signal_cb (XedSpellChecker *checker,
const gchar *word,
gint len,
XedAutomaticSpellChecker *spell)
{
gchar *w;
if (len < 0)
{
w = g_strdup (word);
}
else
{
w = g_strndup (word, len);
}
remove_tag_to_word (spell, w);
g_free (w);
}
static void
set_language_cb (XedSpellChecker *checker,
const XedSpellCheckerLanguage *lang,
XedAutomaticSpellChecker *spell)
{
xed_automatic_spell_checker_recheck_all (spell);
}
static void
clear_session_cb (XedSpellChecker *checker,
XedAutomaticSpellChecker *spell)
{
xed_automatic_spell_checker_recheck_all (spell);
}
/* When the user right-clicks on a word, they want to check that word.
* Here, we do NOT move the cursor to the location of the clicked-upon word
* since that prevents the use of edit functions on the context menu.
*/
static gboolean
button_press_event (GtkTextView *view,
GdkEventButton *event,
XedAutomaticSpellChecker *spell)
{
if (event->button == 3)
{
gint x, y;
GtkTextIter iter;
GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
/* handle deferred check if it exists */
if (spell->deferred_check)
{
check_deferred_range (spell, TRUE);
}
gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_TEXT, event->x, event->y, &x, &y);
gtk_text_view_get_iter_at_location (view, &iter, x, y);
gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter);
}
return FALSE; /* false: let gtk process this event, too.
we don't want to eat any events. */
}
/* Move the insert mark before popping up the menu, otherwise it
* will contain the wrong set of suggestions.
*/
static gboolean
popup_menu_event (GtkTextView *view,
XedAutomaticSpellChecker *spell)
{
GtkTextIter iter;
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (view);
/* handle deferred check if it exists */
if (spell->deferred_check)
{
check_deferred_range (spell, TRUE);
}
gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter);
return FALSE;
}
static void
tag_table_changed (GtkTextTagTable *table,
XedAutomaticSpellChecker *spell)
{
g_return_if_fail (spell->tag_highlight != NULL);
gtk_text_tag_set_priority (spell->tag_highlight, gtk_text_tag_table_get_size (table) - 1);
}
static void
tag_added_or_removed (GtkTextTagTable *table,
GtkTextTag *tag,
XedAutomaticSpellChecker *spell)
{
tag_table_changed (table, spell);
}
static void
tag_changed (GtkTextTagTable *table,
GtkTextTag *tag,
gboolean size_changed,
XedAutomaticSpellChecker *spell)
{
tag_table_changed (table, spell);
}
static void
highlight_updated (GtkSourceBuffer *buffer,
GtkTextIter *start,
GtkTextIter *end,
XedAutomaticSpellChecker *spell)
{
check_range (spell, *start, *end, FALSE);
}
static void
spell_tag_destroyed (XedAutomaticSpellChecker *spell,
GObject *where_the_object_was)
{
spell->tag_highlight = NULL;
}
XedAutomaticSpellChecker *
xed_automatic_spell_checker_new (XedDocument *doc,
XedSpellChecker *checker)
{
XedAutomaticSpellChecker *spell;
GtkTextTagTable *tag_table;
GtkTextIter start, end;
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
g_return_val_if_fail (XED_IS_SPELL_CHECKER (checker), NULL);
g_return_val_if_fail ((spell = xed_automatic_spell_checker_get_from_document (doc)) == NULL, spell);
/* attach to the widget */
spell = g_new0 (XedAutomaticSpellChecker, 1);
spell->doc = doc;
spell->spell_checker = g_object_ref (checker);
if (automatic_spell_checker_id == 0)
{
automatic_spell_checker_id = g_quark_from_string ("XedAutomaticSpellCheckerID");
}
if (suggestion_id == 0)
{
suggestion_id = g_quark_from_string ("XedAutoSuggestionID");
}
g_object_set_qdata_full (G_OBJECT (doc), automatic_spell_checker_id,
spell, (GDestroyNotify)xed_automatic_spell_checker_free_internal);
g_signal_connect (doc, "insert-text",
G_CALLBACK (insert_text_before), spell);
g_signal_connect_after (doc, "insert-text",
G_CALLBACK (insert_text_after), spell);
g_signal_connect_after (doc, "delete-range",
G_CALLBACK (delete_range_after), spell);
g_signal_connect (doc, "mark-set",
G_CALLBACK (mark_set), spell);
g_signal_connect (doc, "highlight-updated",
G_CALLBACK (highlight_updated), spell);
g_signal_connect (spell->spell_checker, "add_word_to_session",
G_CALLBACK (add_word_signal_cb), spell);
g_signal_connect (spell->spell_checker, "add_word_to_personal",
G_CALLBACK (add_word_signal_cb), spell);
g_signal_connect (spell->spell_checker, "clear_session",
G_CALLBACK (clear_session_cb), spell);
g_signal_connect (spell->spell_checker, "set_language",
G_CALLBACK (set_language_cb), spell);
spell->tag_highlight = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (doc),
"gtkspell-misspelled",
"underline", PANGO_UNDERLINE_ERROR,
NULL);
g_object_weak_ref (G_OBJECT (spell->tag_highlight), (GWeakNotify)spell_tag_destroyed, spell);
tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (doc));
gtk_text_tag_set_priority (spell->tag_highlight, gtk_text_tag_table_get_size (tag_table) - 1);
g_signal_connect (tag_table, "tag-added",
G_CALLBACK (tag_added_or_removed), spell);
g_signal_connect (tag_table, "tag-removed",
G_CALLBACK (tag_added_or_removed), spell);
g_signal_connect (tag_table, "tag-changed",
G_CALLBACK (tag_changed), spell);
/* we create the mark here, but we don't use it until text is
* inserted, so we don't really care where iter points. */
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end);
spell->mark_insert_start = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-start");
if (spell->mark_insert_start == NULL)
{
spell->mark_insert_start = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-start",
&start,
TRUE);
}
else
{
gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), spell->mark_insert_start, &start);
}
spell->mark_insert_end = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-end");
if (spell->mark_insert_end == NULL)
{
spell->mark_insert_end = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-insert-end",
&start,
TRUE);
}
else
{
gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), spell->mark_insert_end, &start);
}
spell->mark_click = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-click");
if (spell->mark_click == NULL)
{
spell->mark_click = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
"xed-automatic-spell-checker-click",
&start,
TRUE);
}
else
{
gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), spell->mark_click, &start);
}
spell->deferred_check = FALSE;
return spell;
}
XedAutomaticSpellChecker *
xed_automatic_spell_checker_get_from_document (const XedDocument *doc)
{
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
if (automatic_spell_checker_id == 0)
{
return NULL;
}
return g_object_get_qdata (G_OBJECT (doc), automatic_spell_checker_id);
}
void
xed_automatic_spell_checker_free (XedAutomaticSpellChecker *spell)
{
g_return_if_fail (spell != NULL);
g_return_if_fail (xed_automatic_spell_checker_get_from_document (spell->doc) == spell);
if (automatic_spell_checker_id == 0)
{
return;
}
g_object_set_qdata (G_OBJECT (spell->doc), automatic_spell_checker_id, NULL);
}
static void
xed_automatic_spell_checker_free_internal (XedAutomaticSpellChecker *spell)
{
GtkTextTagTable *table;
GtkTextIter start, end;
GSList *list;
g_return_if_fail (spell != NULL);
table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (spell->doc));
if (table != NULL && spell->tag_highlight != NULL)
{
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end);
gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), spell->tag_highlight, &start, &end);
g_signal_handlers_disconnect_matched (G_OBJECT (table),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
gtk_text_tag_table_remove (table, spell->tag_highlight);
}
g_signal_handlers_disconnect_matched (G_OBJECT (spell->doc),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_signal_handlers_disconnect_matched (G_OBJECT (spell->spell_checker),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_object_unref (spell->spell_checker);
list = spell->views;
while (list != NULL)
{
XedView *view = XED_VIEW (list->data);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
list = g_slist_next (list);
}
g_slist_free (spell->views);
g_free (spell);
}
void
xed_automatic_spell_checker_attach_view (XedAutomaticSpellChecker *spell,
XedView *view)
{
g_return_if_fail (spell != NULL);
g_return_if_fail (XED_IS_VIEW (view));
g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == GTK_TEXT_BUFFER (spell->doc));
g_signal_connect (view, "button-press-event",
G_CALLBACK (button_press_event), spell);
g_signal_connect (view, "popup-menu",
G_CALLBACK (popup_menu_event), spell);
g_signal_connect (view, "populate-popup",
G_CALLBACK (populate_popup), spell);
g_signal_connect (view, "destroy",
G_CALLBACK (view_destroy), spell);
spell->views = g_slist_prepend (spell->views, view);
}
void
xed_automatic_spell_checker_detach_view (XedAutomaticSpellChecker *spell,
XedView *view)
{
g_return_if_fail (spell != NULL);
g_return_if_fail (XED_IS_VIEW (view));
g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == GTK_TEXT_BUFFER (spell->doc));
g_return_if_fail (spell->views != NULL);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
g_signal_handlers_disconnect_matched (G_OBJECT (view),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
spell);
spell->views = g_slist_remove (spell->views, view);
}

View File

@ -1,67 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-automatic-spell-checker.h
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
/* This is a modified version of gtkspell 2.0.2 (gtkspell.sf.net) */
/* gtkspell - a spell-checking addon for GTK's TextView widget
* Copyright (c) 2002 Evan Martin.
*/
#ifndef __XED_AUTOMATIC_SPELL_CHECKER_H__
#define __XED_AUTOMATIC_SPELL_CHECKER_H__
#include <xed/xed-document.h>
#include <xed/xed-view.h>
#include "xed-spell-checker.h"
typedef struct _XedAutomaticSpellChecker XedAutomaticSpellChecker;
XedAutomaticSpellChecker *xed_automatic_spell_checker_new (
XedDocument *doc,
XedSpellChecker *checker);
XedAutomaticSpellChecker *xed_automatic_spell_checker_get_from_document (
const XedDocument *doc);
void xed_automatic_spell_checker_free (
XedAutomaticSpellChecker *spell);
void xed_automatic_spell_checker_attach_view (
XedAutomaticSpellChecker *spell,
XedView *view);
void xed_automatic_spell_checker_detach_view (
XedAutomaticSpellChecker *spell,
XedView *view);
void xed_automatic_spell_checker_recheck_all (
XedAutomaticSpellChecker *spell);
#endif /* __XED_AUTOMATIC_SPELL_CHECKER_H__ */

View File

@ -1,726 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-dialog.c
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <xed/xed-utils.h>
#include "xed-spell-checker-dialog.h"
#include "xed-spell-marshal.h"
struct _XedSpellCheckerDialog
{
GtkWindow parent_instance;
XedSpellChecker *spell_checker;
gchar *misspelled_word;
GtkWidget *misspelled_word_label;
GtkWidget *word_entry;
GtkWidget *check_word_button;
GtkWidget *ignore_button;
GtkWidget *ignore_all_button;
GtkWidget *change_button;
GtkWidget *change_all_button;
GtkWidget *add_word_button;
GtkWidget *close_button;
GtkWidget *suggestions_list;
GtkWidget *language_label;
GtkTreeModel *suggestions_list_model;
};
enum
{
IGNORE,
IGNORE_ALL,
CHANGE,
CHANGE_ALL,
ADD_WORD_TO_PERSONAL,
LAST_SIGNAL
};
enum
{
COLUMN_SUGGESTIONS,
NUM_COLUMNS
};
static void update_suggestions_list_model (XedSpellCheckerDialog *dlg,
GSList *suggestions);
static void word_entry_changed_handler (GtkEditable *editable,
XedSpellCheckerDialog *dlg);
static void close_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void suggestions_list_selection_changed_handler (GtkTreeSelection *selection,
XedSpellCheckerDialog *dlg);
static void check_word_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void add_word_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void ignore_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void ignore_all_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void change_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void change_all_button_clicked_handler (GtkButton *button,
XedSpellCheckerDialog *dlg);
static void suggestions_list_row_activated_handler (GtkTreeView *view,
GtkTreePath *path,
GtkTreeViewColumn *column,
XedSpellCheckerDialog *dlg);
static guint signals [LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE(XedSpellCheckerDialog, xed_spell_checker_dialog, GTK_TYPE_WINDOW)
static void
xed_spell_checker_dialog_dispose (GObject *object)
{
XedSpellCheckerDialog *dlg = XED_SPELL_CHECKER_DIALOG (object);
if (dlg->spell_checker != NULL)
{
g_object_unref (dlg->spell_checker);
dlg->spell_checker = NULL;
}
if (dlg->misspelled_word != NULL)
{
g_free (dlg->misspelled_word);
dlg->misspelled_word = NULL;
}
G_OBJECT_CLASS (xed_spell_checker_dialog_parent_class)->dispose (object);
}
static void
xed_spell_checker_dialog_class_init (XedSpellCheckerDialogClass * klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = xed_spell_checker_dialog_dispose;
signals[IGNORE] =
g_signal_new ("ignore",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, ignore),
NULL, NULL,
xed_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
signals[IGNORE_ALL] =
g_signal_new ("ignore_all",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, ignore_all),
NULL, NULL,
xed_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
signals[CHANGE] =
g_signal_new ("change",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, change),
NULL, NULL,
xed_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_STRING);
signals[CHANGE_ALL] =
g_signal_new ("change_all",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, change_all),
NULL, NULL,
xed_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_STRING);
signals[ADD_WORD_TO_PERSONAL] =
g_signal_new ("add_word_to_personal",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerDialogClass, add_word_to_personal),
NULL, NULL,
xed_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
}
static void
create_dialog (XedSpellCheckerDialog *dlg,
const gchar *data_dir)
{
GtkWidget *error_widget;
GtkWidget *content;
GtkTreeViewColumn *column;
GtkCellRenderer *cell;
GtkTreeSelection *selection;
gchar *root_objects[] = {
"content",
"check_word_image",
"add_word_image",
"ignore_image",
"change_image",
"ignore_all_image",
"change_all_image",
NULL
};
gboolean ret;
gchar *ui_file;
g_return_if_fail (dlg != NULL);
dlg->spell_checker = NULL;
dlg->misspelled_word = NULL;
ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL);
ret = xed_utils_get_ui_objects (ui_file,
root_objects,
&error_widget,
"content", &content,
"misspelled_word_label", &dlg->misspelled_word_label,
"word_entry", &dlg->word_entry,
"check_word_button", &dlg->check_word_button,
"ignore_button", &dlg->ignore_button,
"ignore_all_button", &dlg->ignore_all_button,
"change_button", &dlg->change_button,
"change_all_button", &dlg->change_all_button,
"add_word_button", &dlg->add_word_button,
"close_button", &dlg->close_button,
"suggestions_list", &dlg->suggestions_list,
"language_label", &dlg->language_label,
NULL);
g_free (ui_file);
if (!ret)
{
gtk_widget_show (error_widget);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
error_widget, TRUE, TRUE, 0);
return;
}
gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), "");
gtk_widget_set_sensitive (dlg->word_entry, FALSE);
gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE);
gtk_widget_set_sensitive (dlg->change_button, FALSE);
gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
gtk_widget_set_sensitive (dlg->add_word_button, FALSE);
gtk_label_set_label (GTK_LABEL (dlg->language_label), "");
gtk_container_add (GTK_CONTAINER (dlg), content);
g_object_unref (content);
gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling"));
/* Suggestion list */
dlg->suggestions_list_model = GTK_TREE_MODEL (
gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING));
gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list),
dlg->suggestions_list_model);
/* Add the suggestions column */
cell = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell,
"text", COLUMN_SUGGESTIONS, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list),
COLUMN_SUGGESTIONS);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
/* Set default button */
gtk_widget_set_can_default (dlg->change_button, TRUE);
gtk_widget_grab_default (dlg->change_button);
gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE);
/* Connect signals */
g_signal_connect (dlg->word_entry, "changed",
G_CALLBACK (word_entry_changed_handler), dlg);
g_signal_connect (dlg->close_button, "clicked",
G_CALLBACK (close_button_clicked_handler), dlg);
g_signal_connect (selection, "changed",
G_CALLBACK (suggestions_list_selection_changed_handler),
dlg);
g_signal_connect (dlg->check_word_button, "clicked",
G_CALLBACK (check_word_button_clicked_handler), dlg);
g_signal_connect (dlg->add_word_button, "clicked",
G_CALLBACK (add_word_button_clicked_handler), dlg);
g_signal_connect (dlg->ignore_button, "clicked",
G_CALLBACK (ignore_button_clicked_handler), dlg);
g_signal_connect (dlg->ignore_all_button, "clicked",
G_CALLBACK (ignore_all_button_clicked_handler), dlg);
g_signal_connect (dlg->change_button, "clicked",
G_CALLBACK (change_button_clicked_handler), dlg);
g_signal_connect (dlg->change_all_button, "clicked",
G_CALLBACK (change_all_button_clicked_handler), dlg);
g_signal_connect (dlg->suggestions_list, "row-activated",
G_CALLBACK (suggestions_list_row_activated_handler), dlg);
}
static void
xed_spell_checker_dialog_init (XedSpellCheckerDialog *dlg)
{
}
GtkWidget *
xed_spell_checker_dialog_new (const gchar *data_dir)
{
XedSpellCheckerDialog *dlg;
dlg = XED_SPELL_CHECKER_DIALOG (
g_object_new (XED_TYPE_SPELL_CHECKER_DIALOG, NULL));
g_return_val_if_fail (dlg != NULL, NULL);
create_dialog (dlg, data_dir);
return GTK_WIDGET (dlg);
}
GtkWidget *
xed_spell_checker_dialog_new_from_spell_checker (XedSpellChecker *spell,
const gchar *data_dir)
{
XedSpellCheckerDialog *dlg;
g_return_val_if_fail (spell != NULL, NULL);
dlg = XED_SPELL_CHECKER_DIALOG (
g_object_new (XED_TYPE_SPELL_CHECKER_DIALOG, NULL));
g_return_val_if_fail (dlg != NULL, NULL);
create_dialog (dlg, data_dir);
xed_spell_checker_dialog_set_spell_checker (dlg, spell);
return GTK_WIDGET (dlg);
}
void
xed_spell_checker_dialog_set_spell_checker (XedSpellCheckerDialog *dlg, XedSpellChecker *spell)
{
const XedSpellCheckerLanguage* language;
const gchar *lang;
gchar *tmp;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (spell != NULL);
if (dlg->spell_checker != NULL)
g_object_unref (dlg->spell_checker);
dlg->spell_checker = spell;
g_object_ref (dlg->spell_checker);
language = xed_spell_checker_get_language (dlg->spell_checker);
lang = xed_spell_checker_language_to_string (language);
tmp = g_strdup_printf("<b>%s</b>", lang);
gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp);
g_free (tmp);
if (dlg->misspelled_word != NULL)
xed_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1);
else
gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model));
/* TODO: reset all widgets */
}
void
xed_spell_checker_dialog_set_misspelled_word (XedSpellCheckerDialog *dlg,
const gchar *word,
gint len)
{
gchar *tmp;
GSList *sug;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (word != NULL);
g_return_if_fail (dlg->spell_checker != NULL);
g_return_if_fail (!xed_spell_checker_check_word (dlg->spell_checker, word, -1));
/* build_suggestions_list */
if (dlg->misspelled_word != NULL)
g_free (dlg->misspelled_word);
dlg->misspelled_word = g_strdup (word);
tmp = g_strdup_printf("<b>%s</b>", word);
gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp);
g_free (tmp);
sug = xed_spell_checker_get_suggestions (dlg->spell_checker,
dlg->misspelled_word,
-1);
update_suggestions_list_model (dlg, sug);
/* free the suggestion list */
g_slist_foreach (sug, (GFunc)g_free, NULL);
g_slist_free (sug);
gtk_widget_set_sensitive (dlg->ignore_button, TRUE);
gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE);
gtk_widget_set_sensitive (dlg->add_word_button, TRUE);
}
static void
update_suggestions_list_model (XedSpellCheckerDialog *dlg, GSList *suggestions)
{
GtkListStore *store;
GtkTreeIter iter;
GtkTreeSelection *sel;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model));
store = GTK_LIST_STORE (dlg->suggestions_list_model);
gtk_list_store_clear (store);
gtk_widget_set_sensitive (dlg->word_entry, TRUE);
if (suggestions == NULL)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
/* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions
* for the current misspelled word */
COLUMN_SUGGESTIONS, _("(no suggested words)"),
-1);
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), "");
gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
return;
}
gtk_widget_set_sensitive (dlg->suggestions_list, TRUE);
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data);
while (suggestions != NULL)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_SUGGESTIONS, (gchar*)suggestions->data,
-1);
suggestions = g_slist_next (suggestions);
}
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list));
gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter);
gtk_tree_selection_select_iter (sel, &iter);
}
static void
word_entry_changed_handler (GtkEditable *editable, XedSpellCheckerDialog *dlg)
{
const gchar *text;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
if (g_utf8_strlen (text, -1) > 0)
{
gtk_widget_set_sensitive (dlg->check_word_button, TRUE);
gtk_widget_set_sensitive (dlg->change_button, TRUE);
gtk_widget_set_sensitive (dlg->change_all_button, TRUE);
}
else
{
gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
gtk_widget_set_sensitive (dlg->change_button, FALSE);
gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
}
}
static void
close_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
gtk_widget_destroy (GTK_WIDGET (dlg));
}
static void
suggestions_list_selection_changed_handler (GtkTreeSelection *selection,
XedSpellCheckerDialog *dlg)
{
GtkTreeIter iter;
GValue value = {0, };
const gchar *text;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
gtk_tree_model_get_value (dlg->suggestions_list_model, &iter,
COLUMN_SUGGESTIONS,
&value);
text = g_value_get_string (&value);
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text);
g_value_unset (&value);
}
static void
check_word_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
const gchar *word;
gssize len;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
len = strlen (word);
g_return_if_fail (len > 0);
if (xed_spell_checker_check_word (dlg->spell_checker, word, len))
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE (dlg->suggestions_list_model);
gtk_list_store_clear (store);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
/* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */
COLUMN_SUGGESTIONS, _("(correct spelling)"),
-1);
gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
}
else
{
GSList *sug;
sug = xed_spell_checker_get_suggestions (dlg->spell_checker,
word,
len);
update_suggestions_list_model (dlg, sug);
/* free the suggestion list */
g_slist_foreach (sug, (GFunc)g_free, NULL);
g_slist_free (sug);
}
}
static void
add_word_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
xed_spell_checker_add_word_to_personal (dlg->spell_checker,
dlg->misspelled_word,
-1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word);
g_free (word);
}
static void
ignore_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word);
g_free (word);
}
static void
ignore_all_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
xed_spell_checker_add_word_to_session (dlg->spell_checker,
dlg->misspelled_word,
-1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word);
g_free (word);
}
static void
change_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
const gchar *entry_text;
gchar *change;
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
entry_text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
g_return_if_fail (entry_text != NULL);
g_return_if_fail (*entry_text != '\0');
change = g_strdup (entry_text);
xed_spell_checker_set_correction (dlg->spell_checker,
dlg->misspelled_word, -1,
change, -1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change);
g_free (word);
g_free (change);
}
/* double click on one of the suggestions is like clicking on "change" */
static void
suggestions_list_row_activated_handler (GtkTreeView *view,
GtkTreePath *path,
GtkTreeViewColumn *column,
XedSpellCheckerDialog *dlg)
{
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg);
}
static void
change_all_button_clicked_handler (GtkButton *button, XedSpellCheckerDialog *dlg)
{
const gchar *entry_text;
gchar *change;
gchar *word;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
g_return_if_fail (dlg->misspelled_word != NULL);
entry_text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
g_return_if_fail (entry_text != NULL);
g_return_if_fail (*entry_text != '\0');
change = g_strdup (entry_text);
xed_spell_checker_set_correction (dlg->spell_checker,
dlg->misspelled_word, -1,
change, -1);
word = g_strdup (dlg->misspelled_word);
g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change);
g_free (word);
g_free (change);
}
void
xed_spell_checker_dialog_set_completed (XedSpellCheckerDialog *dlg)
{
gchar *tmp;
g_return_if_fail (XED_IS_SPELL_CHECKER_DIALOG (dlg));
tmp = g_strdup_printf("<b>%s</b>", _("Completed spell checking"));
gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label),
tmp);
g_free (tmp);
gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model));
gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), "");
gtk_widget_set_sensitive (dlg->word_entry, FALSE);
gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_button, FALSE);
gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE);
gtk_widget_set_sensitive (dlg->change_button, FALSE);
gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
gtk_widget_set_sensitive (dlg->add_word_button, FALSE);
gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
}

View File

@ -1,92 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-dialog.h
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_CHECKER_DIALOG_H__
#define __XED_SPELL_CHECKER_DIALOG_H__
#include <gtk/gtk.h>
#include "xed-spell-checker.h"
G_BEGIN_DECLS
#define XED_TYPE_SPELL_CHECKER_DIALOG (xed_spell_checker_dialog_get_type ())
#define XED_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_SPELL_CHECKER_DIALOG, XedSpellCheckerDialog))
#define XED_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_SPELL_CHECKER_DIALOG, XedSpellCheckerDialog))
#define XED_IS_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_SPELL_CHECKER_DIALOG))
#define XED_IS_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SPELL_CHECKER_DIALOG))
#define XED_SPELL_CHECKER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_SPELL_CHECKER_DIALOG, XedSpellCheckerDialog))
typedef struct _XedSpellCheckerDialog XedSpellCheckerDialog;
typedef struct _XedSpellCheckerDialogClass XedSpellCheckerDialogClass;
struct _XedSpellCheckerDialogClass
{
GtkWindowClass parent_class;
/* Signals */
void (*ignore) (XedSpellCheckerDialog *dlg,
const gchar *word);
void (*ignore_all) (XedSpellCheckerDialog *dlg,
const gchar *word);
void (*change) (XedSpellCheckerDialog *dlg,
const gchar *word,
const gchar *change_to);
void (*change_all) (XedSpellCheckerDialog *dlg,
const gchar *word,
const gchar *change_to);
void (*add_word_to_personal) (XedSpellCheckerDialog *dlg,
const gchar *word);
};
GType xed_spell_checker_dialog_get_type (void) G_GNUC_CONST;
/* Constructors */
GtkWidget *xed_spell_checker_dialog_new (const gchar *data_dir);
GtkWidget *xed_spell_checker_dialog_new_from_spell_checker
(XedSpellChecker *spell,
const gchar *data_dir);
void xed_spell_checker_dialog_set_spell_checker
(XedSpellCheckerDialog *dlg,
XedSpellChecker *spell);
void xed_spell_checker_dialog_set_misspelled_word
(XedSpellCheckerDialog *dlg,
const gchar* word,
gint len);
void xed_spell_checker_dialog_set_completed
(XedSpellCheckerDialog *dlg);
G_END_DECLS
#endif /* __XED_SPELL_CHECKER_DIALOG_H__ */

View File

@ -1,439 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-language.c
* This file is part of xed
*
* Copyright (C) 2006 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2006. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
/* Part of the code taked from Epiphany.
*
* Copyright (C) 2003, 2004 Christian Persch
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <enchant.h>
#include <glib/gi18n.h>
#include <libxml/xmlreader.h>
#include "xed-spell-checker-language.h"
#include <xed/xed-debug.h>
#define ISO_639_DOMAIN "iso_639"
#define ISO_3166_DOMAIN "iso_3166"
#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
struct _XedSpellCheckerLanguage
{
gchar *abrev;
gchar *name;
};
static gboolean available_languages_initialized = FALSE;
static GSList *available_languages = NULL;
static GHashTable *iso_639_table = NULL;
static GHashTable *iso_3166_table = NULL;
static void
bind_iso_domains (void)
{
static gboolean bound = FALSE;
if (bound == FALSE)
{
bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
bound = TRUE;
}
}
static void
read_iso_639_entry (xmlTextReaderPtr reader,
GHashTable *table)
{
xmlChar *code, *name;
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code");
name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
/* Get iso-639-2 code */
if (code == NULL || code[0] == '\0')
{
xmlFree (code);
/* FIXME: use the 2T or 2B code? */
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code");
}
if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0')
{
g_hash_table_insert (table, code, name);
}
else
{
xmlFree (code);
xmlFree (name);
}
}
static void
read_iso_3166_entry (xmlTextReaderPtr reader,
GHashTable *table)
{
xmlChar *code, *name;
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code");
name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0')
{
char *lcode;
lcode = g_ascii_strdown ((char *) code, -1);
xmlFree (code);
/* g_print ("%s -> %s\n", lcode, name); */
g_hash_table_insert (table, lcode, name);
}
else
{
xmlFree (code);
xmlFree (name);
}
}
typedef enum
{
STATE_START,
STATE_STOP,
STATE_ENTRIES,
} ParserState;
static void
load_iso_entries (int iso,
GFunc read_entry_func,
gpointer user_data)
{
xmlTextReaderPtr reader;
ParserState state = STATE_START;
xmlChar iso_entries[32], iso_entry[32];
char *filename;
int ret = -1;
xed_debug_message (DEBUG_PLUGINS, "Loading ISO-%d codes", iso);
filename = g_strdup_printf (ISO_CODES_PREFIX "/share/xml/iso-codes/iso_%d.xml", iso);
reader = xmlNewTextReaderFilename (filename);
if (reader == NULL) goto out;
xmlStrPrintf (iso_entries, sizeof (iso_entries), (const xmlChar *)"iso_%d_entries", iso);
xmlStrPrintf (iso_entry, sizeof (iso_entry), (const xmlChar *)"iso_%d_entry", iso);
ret = xmlTextReaderRead (reader);
while (ret == 1)
{
const xmlChar *tag;
xmlReaderTypes type;
tag = xmlTextReaderConstName (reader);
type = xmlTextReaderNodeType (reader);
if (state == STATE_ENTRIES &&
type == XML_READER_TYPE_ELEMENT &&
xmlStrEqual (tag, iso_entry))
{
read_entry_func (reader, user_data);
}
else if (state == STATE_START &&
type == XML_READER_TYPE_ELEMENT &&
xmlStrEqual (tag, iso_entries))
{
state = STATE_ENTRIES;
}
else if (state == STATE_ENTRIES &&
type == XML_READER_TYPE_END_ELEMENT &&
xmlStrEqual (tag, iso_entries))
{
state = STATE_STOP;
}
else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE ||
type == XML_READER_TYPE_WHITESPACE ||
type == XML_READER_TYPE_TEXT ||
type == XML_READER_TYPE_COMMENT)
{
/* eat it */
}
else
{
/* ignore it */
}
ret = xmlTextReaderRead (reader);
}
xmlFreeTextReader (reader);
out:
if (ret < 0 || state != STATE_STOP)
{
g_warning ("Failed to load ISO-%d codes from %s!\n",
iso, filename);
}
g_free (filename);
}
static GHashTable *
create_iso_639_table (void)
{
GHashTable *table;
bind_iso_domains ();
table = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) xmlFree,
(GDestroyNotify) xmlFree);
load_iso_entries (639, (GFunc) read_iso_639_entry, table);
return table;
}
static GHashTable *
create_iso_3166_table (void)
{
GHashTable *table;
bind_iso_domains ();
table = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) xmlFree);
load_iso_entries (3166, (GFunc) read_iso_3166_entry, table);
return table;
}
static char *
create_name_for_language (const char *code)
{
char **str;
char *name = NULL;
const char *langname, *localename;
int len;
g_return_val_if_fail (iso_639_table != NULL, NULL);
g_return_val_if_fail (iso_3166_table != NULL, NULL);
str = g_strsplit (code, "_", -1);
len = g_strv_length (str);
g_return_val_if_fail (len != 0, NULL);
langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]);
if (len == 1 && langname != NULL)
{
name = g_strdup (dgettext (ISO_639_DOMAIN, langname));
}
else if (len == 2 && langname != NULL)
{
gchar *locale_code = g_ascii_strdown (str[1], -1);
localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code);
g_free (locale_code);
if (localename != NULL)
{
/* Translators: the first %s is the language name, and
* the second %s is the locale name. Example:
* "French (France)"
*/
name = g_strdup_printf (C_("language", "%s (%s)"),
dgettext (ISO_639_DOMAIN, langname),
dgettext (ISO_3166_DOMAIN, localename));
}
else
{
name = g_strdup_printf (C_("language", "%s (%s)"),
dgettext (ISO_639_DOMAIN, langname), str[1]);
}
}
else
{
/* Translators: this refers to an unknown language code
* (one which isn't in our built-in list).
*/
name = g_strdup_printf (C_("language", "Unknown (%s)"), code);
}
g_strfreev (str);
return name;
}
static void
enumerate_dicts (const char * const lang_tag,
const char * const provider_name,
const char * const provider_desc,
const char * const provider_file,
void * user_data)
{
gchar *lang_name;
GTree *dicts = (GTree *)user_data;
lang_name = create_name_for_language (lang_tag);
g_return_if_fail (lang_name != NULL);
/* g_print ("%s - %s\n", lang_tag, lang_name); */
g_tree_replace (dicts, g_strdup (lang_tag), lang_name);
}
static gint
key_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
{
return strcmp (a, b);
}
static gint
lang_cmp (const XedSpellCheckerLanguage *a,
const XedSpellCheckerLanguage *b)
{
return g_utf8_collate (a->name, b->name);
}
static gboolean
build_langs_list (const gchar *key,
const gchar *value,
gpointer data)
{
XedSpellCheckerLanguage *lang = g_new (XedSpellCheckerLanguage, 1);
lang->abrev = g_strdup (key);
lang->name = g_strdup (value);
available_languages = g_slist_insert_sorted (available_languages,
lang,
(GCompareFunc)lang_cmp);
return FALSE;
}
const GSList *
xed_spell_checker_get_available_languages (void)
{
EnchantBroker *broker;
GTree *dicts;
if (available_languages_initialized)
return available_languages;
g_return_val_if_fail (available_languages == NULL, NULL);
available_languages_initialized = TRUE;
broker = enchant_broker_init ();
g_return_val_if_fail (broker != NULL, NULL);
/* Use a GTree to efficiently remove duplicates while building the list */
dicts = g_tree_new_full (key_cmp,
NULL,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
iso_639_table = create_iso_639_table ();
iso_3166_table = create_iso_3166_table ();
enchant_broker_list_dicts (broker, enumerate_dicts, dicts);
enchant_broker_free (broker);
g_hash_table_destroy (iso_639_table);
g_hash_table_destroy (iso_3166_table);
iso_639_table = NULL;
iso_3166_table = NULL;
g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL);
g_tree_destroy (dicts);
return available_languages;
}
const gchar *
xed_spell_checker_language_to_string (const XedSpellCheckerLanguage *lang)
{
if (lang == NULL)
/* Translators: this refers the Default language used by the
* spell checker
*/
return C_("language", "Default");
return lang->name;
}
const gchar *
xed_spell_checker_language_to_key (const XedSpellCheckerLanguage *lang)
{
g_return_val_if_fail (lang != NULL, NULL);
return lang->abrev;
}
const XedSpellCheckerLanguage *
xed_spell_checker_language_from_key (const gchar *key)
{
const GSList *langs;
g_return_val_if_fail (key != NULL, NULL);
langs = xed_spell_checker_get_available_languages ();
while (langs != NULL)
{
const XedSpellCheckerLanguage *l = (const XedSpellCheckerLanguage *)langs->data;
if (g_ascii_strcasecmp (key, l->abrev) == 0)
return l;
langs = g_slist_next (langs);
}
return NULL;
}

View File

@ -1,51 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker-language.h
* This file is part of xed
*
* Copyright (C) 2006 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2006. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_CHECKER_LANGUAGE_H__
#define __XED_SPELL_CHECKER_LANGUAGE_H__
#include <glib.h>
G_BEGIN_DECLS
typedef struct _XedSpellCheckerLanguage XedSpellCheckerLanguage;
const gchar *xed_spell_checker_language_to_string (const XedSpellCheckerLanguage *lang);
const gchar *xed_spell_checker_language_to_key (const XedSpellCheckerLanguage *lang);
const XedSpellCheckerLanguage *xed_spell_checker_language_from_key (const gchar *key);
/* GSList contains "XedSpellCheckerLanguage*" items */
const GSList *xed_spell_checker_get_available_languages
(void);
G_END_DECLS
#endif /* __XED_SPELL_CHECKER_LANGUAGE_H__ */

View File

@ -1,564 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker.c
* This file is part of xed
*
* Copyright (C) 2002-2006 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002-2006. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <enchant.h>
#include <glib/gi18n.h>
#include <glib.h>
#include "xed-spell-checker.h"
#include "xed-spell-utils.h"
#include "xed-spell-marshal.h"
struct _XedSpellChecker
{
GObject parent_instance;
EnchantDict *dict;
EnchantBroker *broker;
const XedSpellCheckerLanguage *active_lang;
};
/* GObject properties */
enum {
PROP_0 = 0,
PROP_LANGUAGE,
LAST_PROP
};
/* Signals */
enum {
ADD_WORD_TO_PERSONAL = 0,
ADD_WORD_TO_SESSION,
SET_LANGUAGE,
CLEAR_SESSION,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE(XedSpellChecker, xed_spell_checker, G_TYPE_OBJECT)
static void
xed_spell_checker_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
/*
XedSpellChecker *spell = XED_SPELL_CHECKER (object);
*/
switch (prop_id)
{
case PROP_LANGUAGE:
/* TODO */
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
xed_spell_checker_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
/*
XedSpellChecker *spell = XED_SPELL_CHECKER (object);
*/
switch (prop_id)
{
case PROP_LANGUAGE:
/* TODO */
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
xed_spell_checker_finalize (GObject *object)
{
XedSpellChecker *spell_checker;
g_return_if_fail (XED_IS_SPELL_CHECKER (object));
spell_checker = XED_SPELL_CHECKER (object);
if (spell_checker->dict != NULL)
{
enchant_broker_free_dict (spell_checker->broker, spell_checker->dict);
}
if (spell_checker->broker != NULL)
{
enchant_broker_free (spell_checker->broker);
}
G_OBJECT_CLASS (xed_spell_checker_parent_class)->finalize (object);
}
static void
xed_spell_checker_class_init (XedSpellCheckerClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = xed_spell_checker_set_property;
object_class->get_property = xed_spell_checker_get_property;
object_class->finalize = xed_spell_checker_finalize;
g_object_class_install_property (object_class,
PROP_LANGUAGE,
g_param_spec_pointer ("language",
"Language",
"The language used by the spell checker",
G_PARAM_READWRITE));
signals[ADD_WORD_TO_PERSONAL] =
g_signal_new ("add_word_to_personal",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, add_word_to_personal),
NULL, NULL,
xed_marshal_VOID__STRING_INT,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_INT);
signals[ADD_WORD_TO_SESSION] =
g_signal_new ("add_word_to_session",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, add_word_to_session),
NULL, NULL,
xed_marshal_VOID__STRING_INT,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_INT);
signals[SET_LANGUAGE] =
g_signal_new ("set_language",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, set_language),
NULL, NULL,
xed_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
signals[CLEAR_SESSION] =
g_signal_new ("clear_session",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedSpellCheckerClass, clear_session),
NULL, NULL,
xed_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
xed_spell_checker_init (XedSpellChecker *spell_checker)
{
spell_checker->broker = enchant_broker_init ();
spell_checker->dict = NULL;
spell_checker->active_lang = NULL;
}
XedSpellChecker *
xed_spell_checker_new (void)
{
XedSpellChecker *spell;
spell = XED_SPELL_CHECKER (g_object_new (XED_TYPE_SPELL_CHECKER, NULL));
g_return_val_if_fail (spell != NULL, NULL);
return spell;
}
static gboolean
lazy_init (XedSpellChecker *spell,
const XedSpellCheckerLanguage *language)
{
if (spell->dict != NULL)
{
return TRUE;
}
g_return_val_if_fail (spell->broker != NULL, FALSE);
spell->active_lang = NULL;
if (language != NULL)
{
spell->active_lang = language;
}
else
{
/* First try to get a default language */
const XedSpellCheckerLanguage *l;
gint i = 0;
const gchar * const *lang_tags = g_get_language_names ();
while (lang_tags [i])
{
l = xed_spell_checker_language_from_key (lang_tags [i]);
if (l != NULL)
{
spell->active_lang = l;
break;
}
i++;
}
}
/* Second try to get a default language */
if (spell->active_lang == NULL)
{
spell->active_lang = xed_spell_checker_language_from_key ("en_US");
}
/* Last try to get a default language */
if (spell->active_lang == NULL)
{
const GSList *langs;
langs = xed_spell_checker_get_available_languages ();
if (langs != NULL)
{
spell->active_lang = (const XedSpellCheckerLanguage *)langs->data;
}
}
if (spell->active_lang != NULL)
{
const gchar *key;
key = xed_spell_checker_language_to_key (spell->active_lang);
spell->dict = enchant_broker_request_dict (spell->broker, key);
}
if (spell->dict == NULL)
{
spell->active_lang = NULL;
if (language != NULL)
{
g_warning ("Spell checker plugin: cannot select a default language.");
}
return FALSE;
}
return TRUE;
}
gboolean
xed_spell_checker_set_language (XedSpellChecker *spell,
const XedSpellCheckerLanguage *language)
{
gboolean ret;
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
if (spell->dict != NULL)
{
enchant_broker_free_dict (spell->broker, spell->dict);
spell->dict = NULL;
}
ret = lazy_init (spell, language);
if (ret)
{
g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language);
}
else
{
g_warning ("Spell checker plugin: cannot use language %s.", xed_spell_checker_language_to_string (language));
}
return ret;
}
const XedSpellCheckerLanguage *
xed_spell_checker_get_language (XedSpellChecker *spell)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), NULL);
if (!lazy_init (spell, spell->active_lang))
{
return NULL;
}
return spell->active_lang;
}
gboolean
xed_spell_checker_check_word (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
gint enchant_result;
gboolean res = FALSE;
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
{
return FALSE;
}
if (len < 0)
{
len = strlen (word);
}
if (strcmp (word, "xed") == 0)
{
return TRUE;
}
if (xed_spell_utils_is_digit (word, len))
{
return TRUE;
}
g_return_val_if_fail (spell->dict != NULL, FALSE);
enchant_result = enchant_dict_check (spell->dict, word, len);
switch (enchant_result)
{
case -1:
/* error */
res = FALSE;
g_warning ("Spell checker plugin: error checking word '%s' (%s).",
word, enchant_dict_get_error (spell->dict));
break;
case 1:
/* it is not in the directory */
res = FALSE;
break;
case 0:
/* is is in the directory */
res = TRUE;
break;
default:
g_return_val_if_reached (FALSE);
}
return res;
}
/* return NULL on error or if no suggestions are found */
GSList *
xed_spell_checker_get_suggestions (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
gchar **suggestions;
size_t n_suggestions = 0;
GSList *suggestions_list = NULL;
gint i;
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), NULL);
g_return_val_if_fail (word != NULL, NULL);
if (!lazy_init (spell, spell->active_lang))
{
return NULL;
}
g_return_val_if_fail (spell->dict != NULL, NULL);
if (len < 0)
{
len = strlen (word);
}
suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions);
if (n_suggestions == 0)
{
return NULL;
}
g_return_val_if_fail (suggestions != NULL, NULL);
for (i = 0; i < (gint)n_suggestions; i++)
{
suggestions_list = g_slist_prepend (suggestions_list, suggestions[i]);
}
/* The single suggestions will be freed by the caller */
g_free (suggestions);
suggestions_list = g_slist_reverse (suggestions_list);
return suggestions_list;
}
gboolean
xed_spell_checker_add_word_to_personal (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
{
return FALSE;
}
g_return_val_if_fail (spell->dict != NULL, FALSE);
if (len < 0)
{
len = strlen (word);
}
enchant_dict_add (spell->dict, word, len);
g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len);
return TRUE;
}
gboolean
xed_spell_checker_add_word_to_session (XedSpellChecker *spell,
const gchar *word,
gssize len)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
{
return FALSE;
}
g_return_val_if_fail (spell->dict != NULL, FALSE);
if (len < 0)
{
len = strlen (word);
}
enchant_dict_add_to_session (spell->dict, word, len);
g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len);
return TRUE;
}
gboolean
xed_spell_checker_clear_session (XedSpellChecker *spell)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
/* free and re-request dictionary */
if (spell->dict != NULL)
{
enchant_broker_free_dict (spell->broker, spell->dict);
spell->dict = NULL;
}
if (!lazy_init (spell, spell->active_lang))
{
return FALSE;
}
g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0);
return TRUE;
}
/*
* Informs dictionary, that word 'word' will be replaced/corrected by word
* 'replacement'
*/
gboolean
xed_spell_checker_set_correction (XedSpellChecker *spell,
const gchar *word,
gssize w_len,
const gchar *replacement,
gssize r_len)
{
g_return_val_if_fail (XED_IS_SPELL_CHECKER (spell), FALSE);
g_return_val_if_fail (word != NULL, FALSE);
g_return_val_if_fail (replacement != NULL, FALSE);
if (!lazy_init (spell, spell->active_lang))
{
return FALSE;
}
g_return_val_if_fail (spell->dict != NULL, FALSE);
if (w_len < 0)
{
w_len = strlen (word);
}
if (r_len < 0)
{
r_len = strlen (replacement);
}
enchant_dict_store_replacement (spell->dict,
word,
w_len,
replacement,
r_len);
return TRUE;
}

View File

@ -1,109 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-checker.h
* This file is part of xed
*
* Copyright (C) 2002-2006 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_CHECKER_H__
#define __XED_SPELL_CHECKER_H__
#include <glib.h>
#include <glib-object.h>
#include "xed-spell-checker-language.h"
G_BEGIN_DECLS
#define XED_TYPE_SPELL_CHECKER (xed_spell_checker_get_type ())
#define XED_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_SPELL_CHECKER, XedSpellChecker))
#define XED_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_SPELL_CHECKER, XedSpellChecker))
#define XED_IS_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_SPELL_CHECKER))
#define XED_IS_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SPELL_CHECKER))
#define XED_SPELL_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_SPELL_CHECKER, XedSpellChecker))
typedef struct _XedSpellChecker XedSpellChecker;
typedef struct _XedSpellCheckerClass XedSpellCheckerClass;
struct _XedSpellCheckerClass
{
GObjectClass parent_class;
/* Signals */
void (*add_word_to_personal) (XedSpellChecker *spell,
const gchar *word,
gint len);
void (*add_word_to_session) (XedSpellChecker *spell,
const gchar *word,
gint len);
void (*set_language) (XedSpellChecker *spell,
const XedSpellCheckerLanguage *lang);
void (*clear_session) (XedSpellChecker *spell);
};
GType xed_spell_checker_get_type (void) G_GNUC_CONST;
/* Constructors */
XedSpellChecker *xed_spell_checker_new (void);
gboolean xed_spell_checker_set_language (XedSpellChecker *spell,
const XedSpellCheckerLanguage *lang);
const XedSpellCheckerLanguage
*xed_spell_checker_get_language (XedSpellChecker *spell);
gboolean xed_spell_checker_check_word (XedSpellChecker *spell,
const gchar *word,
gssize len);
GSList *xed_spell_checker_get_suggestions (XedSpellChecker *spell,
const gchar *word,
gssize len);
gboolean xed_spell_checker_add_word_to_personal
(XedSpellChecker *spell,
const gchar *word,
gssize len);
gboolean xed_spell_checker_add_word_to_session
(XedSpellChecker *spell,
const gchar *word,
gssize len);
gboolean xed_spell_checker_clear_session (XedSpellChecker *spell);
gboolean xed_spell_checker_set_correction (XedSpellChecker *spell,
const gchar *word,
gssize w_len,
const gchar *replacement,
gssize r_len);
G_END_DECLS
#endif /* __XED_SPELL_CHECKER_H__ */

View File

@ -1,284 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-language-dialog.c
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <xed/xed-utils.h>
#include <xed/xed-app.h>
#include "xed-spell-language-dialog.h"
#include "xed-spell-checker-language.h"
enum
{
COLUMN_LANGUAGE_NAME = 0,
COLUMN_LANGUAGE_POINTER,
ENCODING_NUM_COLS
};
struct _XedSpellLanguageDialog
{
GtkDialog dialog;
GtkWidget *languages_treeview;
GtkTreeModel *model;
};
G_DEFINE_TYPE (XedSpellLanguageDialog, xed_spell_language_dialog, GTK_TYPE_DIALOG)
static void
xed_spell_language_dialog_class_init (XedSpellLanguageDialogClass *klass)
{
/* GObjectClass *object_class = G_OBJECT_CLASS (klass); */
}
static void
dialog_response_handler (GtkDialog *dlg,
gint res_id)
{
if (res_id == GTK_RESPONSE_HELP)
{
xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dlg), NULL, "xed-spell-checker-plugin");
g_signal_stop_emission_by_name (dlg, "response");
}
}
static void
scroll_to_selected (GtkTreeView *tree_view)
{
GtkTreeModel *model;
GtkTreeSelection *selection;
GtkTreeIter iter;
model = gtk_tree_view_get_model (tree_view);
g_return_if_fail (model != NULL);
/* Scroll to selected */
selection = gtk_tree_view_get_selection (tree_view);
g_return_if_fail (selection != NULL);
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
{
GtkTreePath* path;
path = gtk_tree_model_get_path (model, &iter);
g_return_if_fail (path != NULL);
gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 1.0, 0.0);
gtk_tree_path_free (path);
}
}
static void
language_row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
XedSpellLanguageDialog *dialog)
{
gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
}
static void
create_dialog (XedSpellLanguageDialog *dlg,
const gchar *data_dir)
{
GtkWidget *error_widget;
GtkWidget *content;
gboolean ret;
GtkCellRenderer *cell;
GtkTreeViewColumn *column;
gchar *ui_file;
gchar *root_objects[] = {
"content",
NULL
};
gtk_dialog_add_buttons (GTK_DIALOG (dlg),
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
_("_Help"), GTK_RESPONSE_HELP,
NULL);
gtk_window_set_title (GTK_WINDOW (dlg), _("Set language"));
gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
/* HIG defaults */
gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), 2);
gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), 5);
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), 6);
g_signal_connect (dlg, "response",
G_CALLBACK (dialog_response_handler), NULL);
ui_file = g_build_filename (data_dir, "languages-dialog.ui", NULL);
ret = xed_utils_get_ui_objects (ui_file,
root_objects,
&error_widget,
"content", &content,
"languages_treeview", &dlg->languages_treeview,
NULL);
g_free (ui_file);
if (!ret)
{
gtk_widget_show (error_widget);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), error_widget, TRUE, TRUE, 0);
return;
}
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), content, TRUE, TRUE, 0);
g_object_unref (content);
gtk_container_set_border_width (GTK_CONTAINER (content), 5);
dlg->model = GTK_TREE_MODEL (gtk_list_store_new (ENCODING_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER));
gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->languages_treeview), dlg->model);
g_object_unref (dlg->model);
/* Add the encoding column */
cell = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Languages"),
cell,
"text",
COLUMN_LANGUAGE_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->languages_treeview), column);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->languages_treeview), COLUMN_LANGUAGE_NAME);
g_signal_connect (dlg->languages_treeview, "realize",
G_CALLBACK (scroll_to_selected), dlg);
g_signal_connect (dlg->languages_treeview, "row-activated",
G_CALLBACK (language_row_activated), dlg);
}
static void
xed_spell_language_dialog_init (XedSpellLanguageDialog *dlg)
{
}
static void
populate_language_list (XedSpellLanguageDialog *dlg,
const XedSpellCheckerLanguage *cur_lang)
{
GtkListStore *store;
GtkTreeIter iter;
const GSList* langs;
/* create list store */
store = GTK_LIST_STORE (dlg->model);
langs = xed_spell_checker_get_available_languages ();
while (langs)
{
const gchar *name;
name = xed_spell_checker_language_to_string ((const XedSpellCheckerLanguage*)langs->data);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_LANGUAGE_NAME, name,
COLUMN_LANGUAGE_POINTER, langs->data,
-1);
if (langs->data == cur_lang)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview));
g_return_if_fail (selection != NULL);
gtk_tree_selection_select_iter (selection, &iter);
}
langs = g_slist_next (langs);
}
}
GtkWidget *
xed_spell_language_dialog_new (GtkWindow *parent,
const XedSpellCheckerLanguage *cur_lang,
const gchar *data_dir)
{
XedSpellLanguageDialog *dlg;
g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
dlg = g_object_new (XED_TYPE_SPELL_LANGUAGE_DIALOG, NULL);
create_dialog (dlg, data_dir);
populate_language_list (dlg, cur_lang);
gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
gtk_widget_grab_focus (dlg->languages_treeview);
return GTK_WIDGET (dlg);
}
const XedSpellCheckerLanguage *
xed_spell_language_get_selected_language (XedSpellLanguageDialog *dlg)
{
GValue value = {0, };
const XedSpellCheckerLanguage* lang;
GtkTreeIter iter;
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview));
g_return_val_if_fail (selection != NULL, NULL);
if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
{
return NULL;
}
gtk_tree_model_get_value (dlg->model, &iter, COLUMN_LANGUAGE_POINTER, &value);
lang = (const XedSpellCheckerLanguage* ) g_value_get_pointer (&value);
return lang;
}

View File

@ -1,65 +0,0 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* xed-spell-language-dialog.h
* This file is part of xed
*
* Copyright (C) 2002 Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* Modified by the xed Team, 2002. See the AUTHORS file for a
* list of people on the xed Team.
* See the ChangeLog files for a list of changes.
*/
#ifndef __XED_SPELL_LANGUAGE_DIALOG_H__
#define __XED_SPELL_LANGUAGE_DIALOG_H__
#include <gtk/gtk.h>
#include "xed-spell-checker-language.h"
G_BEGIN_DECLS
#define XED_TYPE_SPELL_LANGUAGE_DIALOG (xed_spell_language_dialog_get_type())
#define XED_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_SPELL_LANGUAGE_DIALOG, XedSpellLanguageDialog))
#define XED_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_SPELL_LANGUAGE_DIALOG, XedSpellLanguageDialogClass))
#define XED_IS_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_SPELL_LANGUAGE_DIALOG))
#define XED_IS_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SPELL_LANGUAGE_DIALOG))
#define XED_SPELL_LANGUAGE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_SPELL_LANGUAGE_DIALOG, XedSpellLanguageDialogClass))
typedef struct _XedSpellLanguageDialog XedSpellLanguageDialog;
typedef struct _XedSpellLanguageDialogClass XedSpellLanguageDialogClass;
struct _XedSpellLanguageDialogClass
{
GtkDialogClass parent_class;
};
GType xed_spell_language_dialog_get_type (void) G_GNUC_CONST;
GtkWidget *xed_spell_language_dialog_new (GtkWindow *parent,
const XedSpellCheckerLanguage *cur_lang,
const gchar *data_dir);
const XedSpellCheckerLanguage *xed_spell_language_get_selected_language (XedSpellLanguageDialog *dlg);
G_END_DECLS
#endif /* __XED_SPELL_LANGUAGE_DIALOG_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
/*
* xed-spell-utils.c
* This file is part of xed
*
* Copyright (C) 2010 - Jesse van den Kieboom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "xed-spell-utils.h"
#include <gtksourceview/gtksource.h>
gboolean
xed_spell_utils_is_digit (const char *text, gssize length)
{
gunichar c;
const gchar *p;
const gchar *end;
g_return_val_if_fail (text != NULL, FALSE);
if (length < 0)
length = strlen (text);
p = text;
end = text + length;
while (p != end) {
const gchar *next;
next = g_utf8_next_char (p);
c = g_utf8_get_char (p);
if (!g_unichar_isdigit (c) && c != '.' && c != ',')
return FALSE;
p = next;
}
return TRUE;
}
gboolean
xed_spell_utils_skip_no_spell_check (GtkTextIter *start,
GtkTextIter *end)
{
GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (start));
while (gtk_source_buffer_iter_has_context_class (buffer, start, "no-spell-check"))
{
GtkTextIter last = *start;
if (!gtk_source_buffer_iter_forward_to_context_class_toggle (buffer, start, "no-spell-check"))
{
return FALSE;
}
if (gtk_text_iter_compare (start, &last) <= 0)
{
return FALSE;
}
gtk_text_iter_forward_word_end (start);
gtk_text_iter_backward_word_start (start);
if (gtk_text_iter_compare (start, &last) <= 0)
{
return FALSE;
}
if (gtk_text_iter_compare (start, end) >= 0)
{
return FALSE;
}
}
return TRUE;
}

View File

@ -1,37 +0,0 @@
/*
* xed-spell-utils.h
* This file is part of xed
*
* Copyright (C) 2010 - Jesse van den Kieboom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef __XED_SPELL_UTILS_H__
#define __XED_SPELL_UTILS_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
gboolean xed_spell_utils_is_digit (const char *text, gssize length);
gboolean xed_spell_utils_skip_no_spell_check (GtkTextIter *start, GtkTextIter *end);
G_END_DECLS
#endif /* __XED_SPELL_UTILS_H__ */