aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-html-editor-spell-check-dialog.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-html-editor-spell-check-dialog.c')
-rw-r--r--e-util/e-html-editor-spell-check-dialog.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/e-util/e-html-editor-spell-check-dialog.c b/e-util/e-html-editor-spell-check-dialog.c
new file mode 100644
index 0000000000..b399dfabd8
--- /dev/null
+++ b/e-util/e-html-editor-spell-check-dialog.c
@@ -0,0 +1,710 @@
+/*
+ * e-html-editor-spell-dialog.c
+ *
+ * Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-html-editor-spell-check-dialog.h"
+
+#include <glib/gi18n-lib.h>
+#include <enchant/enchant.h>
+
+#include "e-html-editor-view.h"
+#include "e-spell-checker.h"
+#include "e-spell-dictionary.h"
+
+#define E_HTML_EDITOR_SPELL_CHECK_DIALOG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_HTML_EDITOR_SPELL_CHECK_DIALOG, EHTMLEditorSpellCheckDialogPrivate))
+
+struct _EHTMLEditorSpellCheckDialogPrivate {
+ GtkWidget *add_word_button;
+ GtkWidget *back_button;
+ GtkWidget *dictionary_combo;
+ GtkWidget *ignore_button;
+ GtkWidget *replace_button;
+ GtkWidget *replace_all_button;
+ GtkWidget *skip_button;
+ GtkWidget *suggestion_label;
+ GtkWidget *tree_view;
+
+ WebKitDOMDOMSelection *selection;
+
+ gchar *word;
+ ESpellDictionary *current_dict;
+};
+
+enum {
+ COLUMN_NAME,
+ COLUMN_DICTIONARY,
+ NUM_COLUMNS
+};
+
+G_DEFINE_TYPE (
+ EHTMLEditorSpellCheckDialog,
+ e_html_editor_spell_check_dialog,
+ E_TYPE_HTML_EDITOR_DIALOG)
+
+static void
+html_editor_spell_check_dialog_set_word (EHTMLEditorSpellCheckDialog *dialog,
+ const gchar *word)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorView *view;
+ GtkTreeView *tree_view;
+ GtkListStore *store;
+ gchar *markup;
+ GList *list, *link;
+
+ if (word == NULL)
+ return;
+
+ if (dialog->priv->word != word) {
+ g_free (dialog->priv->word);
+ dialog->priv->word = g_strdup (word);
+ }
+
+ markup = g_strdup_printf (_("<b>Suggestions for '%s'</b>"), word);
+ gtk_label_set_markup (
+ GTK_LABEL (dialog->priv->suggestion_label), markup);
+ g_free (markup);
+
+ tree_view = GTK_TREE_VIEW (dialog->priv->tree_view);
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (tree_view));
+ gtk_list_store_clear (store);
+
+ list = e_spell_dictionary_get_suggestions (
+ dialog->priv->current_dict, word, -1);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ GtkTreeIter iter;
+ gchar *suggestion = link->data;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, suggestion, -1);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_free);
+
+ /* We give focus to WebKit so that the currently selected word
+ * is highlited. Without focus selection is not visible (at
+ * least with my default color scheme). The focus in fact is not
+ * given to WebKit, because this dialog is modal, but it satisfies
+ * it in a way that it paints the selection :) */
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ view = e_html_editor_get_view (editor);
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+}
+
+static gboolean
+select_next_word (EHTMLEditorSpellCheckDialog *dialog)
+{
+ WebKitDOMNode *anchor, *focus;
+ gulong anchor_offset, focus_offset;
+
+ anchor = webkit_dom_dom_selection_get_anchor_node (dialog->priv->selection);
+ anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dialog->priv->selection);
+
+ focus = webkit_dom_dom_selection_get_focus_node (dialog->priv->selection);
+ focus_offset = webkit_dom_dom_selection_get_focus_offset (dialog->priv->selection);
+
+ /* Jump _behind_ next word */
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "move", "forward", "word");
+ /* Jump before the word */
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "move", "backward", "word");
+ /* Select it */
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "extend", "forward", "word");
+
+ /* If the selection didn't change, then we have most probably
+ * reached the end of document - return FALSE */
+ return !((anchor == webkit_dom_dom_selection_get_anchor_node (
+ dialog->priv->selection)) &&
+ (anchor_offset == webkit_dom_dom_selection_get_anchor_offset (
+ dialog->priv->selection)) &&
+ (focus == webkit_dom_dom_selection_get_focus_node (
+ dialog->priv->selection)) &&
+ (focus_offset == webkit_dom_dom_selection_get_focus_offset (
+ dialog->priv->selection)));
+}
+
+static gboolean
+html_editor_spell_check_dialog_next (EHTMLEditorSpellCheckDialog *dialog)
+{
+ WebKitDOMNode *start = NULL, *end = NULL;
+ gulong start_offset, end_offset;
+
+ if (dialog->priv->word == NULL) {
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "move", "left", "documentboundary");
+ } else {
+ /* Remember last selected word */
+ start = webkit_dom_dom_selection_get_anchor_node (
+ dialog->priv->selection);
+ end = webkit_dom_dom_selection_get_focus_node (
+ dialog->priv->selection);
+ start_offset = webkit_dom_dom_selection_get_anchor_offset (
+ dialog->priv->selection);
+ end_offset = webkit_dom_dom_selection_get_focus_offset (
+ dialog->priv->selection);
+ }
+
+ while (select_next_word (dialog)) {
+ WebKitDOMRange *range;
+ WebKitSpellChecker *checker;
+ gint loc, len;
+ gchar *word;
+
+ range = webkit_dom_dom_selection_get_range_at (
+ dialog->priv->selection, 0, NULL);
+ word = webkit_dom_range_get_text (range);
+
+ checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
+ webkit_spell_checker_check_spelling_of_string (
+ checker, word, &loc, &len);
+
+ /* Found misspelled word! */
+ if (loc != -1) {
+ html_editor_spell_check_dialog_set_word (dialog, word);
+ g_free (word);
+ return TRUE;
+ }
+
+ g_free (word);
+ }
+
+ /* Restore the selection to contain the last misspelled word. This is
+ * reached only when we reach the end of the document */
+ if (start && end) {
+ webkit_dom_dom_selection_set_base_and_extent (
+ dialog->priv->selection, start, start_offset,
+ end, end_offset, NULL);
+ }
+
+ /* Close the dialog */
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ return FALSE;
+}
+
+static gboolean
+select_previous_word (EHTMLEditorSpellCheckDialog *dialog)
+{
+ WebKitDOMNode *old_anchor_node;
+ WebKitDOMNode *new_anchor_node;
+ gulong old_anchor_offset;
+ gulong new_anchor_offset;
+
+ old_anchor_node = webkit_dom_dom_selection_get_anchor_node (
+ dialog->priv->selection);
+ old_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (
+ dialog->priv->selection);
+
+ /* Jump on the beginning of current word */
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "move", "backward", "word");
+ /* Jump before previous word */
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "move", "backward", "word");
+ /* Select it */
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection, "extend", "forward", "word");
+
+ /* If the selection start didn't change, then we have most probably
+ * reached the beginnig of document. Return FALSE */
+
+ new_anchor_node = webkit_dom_dom_selection_get_anchor_node (
+ dialog->priv->selection);
+ new_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (
+ dialog->priv->selection);
+
+ return (new_anchor_node != old_anchor_node) ||
+ (new_anchor_offset != old_anchor_offset);
+}
+
+static gboolean
+html_editor_spell_check_dialog_prev (EHTMLEditorSpellCheckDialog *dialog)
+{
+ WebKitDOMNode *start = NULL, *end = NULL;
+ gulong start_offset, end_offset;
+
+ if (dialog->priv->word == NULL) {
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection,
+ "move", "right", "documentboundary");
+ webkit_dom_dom_selection_modify (
+ dialog->priv->selection,
+ "extend", "backward", "word");
+ } else {
+ /* Remember last selected word */
+ start = webkit_dom_dom_selection_get_anchor_node (
+ dialog->priv->selection);
+ end = webkit_dom_dom_selection_get_focus_node (
+ dialog->priv->selection);
+ start_offset = webkit_dom_dom_selection_get_anchor_offset (
+ dialog->priv->selection);
+ end_offset = webkit_dom_dom_selection_get_focus_offset (
+ dialog->priv->selection);
+ }
+
+ while (select_previous_word (dialog)) {
+ WebKitDOMRange *range;
+ WebKitSpellChecker *checker;
+ gint loc, len;
+ gchar *word;
+
+ range = webkit_dom_dom_selection_get_range_at (
+ dialog->priv->selection, 0, NULL);
+ word = webkit_dom_range_get_text (range);
+
+ checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
+ webkit_spell_checker_check_spelling_of_string (
+ checker, word, &loc, &len);
+
+ /* Found misspelled word! */
+ if (loc != -1) {
+ html_editor_spell_check_dialog_set_word (dialog, word);
+ g_free (word);
+ return TRUE;
+ }
+
+ g_free (word);
+ }
+
+ /* Restore the selection to contain the last misspelled word. This is
+ * reached only when we reach the beginning of the document */
+ if (start && end) {
+ webkit_dom_dom_selection_set_base_and_extent (
+ dialog->priv->selection, start, start_offset,
+ end, end_offset, NULL);
+ }
+
+ /* Close the dialog */
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ return FALSE;
+}
+
+static void
+html_editor_spell_check_dialog_replace (EHTMLEditorSpellCheckDialog *dialog)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorView *view;
+ EHTMLEditorSelection *editor_selection;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gchar *replacement;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ view = e_html_editor_get_view (editor);
+ editor_selection = e_html_editor_view_get_selection (view);
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (dialog->priv->tree_view));
+ gtk_tree_selection_get_selected (selection, &model, &iter);
+ gtk_tree_model_get (model, &iter, 0, &replacement, -1);
+
+ e_html_editor_selection_insert_html (
+ editor_selection, replacement);
+
+ g_free (replacement);
+ html_editor_spell_check_dialog_next (dialog);
+}
+
+static void
+html_editor_spell_check_dialog_replace_all (EHTMLEditorSpellCheckDialog *dialog)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorView *view;
+ EHTMLEditorSelection *editor_selection;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gchar *replacement;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ view = e_html_editor_get_view (editor);
+ editor_selection = e_html_editor_view_get_selection (view);
+
+ selection = gtk_tree_view_get_selection (
+ GTK_TREE_VIEW (dialog->priv->tree_view));
+ gtk_tree_selection_get_selected (selection, &model, &iter);
+ gtk_tree_model_get (model, &iter, 0, &replacement, -1);
+
+ /* Repeatedly search for 'word', then replace selection by
+ * 'replacement'. Repeat until there's at least one occurence of
+ * 'word' in the document */
+ while (webkit_web_view_search_text (
+ WEBKIT_WEB_VIEW (view), dialog->priv->word,
+ FALSE, TRUE, TRUE)) {
+
+ e_html_editor_selection_insert_html (
+ editor_selection, replacement);
+ }
+
+ g_free (replacement);
+ html_editor_spell_check_dialog_next (dialog);
+}
+
+static void
+html_editor_spell_check_dialog_ignore (EHTMLEditorSpellCheckDialog *dialog)
+{
+ if (dialog->priv->word == NULL)
+ return;
+
+ e_spell_dictionary_ignore_word (
+ dialog->priv->current_dict, dialog->priv->word, -1);
+
+ html_editor_spell_check_dialog_next (dialog);
+}
+
+static void
+html_editor_spell_check_dialog_learn (EHTMLEditorSpellCheckDialog *dialog)
+{
+ if (dialog->priv->word == NULL)
+ return;
+
+ e_spell_dictionary_learn_word (
+ dialog->priv->current_dict, dialog->priv->word, -1);
+
+ html_editor_spell_check_dialog_next (dialog);
+}
+
+static void
+html_editor_spell_check_dialog_set_dictionary (EHTMLEditorSpellCheckDialog *dialog)
+{
+ GtkComboBox *combo_box;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ ESpellDictionary *dictionary;
+
+ combo_box = GTK_COMBO_BOX (dialog->priv->dictionary_combo);
+ gtk_combo_box_get_active_iter (combo_box, &iter);
+ model = gtk_combo_box_get_model (combo_box);
+
+ gtk_tree_model_get (model, &iter, 1, &dictionary, -1);
+
+ dialog->priv->current_dict = dictionary;
+
+ /* Update suggestions */
+ html_editor_spell_check_dialog_set_word (dialog, dialog->priv->word);
+}
+
+static void
+html_editor_spell_check_dialog_show (GtkWidget *widget)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorView *view;
+ EHTMLEditorSpellCheckDialog *dialog;
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *window;
+
+ dialog = E_HTML_EDITOR_SPELL_CHECK_DIALOG (widget);
+
+ g_free (dialog->priv->word);
+ dialog->priv->word = NULL;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ view = e_html_editor_get_view (editor);
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
+ window = webkit_dom_document_get_default_view (document);
+ dialog->priv->selection = webkit_dom_dom_window_get_selection (window);
+
+ /* Select the first word or quit */
+ if (html_editor_spell_check_dialog_next (dialog)) {
+ GTK_WIDGET_CLASS (e_html_editor_spell_check_dialog_parent_class)->
+ show (widget);
+ }
+}
+
+static void
+html_editor_spell_check_dialog_finalize (GObject *object)
+{
+ EHTMLEditorSpellCheckDialogPrivate *priv;
+
+ priv = E_HTML_EDITOR_SPELL_CHECK_DIALOG_GET_PRIVATE (object);
+
+ g_free (priv->word);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_html_editor_spell_check_dialog_parent_class)->
+ finalize (object);
+}
+
+static void
+html_editor_spell_check_dialog_constructed (GObject *object)
+{
+ EHTMLEditorSpellCheckDialog *dialog;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_html_editor_spell_check_dialog_parent_class)->
+ constructed (object);
+
+ dialog = E_HTML_EDITOR_SPELL_CHECK_DIALOG (object);
+ e_html_editor_spell_check_dialog_update_dictionaries (dialog);
+}
+
+static void
+e_html_editor_spell_check_dialog_class_init (EHTMLEditorSpellCheckDialogClass *class)
+{
+ GtkWidgetClass *widget_class;
+ GObjectClass *object_class;
+
+ g_type_class_add_private (
+ class, sizeof (EHTMLEditorSpellCheckDialogPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = html_editor_spell_check_dialog_finalize;
+ object_class->constructed = html_editor_spell_check_dialog_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->show = html_editor_spell_check_dialog_show;
+}
+
+static void
+e_html_editor_spell_check_dialog_init (EHTMLEditorSpellCheckDialog *dialog)
+{
+ GtkWidget *widget;
+ GtkGrid *main_layout;
+ GtkListStore *store;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ dialog->priv = E_HTML_EDITOR_SPELL_CHECK_DIALOG_GET_PRIVATE (dialog);
+
+ main_layout = e_html_editor_dialog_get_container (E_HTML_EDITOR_DIALOG (dialog));
+
+ /* == Suggestions == */
+ widget = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (widget), _("<b>Suggestions</b>"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
+ gtk_grid_attach (main_layout, widget, 0, 0, 2, 1);
+ dialog->priv->suggestion_label = widget;
+
+ /* Tree view */
+ widget = gtk_tree_view_new ();
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
+ gtk_widget_set_vexpand (widget, TRUE);
+ gtk_widget_set_hexpand (widget, TRUE);
+ dialog->priv->tree_view = widget;
+
+ /* Column */
+ column = gtk_tree_view_column_new_with_attributes (
+ "", gtk_cell_renderer_text_new (), "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column);
+
+ /* Store */
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (
+ GTK_TREE_VIEW (widget), GTK_TREE_MODEL (store));
+
+ /* Scrolled Window */
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_set_size_request (widget, 150, -1);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_SHADOW_ETCHED_IN);
+ gtk_container_add (GTK_CONTAINER (widget), dialog->priv->tree_view);
+ gtk_grid_attach (main_layout, widget, 0, 1, 1, 5);
+
+ /* Replace */
+ widget = gtk_button_new_with_mnemonic (_("Replace"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_stock (
+ GTK_STOCK_CONVERT, GTK_ICON_SIZE_BUTTON));
+ gtk_grid_attach (main_layout, widget, 1, 1, 1, 1);
+ dialog->priv->replace_button = widget;
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (html_editor_spell_check_dialog_replace), dialog);
+
+ /* Replace All */
+ widget = gtk_button_new_with_mnemonic (_("Replace All"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_stock (
+ GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON));
+ gtk_grid_attach (main_layout, widget, 1, 2, 1, 1);
+ dialog->priv->replace_all_button = widget;
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (html_editor_spell_check_dialog_replace_all), dialog);
+
+ /* Ignore */
+ widget = gtk_button_new_with_mnemonic (_("Ignore"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_stock (
+ GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON));
+ gtk_grid_attach (main_layout, widget, 1, 3, 1, 1);
+ dialog->priv->ignore_button = widget;
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (html_editor_spell_check_dialog_ignore), dialog);
+
+ /* Skip */
+ widget = gtk_button_new_with_mnemonic (_("Skip"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_stock (
+ GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON));
+ gtk_grid_attach (main_layout, widget, 1, 4, 1, 1);
+ dialog->priv->skip_button = widget;
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (html_editor_spell_check_dialog_next), dialog);
+
+ /* Back */
+ widget = gtk_button_new_with_mnemonic (_("Back"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_stock (
+ GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON));
+ gtk_grid_attach (main_layout, widget, 1, 5, 1, 1);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (html_editor_spell_check_dialog_prev), dialog);
+
+ /* Dictionary label */
+ widget = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (widget), _("<b>Dictionary</b>"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 0, 0);
+ gtk_grid_attach (main_layout, widget, 0, 6, 2, 1);
+
+ /* Dictionaries combo */
+ widget = gtk_combo_box_new ();
+ gtk_grid_attach (main_layout, widget, 0, 7, 1, 1);
+ dialog->priv->dictionary_combo = widget;
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (
+ GTK_CELL_LAYOUT (widget), renderer, TRUE);
+ gtk_cell_layout_add_attribute (
+ GTK_CELL_LAYOUT (widget), renderer, "text", 0);
+
+ g_signal_connect_swapped (
+ widget, "changed",
+ G_CALLBACK (html_editor_spell_check_dialog_set_dictionary), dialog);
+
+ /* Add Word button */
+ widget = gtk_button_new_with_mnemonic (_("Add Word"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_stock (
+ GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON));
+ gtk_grid_attach (main_layout, widget, 1, 7, 1, 1);
+ dialog->priv->add_word_button = widget;
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (html_editor_spell_check_dialog_learn), dialog);
+
+ gtk_widget_show_all (GTK_WIDGET (main_layout));
+}
+
+GtkWidget *
+e_html_editor_spell_check_dialog_new (EHTMLEditor *editor)
+{
+ return g_object_new (
+ E_TYPE_HTML_EDITOR_SPELL_CHECK_DIALOG,
+ "editor", editor,
+ "title", N_("Spell Checking"),
+ NULL);
+}
+
+void
+e_html_editor_spell_check_dialog_update_dictionaries (EHTMLEditorSpellCheckDialog *dialog)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorView *view;
+ ESpellChecker *spell_checker;
+ GtkComboBox *combo_box;
+ GtkListStore *store;
+ GQueue queue = G_QUEUE_INIT;
+ gchar **languages;
+ guint n_languages = 0;
+ guint ii;
+
+ g_return_if_fail (E_IS_HTML_EDITOR_SPELL_CHECK_DIALOG (dialog));
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ view = e_html_editor_get_view (editor);
+ spell_checker = e_html_editor_view_get_spell_checker (view);
+
+ languages = e_spell_checker_list_active_languages (
+ spell_checker, &n_languages);
+ for (ii = 0; ii < n_languages; ii++) {
+ ESpellDictionary *dictionary;
+
+ dictionary = e_spell_checker_ref_dictionary (
+ spell_checker, languages[ii]);
+ if (dictionary != NULL)
+ g_queue_push_tail (&queue, dictionary);
+ else
+ g_warning (
+ "%s: No '%s' dictionary found",
+ G_STRFUNC, languages[ii]);
+ }
+ g_strfreev (languages);
+
+ /* Populate a list store for the combo box. */
+ store = gtk_list_store_new (
+ NUM_COLUMNS,
+ G_TYPE_STRING, /* COLUMN_NAME */
+ E_TYPE_SPELL_DICTIONARY); /* COLUMN_DICTIONARY */
+
+ while (!g_queue_is_empty (&queue)) {
+ ESpellDictionary *dictionary;
+ GtkTreeIter iter;
+ const gchar *name;
+
+ dictionary = g_queue_pop_head (&queue);
+ name = e_spell_dictionary_get_name (dictionary);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (
+ store, &iter,
+ COLUMN_NAME, name,
+ COLUMN_DICTIONARY, dictionary,
+ -1);
+
+ g_object_unref (dictionary);
+ }
+
+ /* FIXME Try to restore selection. */
+ combo_box = GTK_COMBO_BOX (dialog->priv->dictionary_combo);
+ gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store));
+ gtk_combo_box_set_active (combo_box, 0);
+
+ g_object_unref (store);
+}
+