[gspell/wip/lang-choosers] language-choosers: add language-code property



commit 5078bf83c89e600c419ce9ff754dc8141570f146
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Thu Jan 14 15:32:04 2016 +0100

    language-choosers: add language-code property
    
    https://bugzilla.gnome.org/show_bug.cgi?id=758421

 docs/reference/gspell-1.0-sections.txt  |    2 +
 gspell/gspell-language-chooser-button.c |   51 ++++++++++++++---
 gspell/gspell-language-chooser-dialog.c |   80 +++++++++++++++++++++++++--
 gspell/gspell-language-chooser.c        |   91 ++++++++++++++++++++++++++++++-
 gspell/gspell-language-chooser.h        |   19 +++++--
 5 files changed, 222 insertions(+), 21 deletions(-)
---
diff --git a/docs/reference/gspell-1.0-sections.txt b/docs/reference/gspell-1.0-sections.txt
index 3df8162..de926e7 100644
--- a/docs/reference/gspell-1.0-sections.txt
+++ b/docs/reference/gspell-1.0-sections.txt
@@ -94,6 +94,8 @@ GspellNavigatorTextClass
 GspellLanguageChooser
 gspell_language_chooser_get_language
 gspell_language_chooser_set_language
+gspell_language_chooser_get_language_code
+gspell_language_chooser_set_language_code
 <SUBSECTION Standard>
 GSPELL_TYPE_LANGUAGE_CHOOSER
 GspellLanguageChooserInterface
diff --git a/gspell/gspell-language-chooser-button.c b/gspell/gspell-language-chooser-button.c
index 76b222f..644f92b 100644
--- a/gspell/gspell-language-chooser-button.c
+++ b/gspell/gspell-language-chooser-button.c
@@ -41,14 +41,16 @@ typedef struct _GspellLanguageChooserButtonPrivate GspellLanguageChooserButtonPr
 
 struct _GspellLanguageChooserButtonPrivate
 {
-       const GspellLanguage *language;
        GspellLanguageChooserDialog *dialog;
+       const GspellLanguage *language;
+       guint default_language : 1;
 };
 
 enum
 {
        PROP_0,
        PROP_LANGUAGE,
+       PROP_LANGUAGE_CODE,
 };
 
 static void gspell_language_chooser_button_iface_init (GspellLanguageChooserInterface *iface);
@@ -80,12 +82,18 @@ update_button_label (GspellLanguageChooserButton *button)
 }
 
 static const GspellLanguage *
-gspell_language_chooser_button_get_language (GspellLanguageChooser *chooser)
+gspell_language_chooser_button_get_language_full (GspellLanguageChooser *chooser,
+                                                 gboolean              *default_language)
 {
        GspellLanguageChooserButtonPrivate *priv;
 
        priv = gspell_language_chooser_button_get_instance_private (GSPELL_LANGUAGE_CHOOSER_BUTTON (chooser));
 
+       if (default_language != NULL)
+       {
+               *default_language = priv->default_language;
+       }
+
        return priv->language;
 }
 
@@ -95,10 +103,20 @@ gspell_language_chooser_button_set_language (GspellLanguageChooser *chooser,
 {
        GspellLanguageChooserButton *button;
        GspellLanguageChooserButtonPrivate *priv;
+       gboolean default_language;
+       gboolean notify_language_code = FALSE;
 
        button = GSPELL_LANGUAGE_CHOOSER_BUTTON (chooser);
        priv = gspell_language_chooser_button_get_instance_private (button);
 
+       default_language = (language == NULL);
+
+       if (priv->default_language != default_language)
+       {
+               priv->default_language = default_language;
+               notify_language_code = TRUE;
+       }
+
        if (language == NULL)
        {
                language = gspell_language_get_default ();
@@ -111,13 +129,19 @@ gspell_language_chooser_button_set_language (GspellLanguageChooser *chooser,
                update_button_label (button);
 
                g_object_notify (G_OBJECT (chooser), "language");
+               notify_language_code = TRUE;
+       }
+
+       if (notify_language_code)
+       {
+               g_object_notify (G_OBJECT (chooser), "language-code");
        }
 }
 
 static void
 gspell_language_chooser_button_iface_init (GspellLanguageChooserInterface *iface)
 {
-       iface->get_language = gspell_language_chooser_button_get_language;
+       iface->get_language_full = gspell_language_chooser_button_get_language_full;
        iface->set_language = gspell_language_chooser_button_set_language;
 }
 
@@ -132,7 +156,11 @@ gspell_language_chooser_button_get_property (GObject    *object,
        switch (prop_id)
        {
                case PROP_LANGUAGE:
-                       g_value_set_boxed (value, gspell_language_chooser_button_get_language (chooser));
+                       g_value_set_boxed (value, gspell_language_chooser_get_language (chooser));
+                       break;
+
+               case PROP_LANGUAGE_CODE:
+                       g_value_set_string (value, gspell_language_chooser_get_language_code (chooser));
                        break;
 
                default:
@@ -152,7 +180,11 @@ gspell_language_chooser_button_set_property (GObject      *object,
        switch (prop_id)
        {
                case PROP_LANGUAGE:
-                       gspell_language_chooser_button_set_language (chooser, g_value_get_boxed (value));
+                       gspell_language_chooser_set_language (chooser, g_value_get_boxed (value));
+                       break;
+
+               case PROP_LANGUAGE_CODE:
+                       gspell_language_chooser_set_language_code (chooser, g_value_get_string (value));
                        break;
 
                default:
@@ -209,7 +241,7 @@ ensure_dialog (GspellLanguageChooserButton *button)
 
        priv->dialog = GSPELL_LANGUAGE_CHOOSER_DIALOG (
                gspell_language_chooser_dialog_new (parent,
-                                                   priv->language,
+                                                   priv->default_language ? NULL : priv->language,
                                                    GTK_DIALOG_DESTROY_WITH_PARENT |
                                                    GTK_DIALOG_USE_HEADER_BAR));
 
@@ -219,8 +251,8 @@ ensure_dialog (GspellLanguageChooserButton *button)
                                      gtk_window_get_modal (parent));
        }
 
-       g_object_bind_property (priv->dialog, "language",
-                               button, "language",
+       g_object_bind_property (priv->dialog, "language-code",
+                               button, "language-code",
                                G_BINDING_DEFAULT);
 
        g_signal_connect (priv->dialog,
@@ -248,7 +280,7 @@ gspell_language_chooser_button_clicked (GtkButton *gtk_button)
        ensure_dialog (button);
 
        gspell_language_chooser_set_language (GSPELL_LANGUAGE_CHOOSER (priv->dialog),
-                                             priv->language);
+                                             priv->default_language ? NULL : priv->language);
 
        gtk_window_present (GTK_WINDOW (priv->dialog));
 }
@@ -266,6 +298,7 @@ gspell_language_chooser_button_class_init (GspellLanguageChooserButtonClass *kla
        button_class->clicked = gspell_language_chooser_button_clicked;
 
        g_object_class_override_property (object_class, PROP_LANGUAGE, "language");
+       g_object_class_override_property (object_class, PROP_LANGUAGE_CODE, "language-code");
 }
 
 static void
diff --git a/gspell/gspell-language-chooser-dialog.c b/gspell/gspell-language-chooser-dialog.c
index 7189038..819cb42 100644
--- a/gspell/gspell-language-chooser-dialog.c
+++ b/gspell/gspell-language-chooser-dialog.c
@@ -45,12 +45,14 @@ struct _GspellLanguageChooserDialogPrivate
 {
        GtkTreeView *treeview;
        const GspellLanguage *language;
+       guint default_language : 1;
 };
 
 enum
 {
        PROP_0,
        PROP_LANGUAGE,
+       PROP_LANGUAGE_CODE,
 };
 
 enum
@@ -94,7 +96,8 @@ scroll_to_selected (GtkTreeView *tree_view)
 }
 
 static const GspellLanguage *
-gspell_language_chooser_dialog_get_language (GspellLanguageChooser *chooser)
+gspell_language_chooser_dialog_get_language_full (GspellLanguageChooser *chooser,
+                                                 gboolean              *default_language)
 {
        GspellLanguageChooserDialog *dialog;
        GspellLanguageChooserDialogPrivate *priv;
@@ -102,15 +105,21 @@ gspell_language_chooser_dialog_get_language (GspellLanguageChooser *chooser)
        dialog = GSPELL_LANGUAGE_CHOOSER_DIALOG (chooser);
        priv = gspell_language_chooser_dialog_get_instance_private (dialog);
 
+       if (default_language != NULL)
+       {
+               *default_language = priv->default_language;
+       }
+
        return priv->language;
 }
 
 static void
 gspell_language_chooser_dialog_set_language (GspellLanguageChooser *chooser,
-                                            const GspellLanguage  *language)
+                                            const GspellLanguage  *language_param)
 {
        GspellLanguageChooserDialog *dialog;
        GspellLanguageChooserDialogPrivate *priv;
+       const GspellLanguage *language;
        GtkTreeSelection *selection;
        GtkTreeModel *model;
        GtkTreeIter iter;
@@ -118,6 +127,8 @@ gspell_language_chooser_dialog_set_language (GspellLanguageChooser *chooser,
        dialog = GSPELL_LANGUAGE_CHOOSER_DIALOG (chooser);
        priv = gspell_language_chooser_dialog_get_instance_private (dialog);
 
+       language = language_param;
+
        if (language == NULL)
        {
                language = gspell_language_get_default ();
@@ -127,14 +138,28 @@ gspell_language_chooser_dialog_set_language (GspellLanguageChooser *chooser,
 
        if (language == NULL)
        {
+               gboolean notify_language_code = FALSE;
+
                gtk_tree_selection_unselect_all (selection);
 
+               /* Update first the full state before notifying the properties. */
+               if (!priv->default_language)
+               {
+                       priv->default_language = TRUE;
+                       notify_language_code = TRUE;
+               }
+
                if (priv->language != NULL)
                {
                        priv->language = NULL;
                        g_object_notify (G_OBJECT (dialog), "language");
                }
 
+               if (notify_language_code)
+               {
+                       g_object_notify (G_OBJECT (dialog), "language-code");
+               }
+
                return;
        }
 
@@ -155,13 +180,32 @@ gspell_language_chooser_dialog_set_language (GspellLanguageChooser *chooser,
 
                if (language == cur_lang)
                {
+                       gboolean default_language;
+                       gboolean notify_language_code = FALSE;
+
                        gtk_tree_selection_select_iter (selection, &iter);
                        scroll_to_selected (priv->treeview);
 
+                       /* Update first the full state before notifying the properties. */
+
+                       default_language = language_param == NULL;
+
+                       if (priv->default_language != default_language)
+                       {
+                               priv->default_language = default_language;
+                               notify_language_code = TRUE;
+                       }
+
                        if (priv->language != language)
                        {
                                priv->language = language;
                                g_object_notify (G_OBJECT (dialog), "language");
+                               notify_language_code = TRUE;
+                       }
+
+                       if (notify_language_code)
+                       {
+                               g_object_notify (G_OBJECT (dialog), "language-code");
                        }
 
                        return;
@@ -176,7 +220,7 @@ warning:
 static void
 gspell_language_chooser_dialog_iface_init (GspellLanguageChooserInterface *iface)
 {
-       iface->get_language = gspell_language_chooser_dialog_get_language;
+       iface->get_language_full = gspell_language_chooser_dialog_get_language_full;
        iface->set_language = gspell_language_chooser_dialog_set_language;
 }
 
@@ -191,7 +235,11 @@ gspell_language_chooser_dialog_get_property (GObject    *object,
        switch (prop_id)
        {
                case PROP_LANGUAGE:
-                       g_value_set_boxed (value, gspell_language_chooser_dialog_get_language (chooser));
+                       g_value_set_boxed (value, gspell_language_chooser_get_language (chooser));
+                       break;
+
+               case PROP_LANGUAGE_CODE:
+                       g_value_set_string (value, gspell_language_chooser_get_language_code (chooser));
                        break;
 
                default:
@@ -211,7 +259,11 @@ gspell_language_chooser_dialog_set_property (GObject      *object,
        switch (prop_id)
        {
                case PROP_LANGUAGE:
-                       gspell_language_chooser_dialog_set_language (chooser, g_value_get_boxed (value));
+                       gspell_language_chooser_set_language (chooser, g_value_get_boxed (value));
+                       break;
+
+               case PROP_LANGUAGE_CODE:
+                       gspell_language_chooser_set_language_code (chooser, g_value_get_string (value));
                        break;
 
                default:
@@ -251,6 +303,7 @@ dialog_response_cb (GtkDialog *gtk_dialog,
        GtkTreeModel *model;
        GtkTreeIter iter;
        const GspellLanguage *lang;
+       gboolean notify_language_code = FALSE;
 
        if (response != GTK_RESPONSE_OK)
        {
@@ -271,10 +324,24 @@ dialog_response_cb (GtkDialog *gtk_dialog,
                            COLUMN_LANGUAGE_POINTER, &lang,
                            -1);
 
+       /* Update first the full state before notifying the properties. */
+
+       if (priv->default_language)
+       {
+               priv->default_language = FALSE;
+               notify_language_code = TRUE;
+       }
+
        if (priv->language != lang)
        {
                priv->language = lang;
                g_object_notify (G_OBJECT (dialog), "language");
+               notify_language_code = TRUE;
+       }
+
+       if (notify_language_code)
+       {
+               g_object_notify (G_OBJECT (dialog), "language-code");
        }
 }
 
@@ -289,6 +356,7 @@ gspell_language_chooser_dialog_class_init (GspellLanguageChooserDialogClass *kla
        object_class->constructed = gspell_language_chooser_dialog_constructed;
 
        g_object_class_override_property (object_class, PROP_LANGUAGE, "language");
+       g_object_class_override_property (object_class, PROP_LANGUAGE_CODE, "language-code");
 
        /* Bind class to template */
        gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/gspell/language-dialog.ui");
@@ -345,6 +413,8 @@ gspell_language_chooser_dialog_init (GspellLanguageChooserDialog *dialog)
 
        priv = gspell_language_chooser_dialog_get_instance_private (dialog);
 
+       priv->default_language = TRUE;
+
        gtk_widget_init_template (GTK_WIDGET (dialog));
 
        store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GSPELL_TYPE_LANGUAGE);
diff --git a/gspell/gspell-language-chooser.c b/gspell/gspell-language-chooser.c
index eeaf3ee..1b2e356 100644
--- a/gspell/gspell-language-chooser.c
+++ b/gspell/gspell-language-chooser.c
@@ -27,6 +27,31 @@
  *
  * #GspellLanguageChooser is an interface that is implemented by widgets for
  * choosing a #GspellLanguage.
+ *
+ * There are two properties: #GspellLanguageChooser:language and
+ * #GspellLanguageChooser:language-code. They are kept in sync. The former is
+ * useful, for example, to bind it to the #GspellChecker's language property
+ * with g_object_bind_property(). The latter is useful to bind it to a
+ * #GSettings key with g_settings_bind().
+ *
+ * When setting the language, %NULL or the empty string can be passed to pick
+ * the default language. In that case, the #GspellLanguageChooser:language-code
+ * property will contain the empty string, whereas the
+ * #GspellLanguageChooser:language property will contain the actual
+ * #GspellLanguage as returned by gspell_language_get_default(). If the user
+ * launches the #GspellLanguageChooser and chooses explicitly a language, then
+ * the #GspellLanguageChooser:language-code property will no longer be empty,
+ * even if it is the same language as the default language.
+ *
+ * Note that if an explicit language (non-%NULL or not the empty string) is set
+ * to the #GspellLanguageChooser, then the #GspellLanguageChooser:language-code
+ * property will not be empty, it will contain the language code of the passed
+ * language, even if the language is the same as the default language.
+ *
+ * Thus, a good default value for a #GSettings key is the empty string. That
+ * way, the default language is chosen, and can change depending on the locale.
+ * But once the user has chosen a language, that language is kept in the
+ * #GSettings key.
  */
 
 G_DEFINE_INTERFACE (GspellLanguageChooser, gspell_language_chooser, G_TYPE_OBJECT)
@@ -46,20 +71,36 @@ gspell_language_chooser_default_init (GspellLanguageChooserInterface *interface)
                                                                 GSPELL_TYPE_LANGUAGE,
                                                                 G_PARAM_READWRITE |
                                                                 G_PARAM_STATIC_STRINGS));
+
+       /**
+        * GspellLanguageChooser:language-code:
+        *
+        * The empty string if the default language was set and the selection
+        * hasn't changed. Or the language code if an explicit language was set
+        * or if the selection has changed.
+        */
+       g_object_interface_install_property (interface,
+                                            g_param_spec_string ("language-code",
+                                                                 "Language Code",
+                                                                 "",
+                                                                 "",
+                                                                 G_PARAM_READWRITE |
+                                                                 G_PARAM_STATIC_STRINGS));
 }
 
 /**
  * gspell_language_chooser_get_language:
  * @chooser: a #GspellLanguageChooser.
  *
- * Returns: (nullable): the selected #GspellLanguage.
+ * Returns: (nullable): the selected #GspellLanguage, or %NULL if no
+ * dictionaries are available.
  */
 const GspellLanguage *
 gspell_language_chooser_get_language (GspellLanguageChooser *chooser)
 {
        g_return_val_if_fail (GSPELL_IS_LANGUAGE_CHOOSER (chooser), NULL);
 
-       return GSPELL_LANGUAGE_CHOOSER_GET_IFACE (chooser)->get_language (chooser);
+       return GSPELL_LANGUAGE_CHOOSER_GET_IFACE (chooser)->get_language_full (chooser, NULL);
 }
 
 /**
@@ -79,4 +120,50 @@ gspell_language_chooser_set_language (GspellLanguageChooser *chooser,
        GSPELL_LANGUAGE_CHOOSER_GET_IFACE (chooser)->set_language (chooser, language);
 }
 
+/**
+ * gspell_language_chooser_get_language_code:
+ * @chooser: a #GspellLanguageChooser.
+ *
+ * Returns: the #GspellLanguageChooser:language-code. It cannot be %NULL.
+ */
+const gchar *
+gspell_language_chooser_get_language_code (GspellLanguageChooser *chooser)
+{
+       const GspellLanguage *lang;
+       gboolean default_lang = TRUE;
+
+       g_return_val_if_fail (GSPELL_IS_LANGUAGE_CHOOSER (chooser), "");
+
+       lang = GSPELL_LANGUAGE_CHOOSER_GET_IFACE (chooser)->get_language_full (chooser, &default_lang);
+
+       if (default_lang || lang == NULL)
+       {
+               return "";
+       }
+
+       return gspell_language_get_code (lang);
+}
+
+/**
+ * gspell_language_chooser_set_language_code:
+ * @chooser: a #GspellLanguageChooser.
+ * @language_code: (nullable): a language code, or the empty string or %NULL to
+ *   pick the default language.
+ */
+void
+gspell_language_chooser_set_language_code (GspellLanguageChooser *chooser,
+                                          const gchar           *language_code)
+{
+       const GspellLanguage *lang = NULL;
+
+       g_return_if_fail (GSPELL_IS_LANGUAGE_CHOOSER (chooser));
+
+       if (language_code != NULL && language_code[0] != '\0')
+       {
+               lang = gspell_language_lookup (language_code);
+       }
+
+       GSPELL_LANGUAGE_CHOOSER_GET_IFACE (chooser)->set_language (chooser, lang);
+}
+
 /* ex:set ts=8 noet: */
diff --git a/gspell/gspell-language-chooser.h b/gspell/gspell-language-chooser.h
index 8ce0565..2ddedf2 100644
--- a/gspell/gspell-language-chooser.h
+++ b/gspell/gspell-language-chooser.h
@@ -38,18 +38,27 @@ struct _GspellLanguageChooserInterface
 {
        GTypeInterface parent_interface;
 
-       const GspellLanguage *  (* get_language)        (GspellLanguageChooser *chooser);
+       /* The return value is the same as get_language(), but there is the
+        * (optional) out parameter @default_language in addition.
+        */
+       const GspellLanguage *  (* get_language_full)   (GspellLanguageChooser *chooser,
+                                                        gboolean              *default_language);
 
        void                    (* set_language)        (GspellLanguageChooser *chooser,
                                                         const GspellLanguage  *language);
 
-       gpointer padding[8];
+       gpointer padding[12];
 };
 
-const GspellLanguage * gspell_language_chooser_get_language    (GspellLanguageChooser *chooser);
+const GspellLanguage * gspell_language_chooser_get_language            (GspellLanguageChooser *chooser);
 
-void                   gspell_language_chooser_set_language    (GspellLanguageChooser *chooser,
-                                                                const GspellLanguage  *language);
+void                   gspell_language_chooser_set_language            (GspellLanguageChooser *chooser,
+                                                                        const GspellLanguage  *language);
+
+const gchar *          gspell_language_chooser_get_language_code       (GspellLanguageChooser *chooser);
+
+void                   gspell_language_chooser_set_language_code       (GspellLanguageChooser *chooser,
+                                                                        const gchar           
*language_code);
 
 G_END_DECLS
 


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