[gnome-builder/wip/gtk4-port: 1654/1774] plugins/spellcheck: import changes from Text Editor




commit 0f4c8b1ed122d198ce0c258519fe7a60508c02be
Author: Christian Hergert <chergert redhat com>
Date:   Fri Jun 24 14:38:26 2022 -0700

    plugins/spellcheck: import changes from Text Editor

 .../spellcheck/editor-enchant-spell-provider.c     | 60 ++++++++++++----
 .../spellcheck/editor-spell-language-info.c        | 30 +++++++-
 .../spellcheck/editor-spell-language-info.h        | 10 +--
 src/plugins/spellcheck/editor-spell-menu.c         | 80 +++++++++++++++++++---
 4 files changed, 150 insertions(+), 30 deletions(-)
---
diff --git a/src/plugins/spellcheck/editor-enchant-spell-provider.c 
b/src/plugins/spellcheck/editor-enchant-spell-provider.c
index fb722c57b..1949013ce 100644
--- a/src/plugins/spellcheck/editor-enchant-spell-provider.c
+++ b/src/plugins/spellcheck/editor-enchant-spell-provider.c
@@ -50,6 +50,31 @@ get_broker (void)
   return broker;
 }
 
+static char *
+_icu_uchar_to_char (const UChar *input,
+                    gsize        max_input_len)
+{
+  GString *str;
+
+  g_assert (input != NULL);
+  g_assert (max_input_len > 0);
+
+  if (input[0] == 0)
+    return NULL;
+
+  str = g_string_new (NULL);
+
+  for (gsize i = 0; i < max_input_len; i++)
+    {
+      if (input[i] == 0)
+        break;
+
+      g_string_append_unichar (str, input[i]);
+    }
+
+  return g_string_free (str, FALSE);
+}
+
 static char *
 get_display_name (const char *code)
 {
@@ -59,20 +84,26 @@ get_display_name (const char *code)
     {
       UChar ret[256];
       UErrorCode status = U_ZERO_ERROR;
-
-      ret[0] = 0;
       uloc_getDisplayName (code, names[i], ret, G_N_ELEMENTS (ret), &status);
-      ret[G_N_ELEMENTS (ret)-1] = 0;
+      if (status == U_ZERO_ERROR)
+        return _icu_uchar_to_char (ret, G_N_ELEMENTS (ret));
+    }
 
-      if (status == U_ZERO_ERROR && ret[0] != 0)
-        {
-          GString *str = g_string_new (NULL);
+  return NULL;
+}
 
-          for (guint j = 0; ret[j]; j++)
-            g_string_append_unichar (str, ret[j]);
+static char *
+get_display_language (const char *code)
+{
+  const char * const *names = g_get_language_names ();
 
-          return g_string_free (str, FALSE);
-        }
+  for (guint i = 0; names[i]; i++)
+    {
+      UChar ret[256];
+      UErrorCode status = U_ZERO_ERROR;
+      uloc_getDisplayLanguage (code, names[i], ret, G_N_ELEMENTS (ret), &status);
+      if (status == U_ZERO_ERROR)
+        return _icu_uchar_to_char (ret, G_N_ELEMENTS (ret));
     }
 
   return NULL;
@@ -112,12 +143,13 @@ list_languages_cb (const char * const  lang_tag,
 {
   GPtrArray *ar = user_data;
   char *name = get_display_name (lang_tag);
+  char *group = get_display_language (lang_tag);
 
   if (name != NULL)
-    {
-      g_ptr_array_add (ar, editor_spell_language_info_new (name, lang_tag));
-      g_free (name);
-    }
+    g_ptr_array_add (ar, editor_spell_language_info_new (name, lang_tag, group));
+
+  g_free (name);
+  g_free (group);
 }
 
 static GPtrArray *
diff --git a/src/plugins/spellcheck/editor-spell-language-info.c 
b/src/plugins/spellcheck/editor-spell-language-info.c
index 8bc4ceb21..7d4095c6d 100644
--- a/src/plugins/spellcheck/editor-spell-language-info.c
+++ b/src/plugins/spellcheck/editor-spell-language-info.c
@@ -27,6 +27,7 @@ struct _EditorSpellLanguageInfo
   GObject parent_instance;
   char *name;
   char *code;
+  char *group;
 };
 
 G_DEFINE_TYPE (EditorSpellLanguageInfo, editor_spell_language_info, G_TYPE_OBJECT)
@@ -34,6 +35,7 @@ G_DEFINE_TYPE (EditorSpellLanguageInfo, editor_spell_language_info, G_TYPE_OBJEC
 enum {
   PROP_0,
   PROP_CODE,
+  PROP_GROUP,
   PROP_NAME,
   N_PROPS
 };
@@ -49,11 +51,13 @@ static GParamSpec *properties [N_PROPS];
  */
 EditorSpellLanguageInfo *
 editor_spell_language_info_new (const char *name,
-                                const char *code)
+                                const char *code,
+                                const char *group)
 {
   return g_object_new (EDITOR_TYPE_SPELL_LANGUAGE_INFO,
                        "name", name,
                        "code", code,
+                       "group", group,
                        NULL);
 }
 
@@ -64,6 +68,7 @@ editor_spell_language_info_finalize (GObject *object)
 
   g_clear_pointer (&self->name, g_free);
   g_clear_pointer (&self->code, g_free);
+  g_clear_pointer (&self->group, g_free);
 
   G_OBJECT_CLASS (editor_spell_language_info_parent_class)->finalize (object);
 }
