aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-html-editor-spell-check-dialog.c
blob: 5d632a1290832474fef1bd1594be697eb1f80758 (plain) (tree)
































                                                                          

                             














































































































































































































































































































































































                                                                                             

                                                               
 
                                                                      
 
                                                        
 


                                                                                     

















































                                                                                  
                                                                                             







































































                                                                                         
                                                                                   








                                                                             







                                                                                 
                                                                           







                                                                            
                                                                      







                                                                          
                                                                          



























                                                                                    
                                                                           






















































































                                                                                          
/*
 * 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"

#include "e-dialog-widgets.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);
    if (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 = e_dialog_button_new_with_icon ("edit-find-replace", _("Replace"));
    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_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 = e_dialog_button_new_with_icon ("edit-clear", _("Ignore"));
    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 = e_dialog_button_new_with_icon ("go-next", _("Skip"));
    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 = e_dialog_button_new_with_icon ("go-previous", _("Back"));
    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 = e_dialog_button_new_with_icon ("list-add", _("Add word"));
    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);
}