Blame gspell/gspell-context-menu.c

Packit aa0600
/*
Packit aa0600
 * This file is part of gspell, a spell-checking library.
Packit aa0600
 *
Packit aa0600
 * Copyright 2016 - Sébastien Wilmet
Packit aa0600
 *
Packit aa0600
 * This library is free software; you can redistribute it and/or
Packit aa0600
 * modify it under the terms of the GNU Lesser General Public
Packit aa0600
 * License as published by the Free Software Foundation; either
Packit aa0600
 * version 2.1 of the License, or (at your option) any later version.
Packit aa0600
 *
Packit aa0600
 * This library is distributed in the hope that it will be useful,
Packit aa0600
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aa0600
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aa0600
 * Lesser General Public License for more details.
Packit aa0600
 *
Packit aa0600
 * You should have received a copy of the GNU Lesser General Public License
Packit aa0600
 * along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit aa0600
 */
Packit aa0600
Packit aa0600
#ifdef HAVE_CONFIG_H
Packit aa0600
#include <config.h>
Packit aa0600
#endif
Packit aa0600
Packit aa0600
#include "gspell-context-menu.h"
Packit aa0600
#include <glib/gi18n-lib.h>
Packit aa0600
Packit aa0600
#define LANGUAGE_DATA_KEY "gspell-language-data-key"
Packit aa0600
#define SUGGESTION_DATA_KEY "gspell-suggestion-data-key"
Packit aa0600
Packit aa0600
typedef struct _LanguageData	LanguageData;
Packit aa0600
typedef struct _SuggestionData	SuggestionData;
Packit aa0600
Packit aa0600
struct _LanguageData
Packit aa0600
{
Packit aa0600
	const GspellLanguage *lang;
Packit aa0600
	GspellLanguageActivatedCallback callback;
Packit aa0600
	gpointer user_data;
Packit aa0600
};
Packit aa0600
Packit aa0600
struct _SuggestionData
Packit aa0600
{
Packit aa0600
	GspellChecker *checker;
Packit aa0600
	gchar *misspelled_word;
Packit aa0600
Packit aa0600
	gchar *suggested_word;
Packit aa0600
	GspellSuggestionActivatedCallback callback;
Packit aa0600
	gpointer user_data;
Packit aa0600
};
Packit aa0600
Packit aa0600
static void
Packit aa0600
suggestion_data_free (gpointer data)
Packit aa0600
{
Packit aa0600
	SuggestionData *suggestion_data = data;
Packit aa0600
Packit aa0600
	if (suggestion_data != NULL)
Packit aa0600
	{
Packit aa0600
		g_clear_object (&suggestion_data->checker);
Packit aa0600
		g_free (suggestion_data->misspelled_word);
Packit aa0600
		g_free (suggestion_data->suggested_word);
Packit aa0600
		g_free (suggestion_data);
Packit aa0600
	}
Packit aa0600
}
Packit aa0600
Packit aa0600
static void
Packit aa0600
activate_language_cb (GtkWidget *menu_item)
Packit aa0600
{
Packit aa0600
	LanguageData *data;
Packit aa0600
Packit aa0600
	data = g_object_get_data (G_OBJECT (menu_item), LANGUAGE_DATA_KEY);
Packit aa0600
	g_return_if_fail (data != NULL);
Packit aa0600
Packit aa0600
	if (data->callback != NULL)
Packit aa0600
	{
Packit aa0600
		data->callback (data->lang, data->user_data);
Packit aa0600
	}
Packit aa0600
}
Packit aa0600
Packit aa0600
static GtkWidget *
Packit aa0600
get_language_menu (const GspellLanguage            *current_language,
Packit aa0600
		   GspellLanguageActivatedCallback  callback,
Packit aa0600
		   gpointer                         user_data)
