Fixed translation of language selector.
[mstardict] / src / tts.cpp
1 /*
2  *  MStarDict - International dictionary for Maemo.
3  *  Copyright (C) 2010 Roman Moravcik
4  *
5  *  base on code of stardict:
6  *  Copyright (C) 2003-2007 Hu Zheng <huzheng_001@163.com>
7  *
8  *  based on code of sdcv:
9  *  Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <string>
31 #include <vector>
32 #include <memory>
33 #include <list>
34
35 #include <glib.h>
36 #include <glib/gi18n.h>
37
38 #include <gtk/gtk.h>
39 #include <hildon/hildon.h>
40
41 #include "conf.hpp"
42 #include "tts.hpp"
43 #include "mstardict.hpp"
44
45 #include <espeak/speak_lib.h>
46
47 enum {
48     DISPNAME_COLUMN,
49     NAME_COLUMN,
50     N_COLUMNS
51 };
52
53 enum {
54     GENDER_NONE = 0,
55     GENDER_MALE,
56     GENDER_FEMALE
57 };
58
59 static TtsVoice voices[] = {
60     {"afrikaans",               N_("Afrikaans")},
61     {"bosnian",                 N_("Bosnian")},
62     {"catalan",                 N_("Catalan")},
63     {"czech",                   N_("Czech")},
64     {"welsh-test",              N_("Welsh")},
65     {"danish",                  N_("Danish")},
66     {"german",                  N_("German")},
67     {"greek",                   N_("Greek")},
68     {"en-scottish",             N_("English (Scottish)")},
69     {"english",                 N_("English")},
70     {"lancashire",              N_("English (Lancashire)")},
71     {"english_rp",              N_("English (Received Pronunciation)")},
72     {"english_wmids",           N_("English (West Midlands)")},
73     {"english-us",              N_("English (American)")},
74     {"en-westindies",           N_("English (Westindies)")},
75     {"esperanto",               N_("Esperanto")},
76     {"spanish",                 N_("Spanish")},
77     {"spanish-latin-american",  N_("Spanish (Latin American)")},
78     {"finnish",                 N_("Finnish")},
79     {"french",                  N_("French")},
80     {"french (Belgium)",        N_("French (Belgium)")},
81     {"greek-ancient",           N_("Greek (Ancient)")},
82     {"hindi-test",              N_("Hindi")},
83     {"croatian",                N_("Croatian")},
84     {"hungarian",               N_("Hungarian")},
85     {"armenian",                N_("Armenian")},
86     {"armenian-west",           N_("Armenian (West)")},
87     {"indonesian-test",         N_("Indonesian")},
88     {"icelandic-test",          N_("Icelandic")},
89     {"italian",                 N_("Italian")},
90     {"lojban",                  N_("Lojban")},
91     {"kurdish",                 N_("Kurdish")},
92     {"latin",                   N_("Latin")},
93     {"latvian",                 N_("Latvian")},
94     {"macedonian-test",         N_("Macedonian")},
95     {"dutch-test",              N_("Dutch")},
96     {"norwegian",               N_("Norwegian")},
97     {"papiamento-test",         N_("Papiamento")},
98     {"polish",                  N_("Polish")},
99     {"brazil",                  N_("Brazil")},
100     {"portugal",                N_("Portugal")},
101     {"romanian",                N_("Romanian")},
102     {"russian_test",            N_("Russian")},
103     {"slovak",                  N_("Slovak")},
104     {"albanian",                N_("Albanian")},
105     {"serbian",                 N_("Serbian")},
106     {"swedish",                 N_("Swedish")},
107     {"swahihi-test",            N_("Swahihi")},
108     {"tamil",                   N_("Tamil")},
109     {"turkish",                 N_("Turkish")},
110     {"vietnam-test",            N_("Vietnam")},
111     {"Mandarin",                N_("Chinese (Mandarin)")},
112     {"cantonese-test",          N_("Chinese (Cantonese)")},
113     {"default",                 N_("Default")},
114     {NULL,                      NULL}
115 };
116
117
118 Tts::Tts(MStarDict *mStarDict)
119 {
120     int rate = 0;
121     bool tts_enabled = false;
122     gchar *language = NULL;
123     int gender = GENDER_NONE;
124
125     oStarDict = mStarDict;
126     Enabled = false;
127
128     /* initialize espeak */
129     rate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 512, NULL, 0);
130
131     /* check if tts is enabled */
132     if (!oStarDict->oConf->GetBool("/apps/maemo/mstardict/tts_enabled", &tts_enabled)) {
133         tts_enabled = true;
134     }
135     Enable(tts_enabled);
136
137     /* read configured language */
138     if (!oStarDict->oConf->GetString("/apps/maemo/mstardict/tts_language", &language)) {
139         language = g_strdup("english");
140     }
141
142     /* read configured gender */
143     if (!oStarDict->oConf->GetInt("/apps/maemo/mstardict/tts_gender", &gender)) {
144         gender = GENDER_MALE;
145     }
146     SetVoice(language, gender);
147
148     if (language) {
149         g_free(language);
150     }
151 }
152
153 Tts::~Tts()
154 {
155     /* deinitialize espeak */
156     espeak_Terminate();
157 }
158
159 void
160 Tts::Enable(bool bEnable)
161 {
162     Enabled = bEnable;
163 }
164
165 bool
166 Tts::IsEnabled()
167 {
168     return Enabled;
169 }
170
171 void
172 Tts::SetVoice(const gchar *language, int gender)
173 {
174     espeak_VOICE voice;
175
176     memset(&voice, 0, sizeof(espeak_VOICE));
177     voice.name = language;
178     voice.gender = gender;
179
180     espeak_SetVoiceByProperties(&voice);
181 }
182
183 void
184 Tts::SayText(const gchar *sText)
185 {
186     espeak_Synth(sText, strlen(sText) + 1, 0, POS_CHARACTER, 0, espeakCHARS_UTF8, NULL, NULL);
187 }
188
189 GtkListStore *
190 Tts::GetVoicesList()
191 {
192     const espeak_VOICE **espeak_voices;
193     GtkListStore *list_store;
194     GtkTreeIter iter;
195     size_t i = 0;
196
197     list_store = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
198
199     espeak_voices = espeak_ListVoices(NULL);
200     while (espeak_voices[i]) {
201         gchar *disp_name = NULL;
202
203         for (int j = 0; voices[j].name != NULL; j++) {
204             if (!strcmp(espeak_voices[i]->name, voices[j].name)) {
205                 disp_name = g_strdup(_(voices[j].disp_name));
206                 break;
207             }
208         }
209
210         if (disp_name == NULL)
211             disp_name = g_strdup(espeak_voices[i]->name);
212
213         gtk_list_store_append(list_store, &iter);
214         gtk_list_store_set(list_store,
215                            &iter,
216                            DISPNAME_COLUMN, disp_name,
217                            NAME_COLUMN, espeak_voices[i]->name,
218                            -1);
219
220         if (disp_name)
221             g_free(disp_name);
222
223         i++;
224     }
225     return list_store;
226 }
227
228 gboolean
229 Tts::onTtsEnableButtonClicked(GtkButton *button,
230                               Tts *oTts)
231 {
232     if (hildon_check_button_get_active(HILDON_CHECK_BUTTON(button))) {
233         gtk_widget_set_sensitive(GTK_WIDGET(oTts->gender_male_button), TRUE);
234         gtk_widget_set_sensitive(GTK_WIDGET(oTts->gender_female_button), TRUE);
235         gtk_widget_set_sensitive(GTK_WIDGET(oTts->language_button), TRUE);
236     } else {
237         gtk_widget_set_sensitive(GTK_WIDGET(oTts->gender_male_button), FALSE);
238         gtk_widget_set_sensitive(GTK_WIDGET(oTts->gender_female_button), FALSE);
239         gtk_widget_set_sensitive(GTK_WIDGET(oTts->language_button), FALSE);
240     }
241     return true;
242 }
243
244 gboolean
245 Tts::onTtsGenderButtonClicked(GtkToggleButton *button1,
246                               GtkToggleButton *button2)
247 {
248     if (gtk_toggle_button_get_active(button1))
249         gtk_toggle_button_set_active(button2, FALSE);
250     else
251         gtk_toggle_button_set_active(button2, TRUE);
252     return true;
253 }
254
255 GtkWidget *
256 Tts::CreateTtsConfWidget()
257 {
258     GtkWidget *frame, *vbox, *hbox;
259     GtkWidget *selector;
260     HildonTouchSelectorColumn *column;
261     GtkListStore *voices_list;
262
263     frame = gtk_frame_new(_("Text-To-Speech"));
264
265     vbox = gtk_vbox_new(FALSE, 0);
266     gtk_container_add(GTK_CONTAINER(frame), vbox);
267
268     /* enable tts button */
269     enable_button = hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT);
270     gtk_button_set_label(GTK_BUTTON(enable_button), _("Enable"));
271     gtk_box_pack_start(GTK_BOX(vbox), enable_button, TRUE, TRUE, 0);
272
273     /* gender selection */
274     hbox = gtk_hbox_new(TRUE, 0);
275     gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
276
277     gender_male_button = hildon_gtk_toggle_button_new(HILDON_SIZE_FINGER_HEIGHT);
278     gtk_button_set_label(GTK_BUTTON(gender_male_button), _("Male"));
279     gtk_box_pack_start(GTK_BOX(hbox), gender_male_button, TRUE, TRUE, 0);
280
281     gender_female_button = hildon_gtk_toggle_button_new(HILDON_SIZE_FINGER_HEIGHT);
282     gtk_button_set_label(GTK_BUTTON(gender_female_button), _("Female"));
283     gtk_box_pack_start(GTK_BOX(hbox), gender_female_button, TRUE, TRUE, 0);
284
285     /* language picker button */
286     language_button = hildon_picker_button_new(HILDON_SIZE_FINGER_HEIGHT,
287                                                HILDON_BUTTON_ARRANGEMENT_VERTICAL);
288     hildon_button_set_title(HILDON_BUTTON(language_button), _("Language"));
289     hildon_button_set_alignment(HILDON_BUTTON(language_button), 0.0, 0.5, 1.0, 0.0);
290     hildon_button_set_title_alignment(HILDON_BUTTON(language_button), 0.0, 0.5);
291     gtk_box_pack_start(GTK_BOX(vbox), language_button, TRUE, TRUE, 0);
292
293     /* get list of voices */
294     voices_list = GetVoicesList();
295
296     /* sort list of voices */
297     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(voices_list),
298                                          DISPNAME_COLUMN, GTK_SORT_ASCENDING);
299
300     /* voices selector */
301     selector = hildon_touch_selector_new();
302     column = hildon_touch_selector_append_text_column(HILDON_TOUCH_SELECTOR(selector),
303                                                       GTK_TREE_MODEL(voices_list), TRUE);
304     g_object_set(G_OBJECT(column), "text-column", DISPNAME_COLUMN, NULL);
305
306     hildon_picker_button_set_selector(HILDON_PICKER_BUTTON(language_button),
307                                       HILDON_TOUCH_SELECTOR(selector));
308
309     g_signal_connect(enable_button, "clicked", G_CALLBACK(onTtsEnableButtonClicked), this);
310     g_signal_connect(gender_male_button, "clicked", G_CALLBACK(onTtsGenderButtonClicked), gender_female_button);
311     g_signal_connect(gender_female_button, "clicked", G_CALLBACK(onTtsGenderButtonClicked), gender_male_button);
312
313     return frame;
314 }
315
316 void
317 Tts::TtsConfWidgetLoadConf()
318 {
319     HildonTouchSelector *selector;
320     GtkTreeIter iter;
321     int gender = GENDER_NONE;
322     gchar *language = NULL;
323     GtkTreeModel *model;
324     gboolean iter_valid = TRUE;
325
326     if (IsEnabled()) {
327         hildon_check_button_set_active(HILDON_CHECK_BUTTON(enable_button), TRUE);
328         gtk_widget_set_sensitive(language_button, TRUE);
329     } else {
330         hildon_check_button_set_active(HILDON_CHECK_BUTTON(enable_button), FALSE);
331         gtk_widget_set_sensitive(language_button, FALSE);
332     }
333
334     if (oStarDict->oConf->GetInt("/apps/maemo/mstardict/tts_gender", &gender)) {
335         if (gender == GENDER_MALE)
336             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gender_male_button), TRUE);
337         else
338             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gender_female_button), TRUE);
339     } else {
340             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gender_male_button), TRUE);
341     }
342
343     if (oStarDict->oConf->GetString("/apps/maemo/mstardict/tts_language", &language)) {
344         if (language) {
345             selector = hildon_picker_button_get_selector(HILDON_PICKER_BUTTON(language_button));
346             model = hildon_touch_selector_get_model(HILDON_TOUCH_SELECTOR(selector), DISPNAME_COLUMN);
347             for (iter_valid = gtk_tree_model_get_iter_first(model, &iter); iter_valid; iter_valid = gtk_tree_model_iter_next(model, &iter)) {
348                 const gchar *tmp;
349                 gtk_tree_model_get(model, &iter, NAME_COLUMN, &tmp, -1);
350                 if (strcmp(tmp, language) == 0) {
351                     hildon_touch_selector_select_iter(HILDON_TOUCH_SELECTOR(selector), DISPNAME_COLUMN, &iter, FALSE);
352                     break;
353                 }
354             }
355             g_free(language);
356         }
357     } else {
358         hildon_picker_button_set_active (HILDON_PICKER_BUTTON (language_button), -1);
359     }
360 }
361
362 void
363 Tts::TtsConfWidgetSaveConf()
364 {
365     bool enabled = false;
366     HildonTouchSelector *selector;
367     GtkTreeIter iter;
368     int gender = GENDER_NONE;
369     const gchar *language;
370
371     enabled = hildon_check_button_get_active(HILDON_CHECK_BUTTON(enable_button));
372     if (oStarDict->oConf->SetBool("/apps/maemo/mstardict/tts_enabled", enabled))
373         Enable(enabled);
374
375     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gender_male_button)))
376         gender = GENDER_MALE;
377     else
378         gender = GENDER_FEMALE;
379     oStarDict->oConf->SetInt("/apps/maemo/mstardict/tts_gender", gender);
380
381     if (hildon_picker_button_get_active(HILDON_PICKER_BUTTON(language_button)) > -1) {
382         selector = hildon_picker_button_get_selector(HILDON_PICKER_BUTTON(language_button));
383         if (hildon_touch_selector_get_selected(selector, DISPNAME_COLUMN, &iter)) {
384             gtk_tree_model_get(hildon_touch_selector_get_model(selector, DISPNAME_COLUMN), &iter, NAME_COLUMN, &language, -1);
385
386             /* fixme convert back disp_name */
387             if (oStarDict->oConf->SetString("/apps/maemo/mstardict/tts_language", language))
388                 SetVoice(language, gender);
389         }
390     }
391 }