@@ -86,6 +91,10 @@ editor_spell_language_info_get_property (GObject    *object,
       g_value_set_string (value, editor_spell_language_info_get_code (self));
       break;
 
+    case PROP_GROUP:
+      g_value_set_string (value, editor_spell_language_info_get_group (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -109,6 +118,10 @@ editor_spell_language_info_set_property (GObject      *object,
       self->code = g_value_dup_string (value);
       break;
 
+    case PROP_GROUP:
+      self->group = g_value_dup_string (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -137,6 +150,13 @@ editor_spell_language_info_class_init (EditorSpellLanguageInfoClass *klass)
                          NULL,
                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_GROUP] =
+    g_param_spec_string ("group",
+                         "Group",
+                         "A group for sorting, usually the country name",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
@@ -160,3 +180,11 @@ editor_spell_language_info_get_code (EditorSpellLanguageInfo *self)
 
   return self->code;
 }
+
+const char *
+editor_spell_language_info_get_group (EditorSpellLanguageInfo *self)
+{
+  g_return_val_if_fail (EDITOR_IS_SPELL_LANGUAGE_INFO (self), NULL);
+
+  return self->group;
+}
diff --git a/src/plugins/spellcheck/editor-spell-language-info.h 
b/src/plugins/spellcheck/editor-spell-language-info.h
index a84426168..ede69b8cd 100644
--- a/src/plugins/spellcheck/editor-spell-language-info.h
+++ b/src/plugins/spellcheck/editor-spell-language-info.h
@@ -28,9 +28,11 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (EditorSpellLanguageInfo, editor_spell_language_info, EDITOR, SPELL_LANGUAGE_INFO, 
GObject)
 
-EditorSpellLanguageInfo *editor_spell_language_info_new      (const char              *name,
-                                                              const char              *code);
-const char              *editor_spell_language_info_get_name (EditorSpellLanguageInfo *self);
-const char              *editor_spell_language_info_get_code (EditorSpellLanguageInfo *self);
+EditorSpellLanguageInfo *editor_spell_language_info_new       (const char              *name,
+                                                               const char              *code,
+                                                               const char              *group);
+const char              *editor_spell_language_info_get_group (EditorSpellLanguageInfo *self);
+const char              *editor_spell_language_info_get_name  (EditorSpellLanguageInfo *self);
+const char              *editor_spell_language_info_get_code  (EditorSpellLanguageInfo *self);
 
 G_END_DECLS
diff --git a/src/plugins/spellcheck/editor-spell-menu.c b/src/plugins/spellcheck/editor-spell-menu.c
index 5baadc97a..c1ee5a5ad 100644
--- a/src/plugins/spellcheck/editor-spell-menu.c
+++ b/src/plugins/spellcheck/editor-spell-menu.c
@@ -161,38 +161,103 @@ editor_spell_corrections_new (void)
   return g_object_new (EDITOR_TYPE_SPELL_CORRECTIONS, NULL);
 }
 
+static int
+count_groups (GPtrArray *infos)
+{
+  g_autoptr(GHashTable) groups = g_hash_table_new (g_str_hash, g_str_equal);
+
+  g_assert (infos != NULL);
+
+  for (guint i = 0; i < infos->len; i++)
+    {
+      EditorSpellLanguageInfo *info = g_ptr_array_index (infos, i);
+      const char *group = editor_spell_language_info_get_group (info);
+
+      if (group != NULL && group[0] != 0 && !g_hash_table_contains (groups, group))
+        g_hash_table_insert (groups, (char *)group, NULL);
+    }
+
+  return g_hash_table_size (groups);
+}
+
 static void
 populate_languages (GMenu *menu)
 {
   EditorSpellProvider *provider = editor_spell_provider_get_default ();
   g_autoptr(GPtrArray) infos = editor_spell_provider_list_languages (provider);
+  g_autoptr(GHashTable) groups = NULL;
 
   if (infos == NULL)
     return;
 
+  groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+  /* First setup our groups. We do that up front so we can avoid
+   * checking below, but also so we can hoist a single group up
+   * into the parent menu if necessary.
+   */
+  if (count_groups (infos) > 1)
+    {
+      for (guint i = 0; i < infos->len; i++)
+        {
+          EditorSpellLanguageInfo *info = g_ptr_array_index (infos, i);
+          const char *group = editor_spell_language_info_get_group (info);
+          GMenu *group_menu;
+
+          if (group == NULL || group[0] == 0)
+            continue;
+
+          if (!g_hash_table_contains (groups, group))
+            {
+              group_menu = g_menu_new ();
+              g_menu_append_submenu (menu, group, G_MENU_MODEL (group_menu));
+              g_hash_table_insert (groups,
+                                   g_strdup (group),
+                                   g_steal_pointer (&group_menu));
+            }
+        }
+    }
+
   for (guint i = 0; i < infos->len; i++)
     {
       EditorSpellLanguageInfo *info = g_ptr_array_index (infos, i);
       const char *name = editor_spell_language_info_get_name (info);
+      const char *group = editor_spell_language_info_get_group (info);
       const char *code = editor_spell_language_info_get_code (info);
-      g_autoptr(GMenuItem) item = g_menu_item_new (name, NULL);
+      g_autoptr(GMenuItem) item = NULL;
+      GMenu *group_menu;
+
+      if (group == NULL || !(group_menu = g_hash_table_lookup (groups, group)))
+        group_menu = menu;
 
+      g_assert (G_IS_MENU (group_menu));
+
+      item = g_menu_item_new (name, NULL);
       g_menu_item_set_action_and_target (item, "spelling.language", "s", code);
-      g_menu_append_item (menu, item);
+      g_menu_append_item (group_menu, item);
     }
 }
 
 GMenuModel *
 editor_spell_menu_new (void)
 {
+  static GMenu *languages_menu;
+  static GMenuItem *languages_item;
   g_autoptr(GMenu) menu = g_menu_new ();
   g_autoptr(GMenuModel) corrections_menu = editor_spell_corrections_new ();
-  g_autoptr(GMenu) languages_menu = g_menu_new ();
-  g_autoptr(GMenuItem) languages_item = g_menu_item_new_submenu (_("Languages"), G_MENU_MODEL 
(languages_menu));
   g_autoptr(GMenuItem) add_item = g_menu_item_new (_("Add to Dictionary"), "spelling.add");
   g_autoptr(GMenuItem) ignore_item = g_menu_item_new (_("Ignore"), "spelling.ignore");
   g_autoptr(GMenuItem) check_item = g_menu_item_new (_("Check Spelling"), "spelling.enabled");
 
+  if (languages_menu == NULL)
+    {
+      languages_menu = g_menu_new ();
+      populate_languages (languages_menu);
+    }
+
+  if (languages_item == NULL)
+    languages_item = g_menu_item_new_submenu (_("Languages"), G_MENU_MODEL (languages_menu));
+
   g_menu_item_set_attribute (add_item, "hidden-when", "s", "action-disabled");
   g_menu_item_set_attribute (ignore_item, "hidden-when", "s", "action-disabled");
   g_menu_item_set_attribute (check_item, "role", "s", "check");
@@ -204,13 +269,6 @@ editor_spell_menu_new (void)
   g_menu_append_item (menu, check_item);
   g_menu_append_item (menu, languages_item);
 
-  populate_languages (languages_menu);
-
-  g_object_set_data_full (G_OBJECT (menu),
-                          "LANGUAGES_MENU",
-                          g_object_ref (languages_menu),
-                          g_object_unref);
-
   g_object_set_data_full (G_OBJECT (menu),
                           "CORRECTIONS_MENU",
                           g_object_ref (corrections_menu),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]