Packit aa0600
{
Packit aa0600
	GtkWidget *menu;
Packit aa0600
	const GList *languages;
Packit aa0600
	const GList *l;
Packit aa0600
Packit aa0600
	menu = gtk_menu_new ();
Packit aa0600
Packit aa0600
	languages = gspell_language_get_available ();
Packit aa0600
	for (l = languages; l != NULL; l = l->next)
Packit aa0600
	{
Packit aa0600
		const GspellLanguage *lang = l->data;
Packit aa0600
		const gchar *lang_name;
Packit aa0600
		GtkWidget *menu_item;
Packit aa0600
		LanguageData *data;
Packit aa0600
Packit aa0600
		lang_name = gspell_language_get_name (lang);
Packit aa0600
Packit aa0600
		if (lang == current_language)
Packit aa0600
		{
Packit aa0600
			/* Do not create a group. Just mark the current language
Packit aa0600
			 * as active.
Packit aa0600
			 *
Packit aa0600
			 * With a group, the first language in the list gets
Packit aa0600
			 * activated, which changes the GspellChecker language
Packit aa0600
			 * before we arrive to the current_language.
Packit aa0600
			 *
Packit aa0600
			 * Also, having a bullet only for the current_language is
Packit aa0600
			 * sufficient (to be like in Firefox), the menu is
Packit aa0600
			 * anyway ephemeral. No need to have an empty bullet for
Packit aa0600
			 * all the other languages.
Packit aa0600
			 */
Packit aa0600
			menu_item = gtk_radio_menu_item_new_with_label (NULL, lang_name);
Packit aa0600
			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE);
Packit aa0600
		}
Packit aa0600
		else
Packit aa0600
		{
Packit aa0600
			menu_item = gtk_menu_item_new_with_label (lang_name);
Packit aa0600
		}
Packit aa0600
Packit aa0600
		gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
Packit aa0600
Packit aa0600
		data = g_new0 (LanguageData, 1);
Packit aa0600
		data->lang = lang;
Packit aa0600
		data->callback = callback;
Packit aa0600
		data->user_data = user_data;
Packit aa0600
Packit aa0600
		g_object_set_data_full (G_OBJECT (menu_item),
Packit aa0600
					LANGUAGE_DATA_KEY,
Packit aa0600
					data,
Packit aa0600
					g_free);
Packit aa0600
Packit aa0600
		g_signal_connect (menu_item,
Packit aa0600
				  "activate",
Packit aa0600
				  G_CALLBACK (activate_language_cb),
Packit aa0600
				  NULL);
Packit aa0600
	}
Packit aa0600
Packit aa0600
	return menu;
Packit aa0600
}
Packit aa0600
Packit aa0600
GtkMenuItem *
Packit aa0600
_gspell_context_menu_get_language_menu_item (const GspellLanguage            *current_language,
Packit aa0600
					     GspellLanguageActivatedCallback  callback,
Packit aa0600
					     gpointer                         user_data)
Packit aa0600
{
Packit aa0600
	GtkWidget *lang_menu;
Packit aa0600
	GtkMenuItem *menu_item;
Packit aa0600
Packit aa0600
	lang_menu = get_language_menu (current_language, callback, user_data);
Packit aa0600
Packit aa0600
	menu_item = GTK_MENU_ITEM (gtk_menu_item_new_with_mnemonic (_("_Language")));
Packit aa0600
	gtk_menu_item_set_submenu (menu_item, lang_menu);
Packit aa0600
	gtk_widget_show_all (GTK_WIDGET (menu_item));
Packit aa0600
Packit aa0600
	return menu_item;
Packit aa0600
}
Packit aa0600
Packit aa0600
static void
Packit aa0600
activate_suggestion_cb (GtkWidget *menu_item)
Packit aa0600
{
Packit aa0600
	SuggestionData *data;
Packit aa0600
Packit aa0600
	data = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_DATA_KEY);
Packit aa0600
	g_return_if_fail (data != NULL);
Packit aa0600
Packit aa0600
	if (data->callback != NULL)
Packit aa0600
	{
Packit aa0600
		data->callback (data->suggested_word, data->user_data);
Packit aa0600
	}
Packit aa0600
}
Packit aa0600
Packit aa0600
static void
Packit aa0600
ignore_all_cb (GtkWidget *menu_item)
Packit aa0600
{
Packit aa0600
	SuggestionData *data;
Packit aa0600
Packit aa0600
	data = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_DATA_KEY);
Packit aa0600
	g_return_if_fail (data != NULL);
