Commit 6a0409a9 authored by Milan Crha's avatar Milan Crha

Bug 561799 - Simplify language selection in message composer

Closes https://bugzilla.gnome.org/show_bug.cgi?id=561799
parent 55d34104
......@@ -125,6 +125,15 @@
<_summary>Spell checking languages</_summary>
<_description>List of dictionary language codes used for spell checking.</_description>
</key>
<key name="composer-spell-languages-recently-used" type="as">
<default>[]</default>
<_summary>List of recently used spell checking languages</_summary>
<_description>List of dictionary language codes used for spell checking, which had been used recently.</_description>
</key>
<key name="composer-spell-languages-max-recently-used" type="i">
<default>5</default>
<_summary>How many recently used spell checking languages to remember</_summary>
</key>
<key name="composer-show-bcc" type="b">
<default>false</default>
<_summary>Show “Bcc” field when sending a mail message</_summary>
......
......@@ -440,6 +440,10 @@ action_insert_text_file_cb (GtkAction *action,
gtk_widget_destroy (dialog);
}
static gboolean
editor_actions_add_to_recent_languages (EHTMLEditor *editor,
const gchar *language_code);
static void
action_language_cb (GtkToggleAction *toggle_action,
EHTMLEditor *editor)
......@@ -468,6 +472,41 @@ action_language_cb (GtkToggleAction *toggle_action,
e_html_editor_update_spell_actions (editor);
g_signal_emit_by_name (editor, "spell-languages-changed");
if (active) {
GSettings *settings;
GPtrArray *array;
gchar **strv;
gint ii, max_items;
gtk_ui_manager_remove_ui (editor->priv->manager, editor->priv->recent_spell_languages_merge_id);
settings = e_util_ref_settings ("org.gnome.evolution.mail");
strv = g_settings_get_strv (settings, "composer-spell-languages-recently-used");
max_items = g_settings_get_int (settings, "composer-spell-languages-max-recently-used");
if (max_items < 5)
max_items = 5;
array = g_ptr_array_sized_new (max_items + 1);
g_ptr_array_add (array, (gpointer) language_code);
editor_actions_add_to_recent_languages (editor, language_code);
for (ii = 0; strv && strv[ii] && array->len < max_items; ii++) {
if (g_strcmp0 (language_code, strv[ii]) != 0) {
g_ptr_array_add (array, strv[ii]);
editor_actions_add_to_recent_languages (editor, strv[ii]);
}
}
g_ptr_array_add (array, NULL);
g_settings_set_strv (settings, "composer-spell-languages-recently-used", (const gchar * const *) array->pdata);
g_object_unref (settings);
g_ptr_array_free (array, TRUE);
g_strfreev (strv);
}
}
static gboolean
......@@ -1606,6 +1645,49 @@ static GtkActionEntry spell_context_entries[] = {
NULL }
};
static gboolean
editor_actions_add_to_recent_languages (EHTMLEditor *editor,
const gchar *language_code)
{
GtkAction *language_action;
gchar *name;
g_return_val_if_fail (E_IS_HTML_EDITOR (editor), FALSE);
g_return_val_if_fail (language_code != NULL, FALSE);
language_action = gtk_action_group_get_action (editor->priv->language_actions, language_code);
if (!language_action)
return FALSE;
name = g_strconcat ("recent-spell-language-", language_code, NULL);
if (!gtk_action_group_get_action (editor->priv->language_actions, name)) {
GtkToggleAction *toggle_action;
toggle_action = gtk_toggle_action_new (name,
gtk_action_get_label (language_action),
gtk_action_get_tooltip (language_action),
NULL);
e_binding_bind_property (language_action, "active",
toggle_action, "active",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
gtk_action_group_add_action (editor->priv->language_actions, GTK_ACTION (toggle_action));
g_object_unref (toggle_action);
}
gtk_ui_manager_add_ui (
editor->priv->manager, editor->priv->recent_spell_languages_merge_id,
"/main-menu/edit-menu/language-menu/recent-languages",
name, name, GTK_UI_MANAGER_AUTO, FALSE);
g_free (name);
return TRUE;
}
static void
editor_actions_setup_languages_menu (EHTMLEditor *editor)
{
......@@ -1613,31 +1695,52 @@ editor_actions_setup_languages_menu (EHTMLEditor *editor)
EContentEditor *cnt_editor;
GtkUIManager *manager;
GtkActionGroup *action_group;
GHashTable *lang_parents; /* gchar *name ~> GtkAction * */
GList *list = NULL, *link;
GSettings *settings;
gchar **strv;
gint ii, added = 0, max_items;
guint merge_id;
lang_parents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
manager = editor->priv->manager;
action_group = editor->priv->language_actions;
cnt_editor = e_html_editor_get_content_editor (editor);
spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
merge_id = gtk_ui_manager_new_merge_id (manager);
editor->priv->recent_spell_languages_merge_id = gtk_ui_manager_new_merge_id (manager);
list = e_spell_checker_list_available_dicts (spell_checker);
for (link = list; link != NULL; link = g_list_next (link)) {
ESpellDictionary *dictionary = link->data;
GtkAction *parent_action;
GtkToggleAction *action;
const gchar *language_name;
const gchar *dictionay_name;
gchar *language_name, *path;
GString *escaped_name = NULL;
gboolean active = FALSE;
language_name = e_spell_dictionary_get_name (dictionary);
if (language_name && strchr (language_name, '_') != NULL)
escaped_name = e_str_replace_string (language_name, "_", "__");
if (!e_util_get_language_info (e_spell_dictionary_get_code (dictionary), &language_name, NULL)) {
language_name = g_strdup (e_spell_dictionary_get_code (dictionary));
if (language_name) {
gchar *ptr;
ptr = strchr (language_name, '_');
if (ptr)
*ptr = '\0';
} else {
language_name = g_strdup ("");
}
}
dictionay_name = e_spell_dictionary_get_name (dictionary);
if (dictionay_name && strchr (dictionay_name, '_') != NULL)
escaped_name = e_str_replace_string (dictionay_name, "_", "__");
action = gtk_toggle_action_new (
e_spell_dictionary_get_code (dictionary),
escaped_name ? escaped_name->str : language_name,
escaped_name ? escaped_name->str : dictionay_name,
NULL, NULL);
if (escaped_name)
......@@ -1659,16 +1762,63 @@ editor_actions_setup_languages_menu (EHTMLEditor *editor)
g_object_unref (action);
parent_action = g_hash_table_lookup (lang_parents, language_name);
if (!parent_action) {
gchar *name, *tmp;
name = g_strdup (e_spell_dictionary_get_code (dictionary));
tmp = strchr (name, '_');
if (tmp)
*tmp = '\0';
tmp = g_strconcat ("language-parent-", name, NULL);
g_free (name);
name = tmp;
parent_action = gtk_action_new (name, language_name, NULL, NULL);
gtk_action_group_add_action (action_group, parent_action);
g_hash_table_insert (lang_parents, g_strdup (language_name), parent_action);
gtk_ui_manager_add_ui (
manager, merge_id,
"/main-menu/edit-menu/language-menu/all-languages",
name, name, GTK_UI_MANAGER_MENU, FALSE);
g_free (name);
}
path = g_strconcat ("/main-menu/edit-menu/language-menu/all-languages/", gtk_action_get_name (parent_action), NULL);
gtk_ui_manager_add_ui (
manager, merge_id,
"/main-menu/edit-menu/language-menu",
path,
e_spell_dictionary_get_code (dictionary),
e_spell_dictionary_get_code (dictionary),
GTK_UI_MANAGER_AUTO, FALSE);
g_free (language_name);
g_free (path);
}
g_list_free (list);
g_clear_object (&spell_checker);
g_hash_table_destroy (lang_parents);
settings = e_util_ref_settings ("org.gnome.evolution.mail");
strv = g_settings_get_strv (settings, "composer-spell-languages-recently-used");
max_items = g_settings_get_int (settings, "composer-spell-languages-max-recently-used");
if (max_items < 5)
max_items = 5;
g_object_unref (settings);
for (ii = 0; strv && strv[ii] && added < max_items; ii++) {
if (editor_actions_add_to_recent_languages (editor, strv[ii]))
added++;
}
g_strfreev (strv);
}
static void
......@@ -2024,6 +2174,10 @@ editor_actions_update_spellcheck_languages_menu (EHTMLEditor *editor,
if (!GTK_IS_TOGGLE_ACTION (link->data))
continue;
if (gtk_action_get_name (link->data) &&
g_str_has_prefix (gtk_action_get_name (link->data), "recent-spell-language-"))
continue;
is_active = g_hash_table_contains (active, gtk_action_get_name (link->data));
toggle_action = GTK_TOGGLE_ACTION (link->data);
......
......@@ -22,7 +22,11 @@
<separator/>
<placeholder name='pre-spell-check'/>
<menuitem action='spell-check'/>
<menu action='language-menu'/>
<menu action='language-menu'>
<placeholder name='recent-languages'/>
<separator/>
<placeholder name='all-languages'/>
</menu>
</menu>
<placeholder name='pre-insert-menu'>
<menu action='view-menu'>
......
......@@ -89,6 +89,7 @@ struct _EHTMLEditorPrivate {
gchar *filename;
guint spell_suggestions_merge_id;
guint recent_spell_languages_merge_id;
gint editor_layout_row;
......
......@@ -4416,30 +4416,49 @@ iso_codes_parse (const GMarkupParser *parser,
#endif /* HAVE_ISO_CODES */
/**
* e_util_get_language_name:
* @language_tag: Language tag to get its name for
* e_util_get_language_info:
* @language_tag: Language tag to get its name for, like "en_US"
* @out_language_name: (out) (nullable) (transfer full): Return location for the language name, or %NULL
* @out_country_name: (out) (nullable) (transfer full): Return location for the country name, or %NULL
*
* Returns: (transfer full): Newly allocated string with localized language name
* Splits language tag into a localized language name and country name (the variant).
* The @out_language_name is always filled when the function returns %TRUE, but
* the @out_countr_name can be %NULL. That's for cases when the @language_tag
* contains only the country part, like "en".
*
* The function returns %FALSE when it could not decode language name from
* the given @language_tag. When either of the @out_language_name and @out_country_name
* is non-NULL and the function returns %TRUE, then their respective values
* should be freed with g_free(), when no longer needed.
*
* Returns: %TRUE, when could get at least language name from the @language_tag,
* %FALSE otherwise.
*
* Since: 3.32
**/
gchar *
e_util_get_language_name (const gchar *language_tag)
gboolean
e_util_get_language_info (const gchar *language_tag,
gchar **out_language_name,
gchar **out_country_name)
{
const gchar *iso_639_name;
const gchar *iso_3166_name;
gchar *language_name;
gchar *lowercase;
gchar **tokens;
g_return_val_if_fail (language_tag != NULL, NULL);
g_return_val_if_fail (language_tag != NULL, FALSE);
if (out_language_name)
*out_language_name = NULL;
if (out_country_name)
*out_country_name = NULL;
/* Split language code into lowercase tokens. */
lowercase = g_ascii_strdown (language_tag, -1);
tokens = g_strsplit (lowercase, "_", -1);
g_free (lowercase);
g_return_val_if_fail (tokens != NULL, NULL);
g_return_val_if_fail (tokens != NULL, FALSE);
if (!iso_639_table && !iso_3166_table) {
#if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
......@@ -4472,46 +4491,77 @@ e_util_get_language_name (const gchar *language_tag)
iso_639_name = g_hash_table_lookup (iso_639_table, tokens[0]);
if (iso_639_name == NULL) {
language_name = g_strdup_printf (
/* Translators: %s is the language ISO code. */
C_("language", "Unknown (%s)"), language_tag);
goto exit;
if (!iso_639_name) {
g_strfreev (tokens);
return FALSE;
}
if (g_strv_length (tokens) < 2) {
language_name = g_strdup (iso_639_name);
if (out_language_name)
*out_language_name = g_strdup (iso_639_name);
if (g_strv_length (tokens) < 2)
goto exit;
}
iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
if (out_country_name) {
iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
if (iso_3166_name != NULL)
language_name = g_strdup_printf (
/* Translators: The first %s is the language name, and the
* second is the country name. Example: "French (France)" */
C_("language", "%s (%s)"), iso_639_name, iso_3166_name);
else
language_name = g_strdup_printf (
/* Translators: The first %s is the language name, and the
* second is the country name. Example: "French (France)" */
C_("language", "%s (%s)"), iso_639_name, tokens[1]);
if (iso_3166_name)
*out_country_name = g_strdup (iso_3166_name);
else
*out_country_name = g_strdup (tokens[1]);
}
exit:
g_strfreev (tokens);
if (language_name) {
if (out_country_name && *out_country_name) {
gchar *ptr;
/* When the name has two or more ';' then strip the string at the second of them */
ptr = strchr (language_name, ';');
/* When the country name has two or more ';' then strip the string at the second of them */
ptr = strchr (*out_country_name, ';');
if (ptr)
ptr = strchr (ptr + 1, ';');
if (ptr)
*ptr = '\0';
}
return language_name;
g_strfreev (tokens);
return TRUE;
}
/**
* e_util_get_language_name:
* @language_tag: Language tag to get its name for, like "en_US"
*
* Returns: (transfer full): Newly allocated string with localized language name
*
* Since: 3.32
**/
gchar *
e_util_get_language_name (const gchar *language_tag)
{
gchar *language_name = NULL, *country_name = NULL;
gchar *res;
g_return_val_if_fail (language_tag != NULL, NULL);
if (!e_util_get_language_info (language_tag, &language_name, &country_name)) {
return g_strdup_printf (
/* Translators: %s is the language ISO code. */
C_("language", "Unknown (%s)"), language_tag);
}
if (!country_name)
return language_name;
res = g_strdup_printf (
/* Translators: The first %s is the language name, and the
* second is the country name. Example: "French (France)" */
C_("language", "%s (%s)"), language_name, country_name);
g_free (language_name);
g_free (country_name);
return res;
}
/**
......
......@@ -348,6 +348,9 @@ gboolean e_util_query_ldap_root_dse_sync (const gchar *host,
GCancellable *cancellable,
GError **error);
gchar * e_util_get_language_name (const gchar *language_tag);
gboolean e_util_get_language_info (const gchar *language_tag,
gchar **out_language_name,
gchar **out_country_name);
void e_misc_util_free_global_memory (void);
G_END_DECLS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment