Back to index

im-sdk  12.3.91
language.c
Go to the documentation of this file.
00001 /* GIMLET: GNOME Input Method Language Enabing Tool
00002  *
00003  * Copyright (C) 2001, 2002 Havoc Pennington
00004  * Copyright (C) 2002 Red Hat, Inc.
00005  * Copyright (C) 2003 Sun Microsystems
00006  * Copyright (C) 2003 Mariano Suarez-Alvarez
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Library General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Library General Public
00019  * License along with this library; if not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00021  * Boston, MA 02111-1307, USA.
00022  */
00023 
00024 #include <config.h>
00025 
00026 #include <gtk/gtkmain.h>
00027 #include <gtk/gtkdrawingarea.h>
00028 #include <gtk/gtkbutton.h>
00029 #include <gtk/gtksignal.h>
00030 #include <panel-applet.h>
00031 #include <panel-applet-gconf.h>
00032 #include <gnome.h>
00033 
00034 #include "gnome-im-switcher.h"
00035 #include "language.h"
00036 #include "utils.h"
00037 
00038 #include <gconf/gconf-client.h>
00039 #include <gtk/gtktreeview.h>
00040 #include <gtk/gtkmessagedialog.h>
00041 #include <gtk/gtktreestore.h>
00042 
00043 #include <string.h>
00044 
00045 #include "gimlet-lang-data.h"
00046 
00047 static GConfClient *default_client = NULL;
00048 
00049 enum
00050 {
00051   COLUMN_NAME,
00052   COLUMN_DESCRIPTION,
00053   N_COLUMNS
00054 };
00055 
00056 /*
00057  * Utility stuff
00058  */
00059 void gconf_set_conversion_keys (GtkWidget *, GSList *);
00060 char *gconf_get_conversion_keys (GimletWindow *);
00061 
00062 static GSList *active_languages = NULL;
00063 
00064 
00065 static void
00066 update_single_tree_model (GtkListStore *store)
00067 {
00068   GSList *tmp;
00069   GtkTreeIter parent_iter;
00070 
00071   gtk_list_store_clear (store);
00072   
00073   tmp = active_languages;
00074   while (tmp != NULL)
00075     {
00076       GimletLanguage *e = tmp->data;
00077       
00078       if (strcmp (e->iiim_lang_name, "ASCII") != 0)
00079        {
00080          gtk_list_store_append (store, &parent_iter);
00081          gtk_list_store_set (store, &parent_iter,
00082                            COLUMN_DESCRIPTION,
00083                            e->description,
00084                            COLUMN_NAME,
00085                            e->name,
00086                            -1);
00087        }
00088       tmp = tmp->next;
00089     }
00090 }
00091 
00092 static GSList *stores = NULL;
00093 
00094 static void
00095 unregister_store (void    *data,
00096                   GObject *where_object_was)
00097 {
00098   stores = g_slist_remove (stores, where_object_was);
00099 }
00100 
00101 static void
00102 update_active_language_tree_models (void)
00103 {
00104   GSList *tmp;
00105   tmp = stores;
00106   while (tmp != NULL)
00107     {
00108       update_single_tree_model (tmp->data);
00109       tmp = tmp->next;
00110     }
00111 }
00112 
00113 static void
00114 register_active_language_tree_model (GtkListStore *store)
00115 {
00116   update_single_tree_model (store);
00117   stores = g_slist_prepend (stores, store);
00118   g_object_weak_ref (G_OBJECT (store), unregister_store, NULL);
00119 }
00120 
00121 static void update_active_languages_from_string_list (GSList *strings);
00122 
00123 static void
00124 languages_change_notify (GConfClient *client,
00125                          guint        cnxn_id,
00126                          GConfEntry  *entry,
00127                          gpointer     user_data)
00128 {
00129   GConfValue *val;
00130   GSList *strings;
00131   
00132   /* FIXME handle whether the entry is writable
00133    */
00134 
00135   val = gconf_entry_get_value (entry);
00136   if (val == NULL || val->type != GCONF_VALUE_LIST ||
00137       gconf_value_get_list_type (val) != GCONF_VALUE_STRING)
00138     strings = NULL;
00139   else
00140     {
00141       GSList *tmp;
00142 
00143       strings = NULL;
00144       tmp = gconf_value_get_list (val);
00145       while (tmp != NULL)
00146         {
00147           GConfValue *v = tmp->data;
00148           g_assert (v->type == GCONF_VALUE_STRING);
00149 
00150           if (gconf_value_get_string (v))
00151             {
00152               strings = g_slist_prepend (strings,
00153                                     (gchar*) gconf_value_get_string (v));
00154             }
00155           
00156           tmp = tmp->next;
00157         }
00158     }
00159 
00160   update_active_languages_from_string_list (strings);
00161 
00162   /* note we didn't copy the strings themselves, so don't free them */
00163   g_slist_free (strings);
00164 }
00165 
00166 static GimletLanguage*
00167 find_language_by_description (const char *description)
00168 {
00169   int i = 0;
00170   int n_elements = G_N_ELEMENTS (g_languages);
00171 
00172   while (i < n_elements)
00173     {
00174       if (strcmp (description, g_languages[i].description) == 0)
00175         return &g_languages[i];
00176 
00177       ++i;
00178     }
00179 
00180   return NULL;
00181 }
00182 
00183 static const GimletLanguage*
00184 find_language_by_iiim_lang_name (const char *iiim_lang_name)
00185 {
00186   int i = 0;
00187   int n_elements = G_N_ELEMENTS (g_languages);
00188 
00189   while (i < n_elements)
00190     {
00191       if (strcmp (iiim_lang_name, g_languages[i].iiim_lang_name) == 0)
00192         return &g_languages[i];
00193 
00194       ++i;
00195     }
00196 
00197   return NULL;
00198 }
00199 
00200 gchar *
00201 gimlet_language_find_name (char *iiim_lang_name)
00202 {
00203   const GimletLanguage *ilname = find_language_by_iiim_lang_name (iiim_lang_name);
00204   if (ilname)
00205     return ilname->name;
00206   else
00207     return NULL;
00208 }
00209 
00210 gchar *
00211 gimlet_language_find_description (char *iiim_lang_name)
00212 {
00213   const GimletLanguage *ilname = find_language_by_iiim_lang_name (iiim_lang_name);
00214   if (ilname)
00215     return ilname->description;
00216   else
00217     return NULL;
00218 }
00219 
00220 gchar *
00221 gimlet_language_find_short (char *ilname)
00222 {
00223   if (find_language_by_iiim_lang_name (ilname))
00224     {
00225       /* treat Chinese specially */
00226       if (strlen (ilname) == 5 &&
00227          ilname[0] == 'z' &&
00228          ilname[1] == 'h')
00229        {
00230          if (strcmp (ilname, "zh_CN") == 0)
00231            return (g_strdup ("SC"));
00232          else
00233            return (g_strdup ("TC"));
00234        }    
00235       else
00236        {
00237          gchar *ll = g_strndup (ilname, 2);
00238          ll[0] = g_ascii_toupper (ll[0]);
00239          return ll;
00240        }
00241     }
00242   else
00243     return NULL;
00244 }
00245 
00246 static GimletLanguage*
00247 gimlet_language_copy (const GimletLanguage *src)
00248 {
00249   GimletLanguage *c;
00250 
00251   c = g_new (GimletLanguage, 1);
00252   c->idx = src->idx;
00253   c->valid = src->valid;
00254   c->conversion_on = src->conversion_on;
00255   c->name = g_strdup (src->name);
00256   c->description = g_strdup (src->description);
00257   c->iiim_lang_name = g_strdup (src->iiim_lang_name);
00258   
00259   return c;
00260 }
00261 
00262 static void
00263 update_active_languages_from_string_list (GSList *strings)
00264 {
00265   GSList *tmp;
00266   GHashTable *table;
00267   const char *description;
00268 
00269   table = g_hash_table_new (g_direct_hash, g_direct_equal);
00270   
00271   g_slist_foreach (active_languages, (GFunc) gimlet_language_free,
00272                  NULL);
00273   g_slist_free (active_languages);
00274   active_languages = NULL;
00275 
00276   /* First add the ASCII . */
00277   description = g_languages[ASCII].description;
00278   if (g_hash_table_lookup (table, GINT_TO_POINTER (g_quark_from_string (description))) == NULL)
00279     {
00280       active_languages = g_slist_prepend (active_languages,
00281                                      gimlet_language_copy (&g_languages[ASCII]));
00282       g_hash_table_insert (table,
00283                         GINT_TO_POINTER (g_quark_from_string (description)),
00284                         GINT_TO_POINTER (g_quark_from_string (description)));
00285     }
00286 
00287   for (tmp = strings; tmp != NULL; tmp = tmp->next)
00288     {
00289       const GimletLanguage *l;
00290       GimletLanguage *language;
00291       const char *iiim_lang_name = tmp->data;
00292       
00293       l = find_language_by_iiim_lang_name (iiim_lang_name);
00294       if (l == NULL)
00295        continue;            /* this can happen e.g client locale is "C" */
00296 
00297       if (g_hash_table_lookup (table, GINT_TO_POINTER (g_quark_from_string (l->description))) != NULL)
00298        continue;
00299       g_hash_table_insert (table,
00300                         GINT_TO_POINTER (g_quark_from_string (l->description)),
00301                         GINT_TO_POINTER (g_quark_from_string (l->description)));
00302       language = l->valid ? gimlet_language_copy (l) : NULL;
00303 
00304       if (language != NULL)
00305        active_languages = g_slist_append (active_languages, language);
00306     }
00307 
00308   g_hash_table_destroy (table);
00309   
00310   update_active_language_tree_models ();
00311 }
00312 
00313 static void
00314 response_callback (GtkWidget *window,
00315                    int        id,
00316                    void      *data)
00317 {
00318   if (id == GTK_RESPONSE_HELP)
00319     gimlet_util_show_help ("imswitcher-usage-add", GTK_WINDOW (window));
00320   else
00321     gtk_widget_destroy (GTK_WIDGET (window));
00322 }
00323 
00324 static void
00325 count_selected_items_func (GtkTreeModel      *model,
00326                            GtkTreePath       *path,
00327                            GtkTreeIter       *iter,
00328                            gpointer           data)
00329 {
00330   int *count = data;
00331 
00332   *count += 1;
00333 }
00334 
00335 static void
00336 available_selection_changed_callback (GtkTreeSelection *selection,
00337                                       void             *data)
00338 {
00339   int count;
00340   GtkWidget *add_button;
00341   GtkWidget *dialog;
00342 
00343   dialog = data;
00344   
00345   count = 0;
00346   gtk_tree_selection_selected_foreach (selection,
00347                                        count_selected_items_func,
00348                                        &count);
00349 
00350   add_button = g_object_get_data (G_OBJECT (dialog), "language-dialog-add");
00351   
00352   gtk_widget_set_sensitive (add_button, count > 0);
00353 }
00354 
00355 static void
00356 displayed_selection_changed_callback (GtkTreeSelection *selection,
00357                                       void             *data)
00358 {
00359   int count;
00360   GtkWidget *remove_button;
00361   GtkWidget *dialog;
00362 
00363   dialog = data;
00364   
00365   count = 0;
00366   gtk_tree_selection_selected_foreach (selection,
00367                                        count_selected_items_func,
00368                                        &count);
00369 
00370   remove_button = g_object_get_data (G_OBJECT (dialog), "language-dialog-remove");
00371   
00372   gtk_widget_set_sensitive (remove_button, count > 0);
00373 }
00374 
00375 static void
00376 get_selected_languages_func (GtkTreeModel      *model,
00377                              GtkTreePath       *path,
00378                              GtkTreeIter       *iter,
00379                              gpointer           data)
00380 {
00381   GSList **list = data;
00382   char *description;
00383 
00384   description = NULL;
00385   gtk_tree_model_get (model,
00386                       iter,
00387                       COLUMN_DESCRIPTION,
00388                       &description,
00389                       -1);
00390 
00391   *list = g_slist_prepend (*list, description);
00392 }
00393 
00394 static gboolean
00395 description_in_language_list (GSList     *list,
00396                            const char *str)
00397 {
00398   GSList *tmp;
00399 
00400   tmp = list;
00401   while (tmp != NULL)
00402     {
00403       const GimletLanguage *lang = tmp->data;
00404       
00405       if (strcmp (lang->description, str) == 0)
00406         return TRUE;
00407 
00408       tmp = tmp->next;
00409     }
00410 
00411   return FALSE;
00412 }
00413 
00414 static GSList*
00415 remove_iiim_lang_from_list (GSList     *list,
00416                          const char *str)
00417 {
00418   GSList *tmp;
00419 
00420   tmp = list;
00421   while (tmp != NULL)
00422     {
00423       if (strcmp (tmp->data, str) == 0)
00424         break;
00425 
00426       tmp = tmp->next;
00427     }
00428 
00429   if (tmp != NULL)
00430     {
00431       list = g_slist_remove (list, tmp->data);
00432       g_free (tmp->data);
00433     }
00434   return list;
00435 }
00436 
00437 /* static GSList*
00438  * remove_string_from_list (GSList     *list,
00439  *                          const char *str)
00440  * {
00441  *   GSList *tmp;
00442  * 
00443  *   tmp = list;
00444  *   while (tmp != NULL)
00445  *     {
00446  *       if (strcmp (tmp->data, str) == 0)
00447  *         break;
00448  * 
00449  *       tmp = tmp->next;
00450  *     }
00451  * 
00452  *   if (tmp != NULL)
00453  *     {
00454  *       list = g_slist_remove (list, tmp->data);
00455  *       g_free (tmp->data);
00456  *     }
00457  *   return list;
00458  * }
00459  */
00460 
00461 /* static GSList*
00462  * language_list_to_description_list (GSList *src)
00463  * {
00464  *   GSList *list;
00465  *   GSList *tmp;
00466  *   
00467  *   list = NULL;
00468  *   tmp = src;
00469  *   while (tmp != NULL)
00470  *     {
00471  *       const GimletLanguage *lang = tmp->data;
00472  *       
00473  *       list = g_slist_append (list, g_strdup (lang->description));
00474  *       tmp = tmp->next;
00475  *     }
00476  * 
00477  *   return list;
00478  * }
00479  */
00480 
00481 static GSList*
00482 language_list_to_iiim_lang_list (GSList *src)
00483 {
00484   GSList *list;
00485   GSList *tmp;
00486   
00487   list = NULL;
00488   tmp = src;
00489   while (tmp != NULL)
00490     {
00491       const GimletLanguage *lang = tmp->data;
00492       
00493       list = g_slist_append (list, g_strdup (lang->iiim_lang_name));
00494       tmp = tmp->next;
00495     }
00496 
00497   return list;
00498 }
00499 
00500 static void
00501 gconf_set_active_languages (GtkWidget *gimlet_applet, GSList *strings)
00502 {
00503   gchar *key;
00504 
00505   key = panel_applet_gconf_get_full_key (PANEL_APPLET (gimlet_applet),
00506                                     (const gchar*)"active_languages");
00507   gconf_client_set_list (default_client, key, 
00508                          GCONF_VALUE_STRING,
00509                          strings,
00510                          NULL);
00511   g_free (key);
00512 }
00513 
00514 static GSList *
00515 gconf_get_active_languages (GimletWindow *gimlet)
00516 {
00517   gchar *key;
00518   GSList *strings = NULL;
00519 
00520   key = panel_applet_gconf_get_full_key (PANEL_APPLET (gimlet->applet),
00521                                     "active_languages");
00522   if (default_client == NULL)
00523     {
00524       GError *err;
00525 
00526       default_client = gconf_client_get_default ();
00527       g_object_ref (G_OBJECT (default_client));
00528 
00529       err = NULL;
00530       gconf_client_notify_add (default_client, key, 
00531                             languages_change_notify,
00532                             NULL, /* user_data */
00533                             NULL, &err);
00534     }
00535   strings = gconf_client_get_list (default_client,
00536                                key,
00537                                GCONF_VALUE_STRING, NULL);
00538   g_free (key);
00539   return strings;
00540 }
00541 
00542 static void
00543 add_button_clicked_callback (GtkWidget *button,
00544                              void      *data)
00545 {
00546   GtkWidget *dialog;
00547   GtkWidget *treeview;
00548   GtkWidget *gimlet_applet;
00549   GtkTreeSelection *selection;
00550   GSList *languages;
00551   GSList *tmp;
00552   GSList *active_iiim_lang_list;
00553 
00554   dialog = data;
00555 
00556   treeview = g_object_get_data (G_OBJECT (dialog),
00557                                 "language-dialog-available-treeview");
00558   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
00559 
00560   languages = NULL;
00561   gtk_tree_selection_selected_foreach (selection,
00562                                        get_selected_languages_func,
00563                                        &languages);
00564 
00565   active_iiim_lang_list = language_list_to_iiim_lang_list (active_languages);
00566 
00567   tmp = languages;
00568   while (tmp != NULL)
00569     {
00570       /* appending is less efficient but produces user-expected
00571        * result
00572        */
00573       if (!description_in_language_list (active_languages, tmp->data))
00574        {
00575          GimletLanguage *l;
00576 
00577          l = find_language_by_description ((const char*)tmp->data);
00578 #if 0
00579          if (l == NULL)
00580            continue;        /* this should not happen */
00581 #endif
00582          active_iiim_lang_list = g_slist_append (active_iiim_lang_list,
00583                                             g_strdup (l->iiim_lang_name));
00584        }
00585       tmp = tmp->next;
00586     }
00587 
00588   /* this is reentrant, but only after it's done using the list
00589    * values, so should be safe
00590    */
00591   gimlet_applet = g_object_get_data (G_OBJECT (dialog),
00592                                  "gimlet-applet");
00593 
00594   gconf_set_active_languages (gimlet_applet, active_iiim_lang_list);
00595 
00596   g_slist_foreach (active_iiim_lang_list, (GFunc) g_free, NULL);
00597   g_slist_free (active_iiim_lang_list);
00598   
00599   g_slist_foreach (languages, (GFunc) g_free, NULL);
00600   g_slist_free (languages);
00601 }
00602 
00603 static void
00604 remove_button_clicked_callback (GtkWidget *button,
00605                                 void      *data)
00606 {
00607   GtkWidget *dialog;
00608   GtkWidget *treeview;
00609   GtkWidget *gimlet_applet;
00610   GtkTreeSelection *selection;
00611   GSList *languages;
00612   GSList *tmp;
00613   GSList *active_iiim_lang_list;
00614 
00615   dialog = data;
00616 
00617   treeview = g_object_get_data (G_OBJECT (dialog),
00618                                 "language-dialog-displayed-treeview");
00619   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
00620 
00621   languages = NULL;
00622   gtk_tree_selection_selected_foreach (selection,
00623                                        get_selected_languages_func,
00624                                        &languages);
00625 
00626   active_iiim_lang_list = language_list_to_iiim_lang_list (active_languages);
00627 
00628   tmp = languages;
00629   while (tmp != NULL)
00630     {
00631       GimletLanguage *l;
00632 
00633       /* appending is less efficient but produces user-expected
00634        * result
00635        */
00636       l = find_language_by_description (tmp->data);
00637 #if 0
00638       if (l == NULL)
00639        continue;            /* this should not happen */
00640 #endif
00641       active_iiim_lang_list =
00642        remove_iiim_lang_from_list (active_iiim_lang_list, l->iiim_lang_name);
00643 
00644       tmp = tmp->next;
00645     }
00646 
00647   /* this is reentrant, but only after it's done using the list
00648    * values, so should be safe
00649    */
00650   gimlet_applet = g_object_get_data (G_OBJECT (dialog),
00651                                  "gimlet-applet");
00652 
00653   gconf_set_active_languages (gimlet_applet, active_iiim_lang_list);
00654 
00655   g_slist_foreach (active_iiim_lang_list, (GFunc) g_free, NULL);
00656   g_slist_free (active_iiim_lang_list);
00657 
00658   g_slist_foreach (languages, (GFunc) g_free, NULL);
00659   g_slist_free (languages);
00660 }
00661 
00662 GtkWidget*
00663 gimlet_langmenu_dialog_new (GtkWindow *transient_parent,
00664                          GimletWindow *gimlet)
00665 {
00666   GladeXML *xml;
00667   GtkWidget *w;
00668   GtkCellRenderer *cell_renderer;
00669   int i;
00670   GtkTreeModel *sort_model;
00671   GtkListStore *tree;
00672   GtkTreeViewColumn *column;
00673   GtkTreeIter parent_iter;
00674   GtkTreeSelection *selection;
00675   GtkWidget *dialog;
00676 
00677   xml = gimlet_util_load_glade_file (GIMLET_GLADE_FILE,
00678                                  "languages-dialog",
00679                                  transient_parent);
00680   if (xml == NULL)
00681     return NULL;
00682 
00683   /* The dialog itself */
00684   dialog = glade_xml_get_widget (xml, "languages-dialog");
00685 
00686   gimlet_util_set_unique_role (GTK_WINDOW (dialog), "gimlet-languages");
00687 
00688   g_signal_connect (G_OBJECT (dialog), "response",
00689                     G_CALLBACK (response_callback),
00690                     NULL);
00691 
00692   /* buttons */
00693   w = glade_xml_get_widget (xml, "add-button");
00694   g_object_set_data (G_OBJECT (dialog),
00695                      "language-dialog-add",
00696                      w);
00697 
00698   g_object_set_data (G_OBJECT (dialog),
00699                      "gimlet-applet",
00700                      gimlet->applet);
00701   g_signal_connect (G_OBJECT (w), "clicked",
00702                     G_CALLBACK (add_button_clicked_callback),
00703                     dialog);
00704 
00705   w = glade_xml_get_widget (xml, "remove-button");
00706   g_object_set_data (G_OBJECT (dialog),
00707                      "language-dialog-remove",
00708                      w);
00709 
00710   g_signal_connect (G_OBJECT (w), "clicked",
00711                     G_CALLBACK (remove_button_clicked_callback),
00712                     dialog);
00713   
00714   /* Tree view of available languages */
00715   
00716   w = glade_xml_get_widget (xml, "available-treeview");
00717   g_object_set_data (G_OBJECT (dialog),
00718                      "language-dialog-available-treeview",
00719                      w);
00720   
00721   tree = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
00722 
00723   /* Column 1 */
00724   cell_renderer = gtk_cell_renderer_text_new ();
00725   column = gtk_tree_view_column_new_with_attributes (_("_Language"),
00726                                                cell_renderer,
00727                                                "text", COLUMN_NAME,
00728                                                NULL);
00729   gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
00730   gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
00731   
00732   /* Column 2 */
00733   cell_renderer = gtk_cell_renderer_text_new ();
00734   column = gtk_tree_view_column_new_with_attributes (_("_Description"),
00735                                                cell_renderer,
00736                                                "text", COLUMN_DESCRIPTION,
00737                                                NULL);
00738   gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
00739   gtk_tree_view_column_set_sort_column_id (column, COLUMN_DESCRIPTION);  
00740 
00741   /* Add the data */
00742 
00743   i = 0;
00744   while (i < (int) G_N_ELEMENTS (g_languages))
00745     {
00746       if (g_languages[i].valid && (strcmp (g_languages[i].iiim_lang_name,
00747                                       "ASCII") != 0))
00748         {
00749           gtk_list_store_append (tree, &parent_iter);
00750           gtk_list_store_set (tree, &parent_iter,
00751                               COLUMN_DESCRIPTION,
00752                               g_languages[i].description,
00753                               COLUMN_NAME,
00754                               g_languages[i].name,
00755                               -1);
00756         }
00757       ++i;
00758     }
00759 
00760   /* Sort model */
00761   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
00762   
00763   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
00764                                         COLUMN_NAME,
00765                                         GTK_SORT_ASCENDING);
00766   
00767   gtk_tree_view_set_model (GTK_TREE_VIEW (w), sort_model);
00768   g_object_unref (G_OBJECT (tree));
00769 
00770   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (w));    
00771   gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
00772                             GTK_SELECTION_MULTIPLE);
00773 
00774   available_selection_changed_callback (selection, dialog);
00775   g_signal_connect (G_OBJECT (selection), "changed",                    
00776                     G_CALLBACK (available_selection_changed_callback),
00777                     dialog);
00778 
00779   /* Tree view of selected languages */
00780   
00781   w = glade_xml_get_widget (xml, "displayed-treeview");
00782   g_object_set_data (G_OBJECT (dialog),
00783                      "language-dialog-displayed-treeview",
00784                      w);
00785   
00786   tree = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
00787 
00788   /* Column 1 */
00789   cell_renderer = gtk_cell_renderer_text_new ();
00790   column = gtk_tree_view_column_new_with_attributes (_("_Language"),
00791                                                cell_renderer,
00792                                                "text", COLUMN_NAME,
00793                                                NULL);
00794   gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
00795   gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
00796   
00797   /* Column 2 */
00798   cell_renderer = gtk_cell_renderer_text_new ();
00799   column = gtk_tree_view_column_new_with_attributes (_("_Description"),
00800                                                cell_renderer,
00801                                                "text", COLUMN_DESCRIPTION,
00802                                                NULL);
00803   gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
00804   gtk_tree_view_column_set_sort_column_id (column, COLUMN_DESCRIPTION);  
00805 
00806   /* Add the data */
00807   register_active_language_tree_model (tree);
00808 
00809   /* Sort model */
00810   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
00811   
00812   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
00813                                         COLUMN_NAME,
00814                                         GTK_SORT_ASCENDING);
00815   
00816   gtk_tree_view_set_model (GTK_TREE_VIEW (w), sort_model);
00817   g_object_unref (G_OBJECT (tree));  
00818 
00819   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (w));    
00820   gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
00821                             GTK_SELECTION_MULTIPLE);
00822 
00823   displayed_selection_changed_callback (selection, dialog);
00824   g_signal_connect (G_OBJECT (selection), "changed",
00825                     G_CALLBACK (displayed_selection_changed_callback),
00826                     dialog);
00827 
00828   g_object_unref (G_OBJECT (xml));
00829   
00830   return dialog;
00831 }
00832 
00833 void
00834 gimlet_language_init (GimletWindow *gimlet)
00835 {
00836   int i;
00837   int n_elements;
00838   gchar **p;
00839   GSList *strings = NULL;
00840 
00841   n_elements = G_N_ELEMENTS (g_languages);
00842 
00843   if (gimlet->client_lang_list != NULL)
00844     {
00845       for (p = gimlet->client_lang_list; *p; p++)
00846        for (i = 0; i < n_elements; i++)
00847          {
00848            /* Translate the description */
00849            g_languages[i].description = _(g_languages[i].description);
00850 
00851            if (g_languages[i].iiim_lang_name != NULL)
00852              {
00853               guint len = strlen (g_languages[i].iiim_lang_name);
00854               if (strncmp (g_languages[i].iiim_lang_name, *p, len) == 0)
00855                 g_languages[i].valid = TRUE;
00856              }
00857          }
00858     }
00859 
00860   strings = gconf_get_active_languages (gimlet);
00861 
00862   update_active_languages_from_string_list (strings);
00863 
00864   g_slist_foreach (strings, (GFunc) g_free, NULL);
00865   g_slist_free (strings);
00866 }
00867 
00868 char*
00869 gimlet_language_get_name (GimletLanguage *data)
00870 {
00871   return data->name;
00872 }
00873 
00874 char*
00875 gimlet_language_get_iiim_lang_name (GimletLanguage *data)
00876 {
00877   /* avoid returning NULL */
00878   return data->iiim_lang_name ? data->iiim_lang_name : DEFAULT_LANG;
00879 }
00880 
00881 char *
00882 gimlet_language_get_conversion_mode (char *iiim_lang_name)
00883 {
00884   GSList *tmp = active_languages;
00885 
00886   while (tmp != NULL)
00887     {
00888       GimletLanguage *lang = tmp->data;
00889       if (strcmp (lang->iiim_lang_name, iiim_lang_name) == 0)
00890          return (lang->conversion_on ? "on" : "off");
00891       tmp = tmp->next;
00892     }
00893   return "off";
00894 }
00895 
00896 GSList*
00897 gimlet_language_get_active_languages (void)
00898 {
00899   GSList *copy;
00900   GSList *tmp;
00901 
00902   copy = NULL;
00903   tmp = active_languages;
00904   while (tmp != NULL)
00905     {
00906       copy = g_slist_append (copy,
00907                               gimlet_language_copy (tmp->data));
00908       
00909       tmp = tmp->next;
00910     }
00911 
00912   return copy;
00913 }
00914 
00915 /*
00916   add an active language from the iiim input language which
00917   client has set.
00918 */
00919 void
00920 gimlet_language_add_active_language (GimletWindow *gimlet,
00921                                  char *iiim_lang_name)
00922 {
00923   GtkWidget *gimlet_applet = GTK_WIDGET (gimlet->applet);
00924   GSList *active_iiim_lang_list;
00925   GSList *tmp;
00926 
00927   active_iiim_lang_list = language_list_to_iiim_lang_list (active_languages);
00928 
00929   tmp = active_iiim_lang_list;
00930   while (tmp != NULL)
00931     {
00932       if (strcmp (tmp->data, iiim_lang_name) == 0)
00933        return;
00934       tmp = tmp->next;
00935     }
00936   active_iiim_lang_list = g_slist_prepend (active_iiim_lang_list,
00937                                       g_strdup (iiim_lang_name));
00938   gconf_set_active_languages (gimlet_applet, active_iiim_lang_list);
00939 
00940   g_slist_foreach (active_iiim_lang_list, (GFunc) g_free, NULL);
00941   g_slist_free (active_iiim_lang_list);
00942 }
00943 
00944 void
00945 gimlet_language_free (GimletLanguage *language)
00946 {
00947   g_free (language->name);
00948   g_free (language->description);
00949   g_free (language->iiim_lang_name);
00950   g_free (language);
00951 }
00952 
00953 static void
00954 gconf_set_conversion_keys (GtkWidget *gimlet_applet,
00955                         GSList *strings)
00956 {
00957   gchar *key;
00958 
00959   key = panel_applet_gconf_get_full_key (PANEL_APPLET (gimlet_applet),
00960                                     (const gchar*)"conversion_keys");
00961   gconf_client_set_list (default_client, key,
00962                       GCONF_VALUE_STRING,
00963                       strings,
00964                       NULL);
00965   g_free (key);
00966 }
00967 
00968 static char *
00969 gconf_get_conversion_keys (GimletWindow *gimlet)
00970 {
00971   gchar *key;
00972   GSList *strings = NULL;
00973   int i, n;
00974   gchar *conversion_keys = NULL;
00975   char s[512], *p = s;
00976 
00977   key = panel_applet_gconf_get_full_key (PANEL_APPLET (gimlet->applet),
00978                                     "conversion_keys");
00979   if (default_client == NULL)
00980     {
00981       GError *err = NULL;
00982 
00983       default_client = gconf_client_get_default ();
00984       g_object_ref (G_OBJECT (default_client));
00985     }
00986 
00987   strings = gconf_client_get_list (default_client,
00988                                key,
00989                                GCONF_VALUE_STRING, NULL);
00990 
00991   
00992   n = g_list_length (strings);
00993 
00994   memset (s, 0, 512);
00995 
00996   for (i=0; i < n; ++i)
00997     {
00998       char *k = g_list_nth_data (strings, i);
00999       char key_delimiter = ',';
01000 
01001       strcpy (p, k);
01002       p += strlen (k);
01003 
01004       if (i < n -1)
01005        *p++ = key_delimiter;
01006 
01007       g_free (k);
01008     }
01009 
01010   g_free (key);
01011   g_list_free (strings);
01012 
01013   if (*s) conversion_keys = g_strdup (s);
01014 
01015   return conversion_keys;
01016 }
01017 
01018 static void
01019 hotkey_cancel_callback (GtkWidget *button,
01020                       GimletWindow *gimlet)
01021 {
01022   gtk_widget_destroy (GTK_WINDOW (gimlet->edit_hotkey_dialog));
01023 }
01024 
01025 static char *
01026 get_hotkey_with_type (char *string,
01027                     char *type)
01028 {
01029   char *label_delimiter = ":";
01030   char **hotkeys = g_strsplit (string, label_delimiter, -1);
01031   int num_hotkeys = 0, i;
01032   char *keys = NULL;
01033 
01034   // num_hotkeys = g_strv_length (hotkeys) / 2;
01035   while (hotkeys [num_hotkeys]) ++num_hotkeys;
01036   num_hotkeys /= 2;
01037 
01038   for (i = 0; i < num_hotkeys; ++i)
01039     {
01040       if (!strcmp (hotkeys[i * 2], type))
01041        {        
01042          keys = strdup (hotkeys[i * 2 + 1]);
01043          break;
01044        }
01045     }
01046 
01047   g_strfreev (hotkeys);
01048 
01049   return keys;
01050 }
01051 
01052 static void
01053 hotkey_changed_callback (GtkWidget *button,
01054                       GimletWindow *gimlet)
01055 {
01056   GSList *strings = NULL;
01057   GtkEntry *trigger_entry = (GtkEntry *)g_object_get_data (G_OBJECT (button),
01058                                       "iiim-hotkey-trigger");
01059   char *trigger; 
01060   char **keys;
01061   char *key_delimiter = ",";
01062   char *old_trigger;
01063   int num_keys, i;
01064   
01065   trigger = strdup (gtk_entry_get_text (trigger_entry));
01066 
01067   /* return if no change is made */
01068   
01069   old_trigger = get_hotkey_with_type (gimlet->hotkey, TRIGGER_KEY_LABEL);
01070   if (!strcasecmp (trigger, old_trigger))
01071     goto END_HOTKEY_CHANGED_CALLBACK;
01072 
01073   /*
01074    * FIXME one warning dialog should be popuped if the trigger input is corrupted.
01075    */
01076 
01077   gimlet_iiim_hotkey_set (gimlet, trigger);
01078 
01079   keys = g_strsplit (trigger, key_delimiter, -1);
01080 
01081   //  num_keys = g_strv_length (keys);
01082   num_keys = 0;
01083   while (keys[num_keys]) ++num_keys;
01084 
01085   for (i = 0; i < num_keys; ++i)
01086     strings = g_list_insert (strings, keys[i], -1);
01087 
01088   gconf_set_conversion_keys (gimlet->applet, strings);
01089 
01090   g_list_free (strings);
01091   g_strfreev (keys);
01092 
01093  END_HOTKEY_CHANGED_CALLBACK:
01094   gtk_widget_destroy (GTK_WINDOW (gimlet->edit_hotkey_dialog));
01095 
01096   g_free (old_trigger);
01097   g_free (trigger);
01098 }
01099 
01100 GtkWidget *
01101 gimlet_hotkey_dialog_new (GtkWidget *transient_parent,
01102                        GimletWindow *gimlet)
01103 {
01104   GladeXML *xml;
01105   GtkWidget *dialog = NULL;
01106   GtkWidget *vbox, *table;
01107   GtkWidget *trigger_entry, *w;
01108   int num_hotkeys = 0;
01109   gchar *label_delimiter = ":";
01110   gchar **hotkeys;
01111   int i;
01112 
01113   if (!gimlet->hotkey) return NULL;
01114 
01115   hotkeys = g_strsplit (gimlet->hotkey, label_delimiter, -1);
01116 
01117   //num_hotkeys = g_strv_length (hotkeys)/2;
01118   while (hotkeys[num_hotkeys]) ++num_hotkeys;
01119   num_hotkeys /= 2;
01120 
01121   xml = gimlet_util_load_glade_file (GIMLET_GLADE_FILE,
01122                                  "hotkey-dialog",
01123                                  transient_parent);
01124 
01125   if (xml == NULL) goto END_HOTKEY_DIALOG;
01126 
01127   dialog = glade_xml_get_widget (xml, "hotkey-dialog");
01128 
01129   gimlet_util_set_unique_role (GTK_WINDOW (dialog), "gimlet-hotkeys");
01130 
01131   /* dynamically create the table */
01132   vbox = glade_xml_get_widget (xml, "hotkey-vbox");
01133   table = gtk_table_new (num_hotkeys, 2, FALSE);
01134   gtk_table_set_row_spacings (GTK_TABLE (table), 4);
01135   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
01136   gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
01137 
01138   for (i = 0; i < num_hotkeys; ++i)
01139     {
01140       w = gtk_label_new (hotkeys [i * 2]);
01141       gtk_table_attach_defaults (GTK_TABLE (table),
01142                              w,
01143                              0, 1, i, i + 1);
01144 
01145       w = gtk_entry_new ();
01146       gtk_entry_set_text (w, hotkeys[i * 2 + 1]);
01147       gtk_table_attach_defaults (GTK_TABLE (table),
01148                              w,
01149                              1, 2, i, i + 1);
01150       if (!strcasecmp (hotkeys[i * 2], TRIGGER_KEY_LABEL))
01151        trigger_entry = w;
01152       else
01153        gtk_widget_set_sensitive (w, FALSE);
01154     }
01155 
01156   w = glade_xml_get_widget (xml, "hotkey-okbutton");
01157   g_object_set_data (G_OBJECT (w), "iiim-hotkey-trigger",
01158                    trigger_entry);
01159   g_object_set_data (G_OBJECT (w), "iiim-hotkey-dialog",
01160                    dialog);
01161 
01162   g_signal_connect (G_OBJECT (w), "clicked",
01163                   G_CALLBACK (hotkey_changed_callback),
01164                   gimlet);
01165 
01166   w = glade_xml_get_widget (xml, "hotkey-cancelbutton");
01167   g_signal_connect (G_OBJECT (w), "clicked",
01168                   G_CALLBACK (hotkey_cancel_callback),
01169                   gimlet);
01170 
01171   /* FIXME one 'reset' button should be added here in order 
01172    * to reset the trigger key
01173    */
01174 
01175   g_object_unref (G_OBJECT (xml));
01176 
01177  END_HOTKEY_DIALOG:
01178   g_strfreev (hotkeys);
01179   return dialog;
01180 }