Packit aa0600
Packit aa0600
	gspell_checker_add_word_to_session (data->checker,
Packit aa0600
					    data->misspelled_word,
Packit aa0600
					    -1);
Packit aa0600
}
Packit aa0600
Packit aa0600
static void
Packit aa0600
add_to_dictionary_cb (GtkWidget *menu_item)
Packit aa0600
{
Packit aa0600
	SuggestionData *data;
Packit aa0600
Packit aa0600
	data = g_object_get_data (G_OBJECT (menu_item), SUGGESTION_DATA_KEY);
Packit aa0600
	g_return_if_fail (data != NULL);
Packit aa0600
Packit aa0600
	gspell_checker_add_word_to_personal (data->checker,
Packit aa0600
					     data->misspelled_word,
Packit aa0600
					     -1);
Packit aa0600
}
Packit aa0600
Packit aa0600
static GtkWidget *
Packit aa0600
get_suggestion_menu (GspellChecker                     *checker,
Packit aa0600
		     const gchar                       *misspelled_word,
Packit aa0600
		     GspellSuggestionActivatedCallback  callback,
Packit aa0600
		     gpointer                           user_data)
Packit aa0600
{
Packit aa0600
	GtkWidget *top_menu;
Packit aa0600
	GtkWidget *menu_item;
Packit aa0600
	GSList *suggestions = NULL;
Packit aa0600
	SuggestionData *data;
Packit aa0600
Packit aa0600
	top_menu = gtk_menu_new ();
Packit aa0600
Packit aa0600
	suggestions = gspell_checker_get_suggestions (checker, misspelled_word, -1);
Packit aa0600
Packit aa0600
	if (suggestions == NULL)
Packit aa0600
	{
Packit aa0600
		/* No suggestions. Put something in the menu anyway... */
Packit aa0600
		menu_item = gtk_menu_item_new_with_label (_("(no suggested words)"));
Packit aa0600
		gtk_widget_set_sensitive (menu_item, FALSE);
Packit aa0600
		gtk_menu_shell_prepend (GTK_MENU_SHELL (top_menu), menu_item);
Packit aa0600
	}
Packit aa0600
	else
Packit aa0600
	{
Packit aa0600
		GtkWidget *menu = top_menu;
Packit aa0600
		gint count = 0;
Packit aa0600
		GSList *l;
Packit aa0600
Packit aa0600
		/* Build a set of menus with suggestions. */
Packit aa0600
		for (l = suggestions; l != NULL; l = l->next)
Packit aa0600
		{
Packit aa0600
			gchar *suggested_word = l->data;
Packit aa0600
			GtkWidget *label;
Packit aa0600
			gchar *label_text;
Packit aa0600
Packit aa0600
			if (count == 10)
Packit aa0600
			{
Packit aa0600
				/* Separator */
Packit aa0600
				menu_item = gtk_separator_menu_item_new ();
Packit aa0600
				gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
Packit aa0600
Packit aa0600
				menu_item = gtk_menu_item_new_with_mnemonic (_("_More…"));
Packit aa0600
				gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
Packit aa0600
Packit aa0600
				menu = gtk_menu_new ();
Packit aa0600
				gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
Packit aa0600
				count = 0;
Packit aa0600
			}
Packit aa0600
Packit aa0600
			label_text = g_strdup_printf ("%s", suggested_word);
Packit aa0600
Packit aa0600
			label = gtk_label_new (label_text);
Packit aa0600
			gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
Packit aa0600
			gtk_widget_set_halign (label, GTK_ALIGN_START);
Packit aa0600
Packit aa0600
			menu_item = gtk_menu_item_new ();
Packit aa0600
			gtk_container_add (GTK_CONTAINER (menu_item), label);
Packit aa0600
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
Packit aa0600
Packit aa0600
			data = g_new0 (SuggestionData, 1);
Packit aa0600
			data->suggested_word = g_strdup (suggested_word);
Packit aa0600
			data->callback = callback;
Packit aa0600
			data->user_data = user_data;
Packit aa0600
Packit aa0600
			g_object_set_data_full (G_OBJECT (menu_item),
Packit aa0600
						SUGGESTION_DATA_KEY,
Packit aa0600
						data,
Packit aa0600
						suggestion_data_free);
Packit aa0600
Packit aa0600
			g_signal_connect (menu_item,
Packit aa0600
					  "activate",
Packit aa0600
					  G_CALLBACK (activate_suggestion_cb),
Packit aa0600
					  NULL);
Packit aa0600
Packit aa0600
			g_free (label_text);
Packit aa0600
			count++;
Packit aa0600
		}
Packit aa0600
	}
Packit aa0600
Packit aa0600
	g_slist_free_full (suggestions, g_free);
Packit aa0600
Packit aa0600
	/* Separator */
Packit aa0600
	menu_item = gtk_separator_menu_item_new ();
Packit aa0600
	gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
Packit aa0600
Packit aa0600
	/* Ignore all */
Packit aa0600
	menu_item = gtk_menu_item_new_with_mnemonic (_("_Ignore All"));
Packit aa0600
	gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
Packit aa0600
Packit aa0600
	data = g_new0 (SuggestionData, 1);
Packit aa0600
	data->checker = g_object_ref (checker);
Packit aa0600
	data->misspelled_word = g_strdup (misspelled_word);
Packit aa0600
Packit aa0600
	g_object_set_data_full (G_OBJECT (menu_item),
Packit aa0600
				SUGGESTION_DATA_KEY,
Packit aa0600
				data,
Packit aa0600
				suggestion_data_free);
Packit aa0600
Packit aa0600
	g_signal_connect (menu_item,
Packit aa0600
			  "activate",
Packit aa0600
			  G_CALLBACK (ignore_all_cb),
Packit aa0600
			  NULL);
Packit aa0600
Packit aa0600
	/* Add to Dictionary */
Packit aa0600
	menu_item = gtk_menu_item_new_with_mnemonic (_("_Add"));
Packit aa0600
	gtk_menu_shell_append (GTK_MENU_SHELL (top_menu), menu_item);
Packit aa0600
Packit aa0600
	data = g_new0 (SuggestionData, 1);
Packit aa0600
	data->checker = g_object_ref (checker);
Packit aa0600
	data->misspelled_word = g_strdup (misspelled_word);
Packit aa0600
Packit aa0600
	g_object_set_data_full (G_OBJECT (menu_item),
Packit aa0600
				SUGGESTION_DATA_KEY,
Packit aa0600
				data,
Packit aa0600
				suggestion_data_free);
Packit aa0600
Packit aa0600
	g_signal_connect (menu_item,
Packit aa0600
			  "activate",
Packit aa0600
			  G_CALLBACK (add_to_dictionary_cb),
Packit aa0600
			  NULL);
Packit aa0600
Packit aa0600
	return top_menu;
Packit aa0600
}
Packit aa0600
Packit aa0600
GtkMenuItem *
Packit aa0600
_gspell_context_menu_get_suggestions_menu_item (GspellChecker                     *checker,
Packit aa0600
						const gchar                       *misspelled_word,
Packit aa0600
						GspellSuggestionActivatedCallback  callback,
Packit aa0600
						gpointer                           user_data)
Packit aa0600
{
Packit aa0600
	GtkWidget *suggestion_menu;
Packit aa0600
	GtkMenuItem *menu_item;
Packit aa0600
Packit aa0600
	g_return_val_if_fail (GSPELL_IS_CHECKER (checker), NULL);
Packit aa0600
	g_return_val_if_fail (misspelled_word != NULL, NULL);
Packit aa0600
Packit aa0600
	suggestion_menu = get_suggestion_menu (checker,
Packit aa0600
					       misspelled_word,
Packit aa0600
					       callback,
Packit aa0600
					       user_data);
Packit aa0600
Packit aa0600
	menu_item = GTK_MENU_ITEM (gtk_menu_item_new_with_mnemonic (_("_Spelling Suggestions…")));
Packit aa0600
	gtk_menu_item_set_submenu (menu_item, suggestion_menu);
Packit aa0600
	gtk_widget_show_all (GTK_WIDGET (menu_item));
Packit aa0600
Packit aa0600
	return menu_item;
Packit aa0600
}
Packit aa0600
Packit aa0600
/* ex:set ts=8 noet: */