2 * Copyright (c) 2008 Jiri Benc <jbenc@upir.cz>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <hildon/hildon-caption.h>
25 #include <hildon/hildon-banner.h>
27 #include <gconf/gconf.h>
28 #include <gconf/gconf-client.h>
31 #define GETTEXT_PACKAGE "osso-applet-textinput"
33 #include <hildon/hildon.h>
34 #include <glib/gi18n-lib.h>
52 HildonCheckButton *word_compl;
53 HildonCheckButton *auto_cap;
54 HildonCheckButton *sp_after;
55 HildonPickerButton *sec_dictsel;
56 HildonTouchSelector *langsel[2];
57 HildonTouchSelector *dictsel[2];
58 HildonCheckButton *dual;
60 GtkComboBox *langsel[2];
61 GtkButton *settings[2];
62 GtkToggleButton *dual;
67 static gchar *get_lang(GConfClient *client, int n)
69 char *tmp = g_strdup_printf("/apps/osso/inputmethod/hildon-im-languages/language-%d", n);
72 res = gconf_client_get_string(client, tmp, NULL);
77 static void set_lang(GConfClient *client, int n, gchar *val)
79 char *tmp = g_strdup_printf("/apps/osso/inputmethod/hildon-im-languages/language-%d", n);
81 gconf_client_set_string(client, tmp, val, NULL);
85 static gchar *read_vkb_str(FILE *f)
90 if (!fread(&len, 1, 1, f) || !len)
92 res = g_malloc(len + 1);
93 if (fread(res, 1, len, f) != len) {
101 static struct lang *read_vkb(gchar *path)
104 struct lang *res = NULL;
108 f = fopen(path, "r");
112 if (!fread(&ver, 1, 1, f) || ver != 1)
114 /* number of sections */
115 if (!fread(&ver, 1, 1, f))
117 /* descriptive name */
118 desc = read_vkb_str(f);
122 code = read_vkb_str(f);
128 res = g_malloc(sizeof(struct lang));
136 static GList *add_lang_link(gchar *path, gchar *dest, GList *list)
137 /* 'dest' has to be allocated; it's eaten by this function! */
139 struct langlink *langlink;
142 link = g_file_read_link(path, NULL);
144 langlink = g_malloc(sizeof(struct langlink));
145 langlink->dest = dest;
146 tmp = strrchr(link, '/');
147 langlink->src = tmp ? tmp + 1 : link;
148 tmp = strrchr(link, '.');
151 langlink->src = g_strdup(langlink->src);
153 list = g_list_append(list, langlink);
158 static GList *get_langs(gchar *path, GList **langlinks, GList *list)
162 gchar *fullpath, *shortpath, *tmp;
165 d = g_dir_open(path, 0, NULL);
168 while ((fname = g_dir_read_name(d))) {
169 if (!g_str_has_suffix(fname, ".vkb"))
171 fullpath = g_strjoin("/", path, fname, NULL);
172 shortpath = g_strdup(fname);
173 tmp = strrchr(shortpath, '.');
176 if (langlinks && g_file_test(fullpath, G_FILE_TEST_IS_SYMLINK)) {
177 *langlinks = add_lang_link(fullpath, shortpath, *langlinks);
181 lang = read_vkb(fullpath);
183 lang->fname = shortpath;
184 lang->ext = !langlinks;
185 list = g_list_append(list, lang);
194 static struct lang *get_def_lang(gchar *code, GList *langs, GList *langlinks)
198 struct langlink *langlink;
202 for (item = langs; item; item = g_list_next(item)) {
204 if (!strcmp(lang->fname, code))
208 for (item = langlinks; item; item = g_list_next(item)) {
209 langlink = item->data;
210 if (!strcmp(langlink->dest, code))
211 return get_def_lang(langlink->src, langs, NULL);
216 static void free_langs(GList *list)
221 for (item = list; item; item = g_list_next(item)) {
231 static void free_langlinks(GList *list)
234 struct langlink *langlink;
236 for (item = list; item; item = g_list_next(item)) {
237 langlink = item->data;
238 g_free(langlink->src);
239 g_free(langlink->dest);
246 static void fill_langsel(HildonTouchSelector *combo, GList *langs, struct lang *deflang, gboolean empty)
252 for (item = langs, i = 0; item; item = g_list_next(item), i++) {
254 hildon_touch_selector_append_text(combo, lang->desc);
256 hildon_touch_selector_set_active(combo, 0, i);
259 hildon_touch_selector_append_text(combo, _("tein_fi_not_in_use"));
261 hildon_touch_selector_set_active(combo, 0, i);
265 static void fill_langsel(GtkComboBox *combo, GList *langs, struct lang *deflang, gboolean empty)
271 for (item = langs, i = 0; item; item = g_list_next(item), i++) {
273 gtk_combo_box_append_text(combo, lang->desc);
275 gtk_combo_box_set_active(combo, i);
278 gtk_combo_box_append_text(combo, "");
280 gtk_combo_box_set_active(combo, i);
285 static void sensitivity_langsel(struct data *d)
290 sens = (hildon_touch_selector_get_active(d->langsel[1], 0) < d->num_langs);
291 gtk_widget_set_sensitive(GTK_WIDGET(d->dual), sens);
294 gtk_widget_show(GTK_WIDGET(d->sec_dictsel));
296 gtk_widget_hide(GTK_WIDGET(d->sec_dictsel));
298 sens = (gtk_combo_box_get_active(d->langsel[1]) < d->num_langs);
299 gtk_widget_set_sensitive(GTK_WIDGET(d->settings[1]), sens);
300 gtk_widget_set_sensitive(GTK_WIDGET(d->dual), sens);
306 static void verify_langsel(HildonTouchSelector *combo, gint column, struct data *d)
308 struct lang *lang[2];
313 for (i = 0; i < 2; i++) {
314 res = hildon_touch_selector_get_active(d->langsel[i], column);
315 lang[i] = (res >= 0) ? g_list_nth_data(d->langs, res) : NULL;
317 if (lang[0] && lang[1] && !strcmp(lang[0]->code, lang[1]->code)) {
318 hildon_banner_show_information(d->win, "gtk-dialog-error",
319 "Impossible combination of languages");
320 hildon_touch_selector_set_active(d->langsel[1], column, d->num_langs);
322 sensitivity_langsel(d);
325 static void verify_langsel(GtkComboBox *combo, struct data *d)
327 struct lang *lang[2];
332 for (i = 0; i < 2; i++) {
333 res = gtk_combo_box_get_active(d->langsel[i]);
334 lang[i] = (res >= 0) ? g_list_nth_data(d->langs, res) : NULL;
336 if (lang[0] && lang[1] && !strcmp(lang[0]->code, lang[1]->code)) {
337 hildon_banner_show_information(d->win, "gtk-dialog-error",
338 "Impossible combination of languages");
339 gtk_combo_box_set_active(d->langsel[1], d->num_langs);
341 sensitivity_langsel(d);
344 static void do_settings(GtkButton *button, struct data *d)
348 which = (button == d->settings[0]) ? 0 : 1;
349 lang_settings(d->client, d->win, d->langs, gtk_combo_box_get_active(d->langsel[which]));
354 static GtkWidget *start(GConfClient *client, GtkWidget *win, void **data)
358 GtkWidget *vbox, *table;
362 d = g_new0(struct data, 1);
366 d->langs = get_langs("/usr/share/keyboards", &d->langlinks, NULL);
367 d->langs = get_langs("/usr/share/ukeyboard", NULL, d->langs);
368 d->num_langs = g_list_length(d->langs);
370 vbox = gtk_vbox_new(FALSE, 0);
372 d->word_compl = HILDON_CHECK_BUTTON(hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT));
373 gtk_button_set_label (GTK_BUTTON (d->word_compl), _("tein_fi_settings_word_completion"));
374 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(d->word_compl), TRUE, TRUE, 0);
376 d->auto_cap = HILDON_CHECK_BUTTON(hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT));
377 gtk_button_set_label (GTK_BUTTON (d->auto_cap), _("tein_fi_settings_auto_capitalization"));
378 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(d->auto_cap), TRUE, TRUE, 0);
380 d->sp_after = HILDON_CHECK_BUTTON(hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT));
381 gtk_button_set_label (GTK_BUTTON (d->sp_after), _("tein_fi_settings_space_after_word"));
382 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(d->sp_after), TRUE, TRUE, 0);
384 table = gtk_table_new(2, 2, TRUE);
385 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
387 for (i = 0; i < 2; i++) {
391 d->langsel[i] = HILDON_TOUCH_SELECTOR(hildon_touch_selector_new_text());
392 code = get_lang(client, i);
393 fill_langsel(d->langsel[i], d->langs, get_def_lang(code, d->langs, d->langlinks), i == 1);
394 g_signal_connect(G_OBJECT(d->langsel[i]), "changed", G_CALLBACK(verify_langsel), d);
396 button = hildon_picker_button_new(HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
397 hildon_button_set_title(HILDON_BUTTON(button), i == 0 ? _("tein_fi_primary_language") : _("tein_fi_secondary_language"));
398 hildon_picker_button_set_selector(HILDON_PICKER_BUTTON (button), d->langsel[i]);
399 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 0.0);
400 hildon_button_set_title_alignment(HILDON_BUTTON(button), 0.0, 0.5);
401 hildon_button_set_value_alignment (HILDON_BUTTON (button), 0.0, 0.5);
402 gtk_table_attach_defaults(GTK_TABLE(table), button, 0, 1, i, i + 1);
404 d->dictsel[i] = HILDON_TOUCH_SELECTOR(hildon_touch_selector_new_text());
405 tmp = get_l_str(client, code, "dictionary");
406 lang = get_def_lang(code, d->langs, d->langlinks);
408 /* If tmp is NULL (i.e. the gconf key is unset), try to use the same
409 * dictionary as the keyboard. But don't do this if the keyboard is
410 * from our package. */
411 fill_dict(d->dictsel[i], d->langs, (tmp || (lang && lang->ext)) ? tmp : code);
415 button = hildon_picker_button_new(HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
416 hildon_button_set_title(HILDON_BUTTON(button), _("tein_fi_settings_dictionary"));
417 hildon_picker_button_set_selector(HILDON_PICKER_BUTTON (button), d->dictsel[i]);
418 hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 0.0);
419 hildon_button_set_title_alignment(HILDON_BUTTON(button), 0.0, 0.5);
420 hildon_button_set_value_alignment (HILDON_BUTTON (button), 0.0, 0.5);
421 gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, i, i + 1);
424 d->sec_dictsel = HILDON_PICKER_BUTTON(button);
426 hildon_check_button_set_active(d->word_compl, get_l_bool(client, code, "word-completion"));
427 hildon_check_button_set_active(d->auto_cap, get_l_bool(client, code, "auto-capitalisation"));
428 hildon_check_button_set_active(d->sp_after, get_l_bool(client, code, "insert-space-after-word"));
435 d->dual = HILDON_CHECK_BUTTON(hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT));
436 hildon_check_button_set_active(d->dual, get_bool(client, "dual-dictionary"));
437 gtk_button_set_label (GTK_BUTTON (d->dual), _("tein_fi_dual_dictionary_use"));
438 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(d->dual), TRUE, TRUE, 0);
440 gtk_widget_show_all(vbox);
442 sensitivity_langsel(d);
449 static GtkWidget *start(GConfClient *client, GtkWidget *win, void **data)
458 d = g_new0(struct data, 1);
462 d->langs = get_langs("/usr/share/keyboards", &d->langlinks, NULL);
463 d->langs = get_langs("/usr/share/ukeyboard", NULL, d->langs);
464 d->num_langs = g_list_length(d->langs);
466 vbox = GTK_BOX(gtk_vbox_new(FALSE, 0));
467 gtk_box_set_spacing(vbox, 5);
468 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
470 for (i = 0; i < 2; i++) {
471 d->langsel[i] = GTK_COMBO_BOX(gtk_combo_box_new_text());
473 tmp = get_lang(client, i);
474 fill_langsel(d->langsel[i], d->langs, get_def_lang(tmp, d->langs, d->langlinks), i == 1);
478 g_signal_connect(G_OBJECT(d->langsel[i]), "changed", G_CALLBACK(verify_langsel), d);
479 gtk_box_pack_start_defaults(vbox, hildon_caption_new(group, i == 0 ? "1st language" : "2nd language",
480 GTK_WIDGET(d->langsel[i]), NULL, HILDON_CAPTION_MANDATORY));
482 d->settings[i] = GTK_BUTTON(gtk_button_new_with_label("Settings"));
483 g_signal_connect(G_OBJECT(d->settings[i]), "clicked", G_CALLBACK(do_settings), d);
484 gtk_box_pack_start_defaults(vbox, hildon_caption_new(group, NULL,
485 GTK_WIDGET(d->settings[i]), NULL, HILDON_CAPTION_OPTIONAL));
488 d->dual = GTK_TOGGLE_BUTTON(gtk_check_button_new());
489 gtk_toggle_button_set_active(d->dual, get_bool(client, "dual-dictionary"));
490 gtk_box_pack_start_defaults(vbox, hildon_caption_new(group, "Use dual dictionaries",
491 GTK_WIDGET(d->dual), NULL, HILDON_CAPTION_MANDATORY));
493 sensitivity_langsel(d);
495 g_object_unref(G_OBJECT(group));
498 align = gtk_alignment_new(0, 0, 1, 0);
499 gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(vbox));
504 static void action(GConfClient *client, void *data)
506 struct data *d = data;
512 for (i = 0; i < 2; i++) {
516 res = hildon_touch_selector_get_active(d->langsel[i], 0);
518 res = gtk_combo_box_get_active(d->langsel[i]);
522 lang = g_list_nth_data(d->langs, res);
525 tmp = g_strdup_printf("sudo /usr/libexec/ukeyboard-set %s %s", lang->fname, lang->code);
527 hildon_banner_show_information(d->win, "gtk-dialog-warning",
531 /* When the newly set layout has the same lang code as the
532 * previous one (but the underlaying file changed), setting
533 * the same value won't trigger layout reload. Workaround
534 * that by setting "en_GB" lang code first. */
535 set_lang(client, i, "en_GB");
536 set_lang(client, i, lang->code);
538 set_l_bool(client, lang->code, "auto-capitalisation", hildon_check_button_get_active(d->auto_cap));
539 set_l_bool(client, lang->code, "word-completion", hildon_check_button_get_active(d->word_compl));
540 set_l_bool(client, lang->code, "insert-space-after-word", hildon_check_button_get_active(d->sp_after));
542 res = hildon_touch_selector_get_active(d->dictsel[i], 0);
544 dict = g_list_nth_data(d->langs, res);
546 if (dict && !dict->ext)
547 set_l_str(client, lang->code, "dictionary", dict->code);
549 set_l_str(client, lang->code, "dictionary", "");
552 set_lang(client, i, "");
555 set_bool(client, "dual-dictionary", hildon_check_button_get_active(d->dual));
557 set_bool(client, "dual-dictionary", gtk_toggle_button_get_active(d->dual));
561 static void stop(GConfClient *client, void *data)
563 struct data *d = data;
567 free_langs(d->langs);
568 free_langlinks(d->langlinks);
572 void prefs_lang_init(struct prefs *prefs)
574 prefs->start = start;
575 prefs->action = action;
577 prefs->name = "Languages";