Support language change in runtime
[platform/core/uifw/inputmethod-setting.git] / im_setting_list / input_method_setting_list_ui.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 #include "input_method_setting_list.h"
18 #include "input_method_setting_list_ui.h"
19 #include "input_method_setting_list_popup_view.h"
20 #include <string>
21 #include <app.h>
22 #include <vector>
23 #include <algorithm>
24 #include <tzplatform_config.h>
25 #include <inputmethod_manager.h>
26 #include <package_manager.h>
27
28 #include "isf_control.h"
29
30 #define IM_SETTING_LIST_PACKAGE                 PACKAGE
31 #define IM_SETTING_LIST_LOCALE_DIR              tzplatform_mkpath(TZ_SYS_RO_APP, PACKAGE_NAME"/res/locale")
32 #define IM_SETTING_LIST_TITLE                   "IDS_IME_BODY_KEYBOARD"
33 #define IM_SETTING_LIST_KEYBOARD_HEADER         "IDS_ST_HEADER_KEYBOARDS"
34 #define IM_SETTING_LIST_POPUP_TITLE             "IDS_ST_BODY_ATTENTION"
35 #define IM_SETTING_LIST_POPUP_CANCEL            "IDS_COM_SK_CANCEL_ABB"
36 #define IM_SETTING_LIST_POPUP_ENABLE            "IDS_ST_BUTTON_ENABLE"
37 #define IM_SETTING_LIST_VIRTUAL_KEYBOARD        "IDS_ST_HEADER_VIRTUAL_KEYBOARD"
38 #define IM_SETTING_LIST_DEFAULT_KEYBOARD        "IDS_ST_HEADER_DEFAULT_KEYBOARD_ABB"
39 #define IM_SETTING_LIST_KEYBOARD_SETTING        "IDS_IME_HEADER_KEYBOARD_SETTINGS_ABB"
40 #define IM_SETTING_LIST_TURNON_KEYBOARD         "IDS_ST_BUTTON_TURN_ON_KEYBOARD_ABB"
41 #define IM_SETTING_LIST_TURNON                  "IDS_ST_BUTTON_TURN_ON_ABB3"
42 #define IM_SETTING_LIST_POPUP_TEXT              dgettext(PACKAGE, "IDS_ST_POP_THIS_INPUT_METHOD_MAY_BE_ABLE_TO_COLLECT_ALL_THE"\
43                                                                   "_TEXT_YOU_TYPE_INCLUDING_PERSONAL_DATA_LIKE_PASSWORDS_AND"\
44                                                                   "_CREDIT_CARD_NUMBERS_MSG")
45
46
47 typedef struct list_item_text_s
48 {
49     char main_text[255];
50     char sub_text[255];
51 } list_item_text;
52
53 typedef struct popup_cb_data_s
54 {
55     Evas_Object *popup;
56     void *data;
57 } popup_cb_data;
58
59 typedef struct gen_item_data_s
60 {
61     Elm_Object_Item *gen_item;
62     int chk_status;
63 } gen_item_data;
64
65 typedef struct _Item_Data
66 {
67     int index;
68     Elm_Object_Item *item;
69 } Item_Data;
70
71 class ime_info_compare
72 {
73     public:
74     bool operator()(const ime_info_s &first, const ime_info_s &sec)
75     {
76         return (strcasecmp(first.label, sec.label) < 0);
77     }
78 };
79
80 typedef void (*popup_ok_cb)(void *data, Evas_Object *obj, void *event_info);
81 typedef void (*popup_cancel_cb)(void *data, Evas_Object *obj, void *event_info);
82
83 static std::vector<ime_info_s>      g_ime_info_list;
84 static Elm_Genlist_Item_Class       *itc_im_list_keyboard_list = NULL;
85 static Elm_Genlist_Item_Class       *itc_im_list_group = NULL;
86 static Elm_Genlist_Item_Class       *itc_im_list_item = NULL;
87 static Elm_Genlist_Item_Class       *itc_im_list_item_one_line = NULL;
88 static Elm_Genlist_Item_Class       *itc_im_list_title = NULL;
89 static int                          g_active_ime_index = -1;
90 static list_item_text               item_text[2];
91 static std::vector<gen_item_data>   g_gen_item_data;
92 static package_manager_h            pkgmgr = NULL;
93
94 void im_setting_list_update_window(void *data);
95
96 static void im_setting_list_text_domain_set(void)
97 {
98     bindtextdomain(IM_SETTING_LIST_PACKAGE, IM_SETTING_LIST_LOCALE_DIR);
99     textdomain(IM_SETTING_LIST_PACKAGE);
100 }
101
102 static Evas_Object *
103 im_setting_list_main_window_create(const char *name, int app_type)
104 {
105     Evas_Object *eo = NULL;
106     eo = elm_win_add(NULL, name, ELM_WIN_BASIC);
107     if (eo) {
108         elm_win_title_set(eo, name);
109         elm_win_borderless_set(eo, EINA_TRUE);
110         elm_win_alpha_set(eo, EINA_FALSE);
111         elm_win_conformant_set(eo, EINA_TRUE);
112         elm_win_autodel_set(eo, EINA_TRUE);
113         if (app_type != APP_TYPE_SETTING_NO_ROTATION) {
114             int rots[4] = {0, 90, 180, 270};
115             elm_win_wm_rotation_available_rotations_set(eo, rots, 4);
116         }
117     }
118     return eo;
119 }
120
121 static Evas_Object* im_setting_list_bg_create(Evas_Object *parent)
122 {
123     Evas_Object *bg;
124     if (parent == NULL) return NULL;
125     bg = elm_bg_add(parent);
126     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
127     elm_win_resize_object_add(parent, bg);
128     evas_object_show(bg);
129     return bg;
130 }
131
132 static void im_setting_list_sort_ime_info(std::vector<ime_info_s> &preinstall, std::vector<ime_info_s> &user)
133 {
134     std::sort(preinstall.begin(), preinstall.end(), ime_info_compare());
135     std::sort(user.begin(), user.end(), ime_info_compare());
136     for (unsigned int i = 0; i < preinstall.size(); ++i)
137     {
138         g_ime_info_list.push_back(preinstall[i]);
139     }
140     for (unsigned int i = 0; i < user.size(); ++i)
141     {
142         g_ime_info_list.push_back(user[i]);
143     }
144 }
145
146 static void im_setting_list_load_ime_info(void)
147 {
148     std::vector<ime_info_s>      ime_info_list_preinstall;
149     std::vector<ime_info_s>      ime_info_list_user;
150     ime_info_s *info = NULL;
151     g_ime_info_list.clear();
152     int cnt = isf_control_get_all_ime_info(&info);
153     if (info) {
154         for (int i = 0; i < cnt; ++i)
155         {
156             SECURE_LOGD("%s %s %d %d %d\n", info[i].appid, info[i].label, info[i].is_enabled, info[i].is_preinstalled, info[i].has_option);
157             if (info[i].is_preinstalled) {
158                 ime_info_list_preinstall.push_back(info[i]);
159             } else {
160                 ime_info_list_user.push_back(info[i]);
161             }
162         }
163         free(info);
164     } else {
165         LOGW("isf_control_get_all_ime_info failed\n");
166     }
167     im_setting_list_sort_ime_info(ime_info_list_preinstall, ime_info_list_user);
168 }
169
170 static int im_setting_list_get_active_ime_index(void)
171 {
172     char *active_ime_appid = NULL;
173
174     int ret = ime_manager_get_active_ime(&active_ime_appid);
175     if (ret == IME_MANAGER_ERROR_NONE)
176         LOGD("get active ime : %s\n", active_ime_appid);
177     else
178         LOGW("Failed to get active ime. error : %d\n", ret);
179
180     std::vector<ime_info_s>::iterator iter = g_ime_info_list.begin();
181     std::vector<ime_info_s>::iterator end = g_ime_info_list.end();
182     for (; iter != end; ++iter)
183     {
184         if (active_ime_appid && (!strcmp(active_ime_appid, iter->appid)))
185         {
186             break;
187         }
188     }
189     if (active_ime_appid)
190     {
191         free(active_ime_appid);
192     }
193     return (iter - g_ime_info_list.begin());
194 }
195
196 static void
197 im_setting_list_check_popup_ok_cb(void *data, Evas_Object *obj, void *event_info)
198 {
199     popup_cb_data *cb_data = (popup_cb_data *)data;
200     if (!cb_data)
201         return;
202     int index = (int)reinterpret_cast<long>(cb_data->data);
203     if (index < 0 || index >= (int)g_ime_info_list.size()) {
204         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
205         return;
206     }
207     Eina_Bool state = EINA_FALSE;
208     state = g_gen_item_data[index].chk_status;
209     if (isf_control_set_enable_ime(g_ime_info_list[index].appid, state) != 0)
210         LOGW("Failed to set enable ime : %s\n", g_ime_info_list[index].appid);
211
212     evas_object_del(cb_data->popup);
213 }
214
215 static void
216 im_setting_list_check_popup_cancel_cb(void *data, Evas_Object *obj, void *event_info)
217 {
218     popup_cb_data *cb_data = (popup_cb_data *)data;
219     if (!cb_data)
220         return;
221     int index = (int)reinterpret_cast<long>(cb_data->data);
222     if (index < 0 || index >= (int)g_ime_info_list.size()) {
223         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
224         return;
225     }
226
227     Eina_Bool state = g_gen_item_data[index].chk_status;
228     if (isf_control_set_enable_ime(g_ime_info_list[index].appid, !state) == 0) {
229         g_gen_item_data[index].chk_status = !state;
230         elm_genlist_item_update(g_gen_item_data[index].gen_item);
231     } else {
232         LOGW("Failed to set enable ime : %s\n", g_ime_info_list[index].appid);
233     }
234
235     evas_object_del(cb_data->popup);
236 }
237
238 static void _popup_back_cb(void *data, Evas_Object *obj, void *event_info)
239 {
240     eext_object_event_callback_del(obj, EEXT_CALLBACK_BACK, _popup_back_cb);
241     popup_cb_data *cb_data = (popup_cb_data *)data;
242     if (!cb_data)
243         return;
244     int index = (int)reinterpret_cast<long>(cb_data->data);
245     if (index < 0 || index >= (int)g_ime_info_list.size()) {
246         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
247         return;
248     }
249
250     if (g_gen_item_data[index].chk_status) {
251         im_setting_list_check_popup_cancel_cb(data, NULL, NULL);
252     } else {
253         evas_object_del(cb_data->popup);
254     }
255 }
256
257 static void _popup_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
258 {
259     popup_cb_data *cb_data = (popup_cb_data *)data;
260     if (!cb_data)
261         return;
262
263     delete cb_data;
264 }
265
266 static void set_popup_message(Evas_Object *obj, int index)
267 {
268     char chFormatMsg[255] = {'\0'};
269     char chPopupMsg[255] = {'\0'};
270     snprintf(chFormatMsg, sizeof(chFormatMsg), "%s", IM_SETTING_LIST_POPUP_TEXT);
271     snprintf(chPopupMsg, sizeof(chPopupMsg), chFormatMsg, g_ime_info_list[index].label);
272     elm_object_text_set(obj, chPopupMsg);
273 }
274
275 static void popup_lang_changed(void *data, Evas_Object *obj, void *event_info)
276 {
277     int index = (int)data;
278     set_popup_message(obj, index);
279 }
280
281 static void im_setting_list_show_popup(void *data, Evas_Object *obj, popup_ok_cb ime_setting_list_ok_callback, popup_cancel_cb ime_setting_list_cancel_callback)
282 {
283     int index = (int)reinterpret_cast<long>(data);
284     if (index < 0 || index >= (int)g_ime_info_list.size()) {
285         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
286         return;
287     }
288
289     Evas_Object *top_widget = elm_object_top_widget_get(obj);
290     Evas_Object *popup = elm_popup_add(top_widget);
291     elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
292     elm_object_domain_translatable_part_text_set(popup, "title,text", PACKAGE, IM_SETTING_LIST_TURNON_KEYBOARD);
293     evas_object_smart_callback_add(popup, "language,changed", popup_lang_changed, (void *)index);
294
295     set_popup_message(popup, index);
296
297     popup_cb_data *cb_data = new popup_cb_data;
298     cb_data->popup = popup;
299     cb_data->data = data;
300
301     Evas_Object *btn_cancel = elm_button_add(popup);
302     elm_object_domain_translatable_text_set(btn_cancel, PACKAGE, IM_SETTING_LIST_POPUP_CANCEL);
303     elm_object_part_content_set(popup, "button1", btn_cancel);
304     evas_object_smart_callback_add(btn_cancel, "clicked", ime_setting_list_cancel_callback, cb_data);
305
306     Evas_Object *btn_ok = elm_button_add(popup);
307     elm_object_domain_translatable_text_set(btn_ok, PACKAGE, IM_SETTING_LIST_TURNON);
308     elm_object_part_content_set(popup, "button2", btn_ok);
309     evas_object_smart_callback_add(btn_ok, "clicked", ime_setting_list_ok_callback, cb_data);
310
311     eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, _popup_back_cb, cb_data);
312     evas_object_event_callback_add(popup, EVAS_CALLBACK_DEL, _popup_del_cb, cb_data);
313     evas_object_show(popup);
314 }
315
316 static void im_setting_list_check_button_change_cb(void *data, Evas_Object *obj, void *event_info)
317 {
318     /*save the checked ime*/
319     int index = (int)reinterpret_cast<long>(data);
320     if (index < 0 || index >= (int)g_ime_info_list.size()) {
321         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
322         return;
323     }
324
325     Eina_Bool state = g_gen_item_data[index].chk_status;
326
327     if (!state) {
328         if (isf_control_set_enable_ime(g_ime_info_list[index].appid, state) != 0)
329             LOGW("Failed to set enable ime : %s\n", g_ime_info_list[index].appid);
330     } else {
331         im_setting_list_show_popup(data, obj, im_setting_list_check_popup_ok_cb, im_setting_list_check_popup_cancel_cb);
332     }
333 }
334
335 static void
336 im_setting_list_popup_ok_cb(void *data, Evas_Object *obj, void *event_info)
337 {
338     popup_cb_data *cb_data = (popup_cb_data *)data;
339     if (!cb_data)
340         return;
341     int index = (int)reinterpret_cast<long>(cb_data->data);
342     if (index < 0 || index >= (int)g_ime_info_list.size()) {
343         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
344         return;
345     }
346
347     Eina_Bool state = g_gen_item_data[index].chk_status;
348     if (isf_control_set_enable_ime(g_ime_info_list[index].appid, !state) == 0) {
349         g_gen_item_data[index].chk_status = !state;
350         Evas_Object *ck = elm_object_item_part_content_get(g_gen_item_data[index].gen_item, "elm.swallow.end");
351         if (ck == NULL) {
352             ck = elm_object_item_part_content_get(g_gen_item_data[index].gen_item, "elm.icon");
353         }
354
355         if (ck) {
356             elm_object_signal_emit(ck, "elm,activate,check,on", "elm");
357             elm_check_state_set(ck, !state);
358         }
359     } else {
360         LOGW("Failed to set enable ime : %s\n", g_ime_info_list[index].appid);
361     }
362     evas_object_del(cb_data->popup);
363 }
364
365 static void
366 im_setting_list_popup_cancel_cb(void *data, Evas_Object *obj, void *event_info)
367 {
368     popup_cb_data *cb_data = (popup_cb_data *)data;
369     if (!cb_data)
370         return;
371     evas_object_del(cb_data->popup);
372 }
373
374 static void im_setting_list_item_sel_cb(void *data, Evas_Object *obj, void *event_info)
375 {
376     Elm_Object_Item *item = (Elm_Object_Item *)event_info;
377     elm_genlist_item_selected_set(item, EINA_FALSE);
378
379     int index = (int)reinterpret_cast<long>(data);
380     if (index < 0 || index >= (int)g_ime_info_list.size()) {
381         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
382         return;
383     }
384
385     if (g_ime_info_list[index].is_preinstalled || (index == g_active_ime_index))
386     {
387         return;
388     }
389
390     Evas_Object *ck = elm_object_item_part_content_get(item, "elm.swallow.end");
391     if (ck == NULL) {
392         ck = elm_object_item_part_content_get(item, "elm.icon");
393     }
394     Eina_Bool state = g_gen_item_data[index].chk_status;
395
396     if (state) {
397         if (isf_control_set_enable_ime(g_ime_info_list[index].appid, !state) == 0) {
398             if (ck) {
399                 elm_object_signal_emit(ck, "elm,activate,check,off", "elm");
400                 elm_check_state_set(ck, !state);
401             }
402             g_gen_item_data[index].chk_status = !state;
403         } else {
404             LOGW("Failed to set enable ime : %s\n", g_ime_info_list[index].appid);
405         }
406     } else {
407         im_setting_list_show_popup(data, obj, im_setting_list_popup_ok_cb, im_setting_list_popup_cancel_cb);
408     }
409 }
410
411 static void im_setting_list_set_default_keyboard_item_sel_cb(void *data, Evas_Object *obj, void *event_info)
412 {
413     Elm_Object_Item *item = (Elm_Object_Item *)event_info;
414
415     elm_genlist_item_selected_set(item, EINA_FALSE);
416     im_setting_list_popup_view_create(data);
417 }
418
419 static void im_setting_list_keyboard_setting_item_sel_cb(void *data, Evas_Object *obj, void *event_info)
420 {
421     appdata *ad = (appdata *)data;
422     if (ad->app_state == APP_STATE_PAUSE)
423         return;
424
425     Elm_Object_Item *item = (Elm_Object_Item *)event_info;
426     elm_genlist_item_selected_set(item, EINA_FALSE);
427     isf_control_open_ime_option_window();
428 }
429
430 static void
431 _elm_win_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
432 {
433     Evas_Coord w = -1, h = -1;
434     Evas_Object *conform = (Evas_Object*)data;
435     if (conform) {
436         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
437         if (w > 0 && h > 0) {
438             evas_object_resize(conform, w, h);
439         }
440     }
441 }
442
443 static Evas_Object *im_setting_list_conform_create(Evas_Object *parentWin)
444 {
445     Evas_Object *conform = elm_conformant_add(parentWin);
446     elm_win_indicator_mode_set(parentWin, ELM_WIN_INDICATOR_SHOW);
447     elm_win_indicator_opacity_set(parentWin, ELM_WIN_INDICATOR_OPAQUE);
448     evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
449     evas_object_size_hint_align_set(conform, EVAS_HINT_FILL, EVAS_HINT_FILL);
450
451     Evas_Object *bg = elm_bg_add(conform);
452     elm_object_style_set(bg, "indicator/headerbg");
453     elm_object_part_content_set(conform, "elm.swallow.indicator_bg", bg);
454     evas_object_show(bg);
455
456     Evas_Coord w = -1, h = -1;
457     elm_win_screen_size_get(parentWin, NULL, NULL, &w, &h);
458     if (w > 0 && h > 0) {
459         evas_object_resize(conform, w, h);
460     }
461     evas_object_event_callback_add(parentWin, EVAS_CALLBACK_RESIZE, _elm_win_resize_cb, conform);
462     evas_object_show(conform);
463     return conform;
464 }
465
466 static Evas_Object *im_setting_list_naviframe_create(Evas_Object* parent)
467 {
468     Evas_Object *naviframe = elm_naviframe_add(parent);
469     elm_naviframe_prev_btn_auto_pushed_set(naviframe, EINA_TRUE);
470     eext_object_event_callback_add(naviframe, EEXT_CALLBACK_BACK, eext_naviframe_back_cb, NULL);
471     evas_object_size_hint_weight_set(naviframe, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
472     evas_object_size_hint_align_set(naviframe, EVAS_HINT_FILL, EVAS_HINT_FILL);
473     elm_object_part_content_set(parent, "elm.swallow.content", naviframe);
474     evas_object_show(naviframe);
475     return naviframe;
476 }
477
478 static void gl_lang_changed(void *data, Evas_Object *obj, void *event_info)
479 {
480     /* Reload ime list for getting translated IME name */
481     im_setting_list_load_ime_info();
482
483     /* Set translated active IME name */
484     snprintf(item_text[0].sub_text, sizeof(item_text[0].sub_text), "%s", g_ime_info_list[g_active_ime_index].label);
485
486     elm_genlist_realized_items_update(obj);
487 }
488
489 static Evas_Object *im_setting_list_genlist_create(appdata *ad)
490 {
491     Evas_Object *genlist = elm_genlist_add(ad->naviframe);
492     elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);
493 #ifdef _CIRCLE
494     /* Circle Surface Creation */
495     if (ad->circle_surface == NULL)
496         ad->circle_surface = eext_circle_surface_conformant_add(ad->conform);
497     ad->main_circle_genlist = eext_circle_object_genlist_add(genlist, ad->circle_surface);
498     eext_rotary_object_event_activated_set(ad->main_circle_genlist, EINA_TRUE);
499 #endif
500     evas_object_smart_callback_add(genlist, "language,changed", gl_lang_changed, NULL);
501     evas_object_show(genlist);
502     return genlist;
503 }
504
505 static char *im_setting_list_genlist_group_label_get(void *data, Evas_Object *obj, const char *part)
506 {
507     char *text = (char *)data;
508     if (!text)
509         return NULL;
510     if (!strcmp(part, "elm.text")) {
511         return strdup(dgettext(PACKAGE, text));
512     }
513     return NULL;
514 }
515
516 static void
517 im_setting_list_genlist_keyboard_list_item_del(void *data, Evas_Object *obj)
518 {
519     Item_Data *id = (Item_Data *)data;
520     if (id) free(id);
521 }
522
523 static char *im_setting_list_genlist_keyboard_list_item_label_get(void *data, Evas_Object *obj, const char *part)
524 {
525     Item_Data *id = (Item_Data *)data;
526     int index = id->index;
527     if (index < 0 || index >= (int)g_ime_info_list.size()) {
528         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
529         return NULL;
530     }
531
532     if (!strcmp(part, "elm.text.main.left.top") ||
533         !strcmp(part, "elm.text.main.left") ||
534         !strcmp(part, "elm.text.main") ||
535         !strcmp(part, "elm.text") ||
536         !strcmp(part, "elm.text.1")) {
537         return strdup(g_ime_info_list[index].label);
538     }
539     return NULL;
540 }
541
542 #ifdef _WEARABLE
543 static char *im_setting_list_genlist_title_label_get(void *data, Evas_Object *obj, const char *part)
544 {
545     if (!strcmp(part, "elm.text")) {
546         return strdup(dgettext(PACKAGE, IM_SETTING_LIST_TITLE));
547     }
548     return NULL;
549 }
550 #endif
551
552 static Evas_Object *im_setting_list_genlist_keyboard_list_item_icon_get(void *data, Evas_Object *obj, const char *part)
553 {
554     Item_Data *id = (Item_Data *)data;
555     int index = id->index;
556
557     if (index < 0 || index >= (int)g_ime_info_list.size()) {
558         LOGW("Wrong value. index : %d, g_ime_info_list.size() : %zu\n", index, g_ime_info_list.size());
559         return NULL;
560     }
561
562     if (!strcmp(part, "elm.swallow.end") ||
563         !strcmp(part, "elm.icon")) {
564         Evas_Object *ck = elm_check_add(obj);
565         elm_object_style_set(ck, "on&off");
566         elm_check_state_set(ck, g_gen_item_data[index].chk_status);
567         elm_object_disabled_set(ck, g_ime_info_list[index].is_preinstalled || (index == g_active_ime_index));
568 #ifndef _MOBILE
569         elm_object_disabled_set(ck, EINA_TRUE);
570 #endif
571         evas_object_propagate_events_set(ck, EINA_FALSE);
572         evas_object_size_hint_align_set(ck, EVAS_HINT_FILL, EVAS_HINT_FILL);
573         evas_object_size_hint_weight_set(ck, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
574         elm_check_state_pointer_set(ck, (Eina_Bool *)(&(g_gen_item_data[index].chk_status)));
575         evas_object_pass_events_set(ck, EINA_TRUE);
576         evas_object_smart_callback_add(ck, "changed", im_setting_list_check_button_change_cb, (void *)(unsigned long int)(index));
577         evas_object_show(ck);
578
579         elm_atspi_accessible_relationship_append(ck, ELM_ATSPI_RELATION_CONTROLLED_BY, id->item);
580         elm_atspi_accessible_relationship_append(id->item, ELM_ATSPI_RELATION_CONTROLLER_FOR, ck);
581         elm_atspi_accessible_relationship_append(id->item, ELM_ATSPI_RELATION_DESCRIBED_BY, ck);
582
583         return ck;
584     }
585     return NULL;
586 }
587
588 static char *im_setting_list_genlist_item_label_get(void *data, Evas_Object *obj, const char *part)
589 {
590     list_item_text *item_text = (list_item_text *)data;
591     if (!item_text)
592         return NULL;
593
594     if (!strcmp(part, "elm.text.main.left.top") ||
595         !strcmp(part, "elm.text.main.left") ||
596         !strcmp(part, "elm.text.main") ||
597         !strcmp(part, "elm.text")) {
598         return strdup(dgettext(PACKAGE, item_text->main_text));
599     }
600     if (!strcmp(part, "elm.text.sub") ||
601         !strcmp(part, "elm.text.sub.left.bottom") ||
602         !strcmp(part, "elm.text.multiline") ||
603         !strcmp(part, "elm.text.1") ||
604         !strcmp(part, "elm.text.2")) {
605         return strdup(dgettext(PACKAGE, item_text->sub_text));
606     }
607     return NULL;
608 }
609
610 static char *im_setting_list_genlist_item_one_line_label_get(void *data, Evas_Object *obj, const char *part)
611 {
612     list_item_text *item_text = (list_item_text *)data;
613     if (!item_text)
614         return NULL;
615     if (!strcmp(part, "elm.text.main.left.top") ||
616         !strcmp(part, "elm.text.main.left") ||
617         !strcmp(part, "elm.text.main") ||
618         !strcmp(part, "elm.text") ||
619         !strcmp(part, "elm.text.1")) {
620         return strdup(dgettext(PACKAGE, item_text->main_text));
621     }
622     return NULL;
623 }
624
625 static void im_setting_list_genlist_item_class_create(int app_type)
626 {
627     if (NULL == itc_im_list_group)
628     {
629         itc_im_list_group = elm_genlist_item_class_new();
630         if (itc_im_list_group)
631         {
632 #ifdef _WEARABLE
633             itc_im_list_group->item_style = "groupindex";
634 #else
635             itc_im_list_group->item_style = "group_index";
636 #endif
637             itc_im_list_group->func.text_get = im_setting_list_genlist_group_label_get;
638             itc_im_list_group->func.content_get = NULL;
639             itc_im_list_group->func.state_get = NULL;
640             itc_im_list_group->func.del = NULL;
641         }
642     }
643
644     if (NULL == itc_im_list_keyboard_list)
645     {
646         itc_im_list_keyboard_list = elm_genlist_item_class_new();
647         if (itc_im_list_keyboard_list)
648         {
649 #ifdef _WEARABLE
650             itc_im_list_keyboard_list->item_style = "1text.1icon.1";
651 #else
652             itc_im_list_keyboard_list->item_style = "type1";
653 #endif
654             itc_im_list_keyboard_list->func.text_get = im_setting_list_genlist_keyboard_list_item_label_get;
655             itc_im_list_keyboard_list->func.content_get = im_setting_list_genlist_keyboard_list_item_icon_get;
656             itc_im_list_keyboard_list->func.state_get = NULL;
657             itc_im_list_keyboard_list->func.del = im_setting_list_genlist_keyboard_list_item_del;
658         }
659     }
660
661 #ifdef _WEARABLE
662     if (NULL == itc_im_list_title)
663     {
664         itc_im_list_title = elm_genlist_item_class_new();
665         if (itc_im_list_title)
666         {
667             itc_im_list_title->item_style = "title";
668             itc_im_list_title->func.text_get = im_setting_list_genlist_title_label_get;
669         }
670     }
671 #endif
672
673     if (app_type == APP_TYPE_SETTING || app_type == APP_TYPE_SETTING_NO_ROTATION)
674     {
675         if (NULL == itc_im_list_item)
676         {
677             itc_im_list_item = elm_genlist_item_class_new();
678             if (itc_im_list_item)
679             {
680 #ifdef _WEARABLE
681                 itc_im_list_item->item_style = "2text";
682 #else
683                 itc_im_list_item->item_style = "type1";
684 #endif
685                 itc_im_list_item->func.text_get = im_setting_list_genlist_item_label_get;
686                 itc_im_list_item->func.content_get = NULL;
687                 itc_im_list_item->func.state_get = NULL;
688                 itc_im_list_item->func.del = NULL;
689             }
690         }
691
692         if (NULL == itc_im_list_item_one_line)
693         {
694             itc_im_list_item_one_line = elm_genlist_item_class_new();
695             if (itc_im_list_item_one_line)
696             {
697 #ifdef _WEARABLE
698                 itc_im_list_item_one_line->item_style = "1text";
699 #else
700                 itc_im_list_item_one_line->item_style = "type1";
701 #endif
702                 itc_im_list_item_one_line->func.text_get = im_setting_list_genlist_item_one_line_label_get;
703                 itc_im_list_item_one_line->func.content_get = NULL;
704                 itc_im_list_item_one_line->func.state_get = NULL;
705                 itc_im_list_item_one_line->func.del = NULL;
706             }
707         }
708     }
709 }
710
711 static void im_setting_list_add_ime(void *data) {
712     appdata *ad = (appdata *)data;
713     if (!ad)
714         return;
715     im_setting_list_genlist_item_class_create(ad->app_type);
716
717     if (NULL != ad->genlist)
718     {
719         elm_genlist_clear(ad->genlist);
720     }
721
722     g_active_ime_index = im_setting_list_get_active_ime_index();
723     if (g_active_ime_index < 0 || g_active_ime_index >= (int)g_ime_info_list.size()) {
724         LOGW("Wrong value. g_active_ime_index : %d, g_ime_info_list.size() : %zu\n", g_active_ime_index, g_ime_info_list.size());
725         return;
726     }
727
728 #ifdef _WEARABLE
729     /* Add scrollable title area in wearable profile */
730     elm_genlist_item_append(ad->genlist, itc_im_list_title, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
731 #endif
732
733     memset(&item_text, 0, sizeof(item_text));
734     if (ad->app_type == APP_TYPE_SETTING || ad->app_type == APP_TYPE_SETTING_NO_ROTATION)
735     {
736         /* Default keyboard selector */
737         snprintf(item_text[0].main_text, sizeof(item_text[0].main_text), "%s", IM_SETTING_LIST_DEFAULT_KEYBOARD);
738         snprintf(item_text[0].sub_text, sizeof(item_text[0].sub_text), "%s", g_ime_info_list[g_active_ime_index].label);
739         Elm_Object_Item *item = elm_genlist_item_append(ad->genlist,
740             itc_im_list_item,
741             (void *)&item_text[0],
742             NULL,
743             ELM_GENLIST_ITEM_NONE,
744             im_setting_list_set_default_keyboard_item_sel_cb,
745             data);
746
747         elm_object_item_domain_text_translatable_set(item, PACKAGE, EINA_TRUE);
748
749 #ifdef _WEARABLE
750         if (g_ime_info_list.size() <= 1) {
751             LOGD("The number of IME : %zu\n", g_ime_info_list.size());
752             elm_object_item_disabled_set(item, EINA_TRUE);
753         }
754 #endif
755
756         /* Keyboard settings */
757         snprintf(item_text[1].main_text, sizeof(item_text[1].main_text), "%s", IM_SETTING_LIST_KEYBOARD_SETTING);
758         item = elm_genlist_item_append(ad->genlist,
759             itc_im_list_item_one_line,
760             (void *)&item_text[1],
761             NULL,
762             ELM_GENLIST_ITEM_NONE,
763             im_setting_list_keyboard_setting_item_sel_cb,
764             ad);
765         elm_object_item_domain_text_translatable_set(item, PACKAGE, EINA_TRUE);
766
767         elm_object_item_disabled_set(item, !(g_ime_info_list[g_active_ime_index].has_option));
768
769 #ifdef _MOBILE
770         /* Keyboards group */
771         Elm_Object_Item *group_header_item = NULL;
772         group_header_item = elm_genlist_item_append(ad->genlist,
773                 itc_im_list_group,
774                 IM_SETTING_LIST_KEYBOARD_HEADER,
775                 NULL,
776                 ELM_GENLIST_ITEM_GROUP,
777                 NULL,
778                 NULL);
779         elm_genlist_item_select_mode_set(group_header_item, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
780         elm_object_item_domain_text_translatable_set(group_header_item, PACKAGE, EINA_TRUE);
781 #endif
782     }
783
784 #ifndef _MOBILE
785     if (ad->app_type == APP_TYPE_NORMAL)
786 #endif
787     {
788         Item_Data *id = NULL;
789
790         /* keyboard list */
791         int info_list_size = g_ime_info_list.size();
792         for (int i = 0; i < info_list_size; i++) {
793             gen_item_data item_data;
794
795             if (g_ime_info_list[i].is_preinstalled || (i == g_active_ime_index)) {
796                 item_data.chk_status = EINA_TRUE;
797             } else {
798                 item_data.chk_status = g_ime_info_list[i].is_enabled;
799             }
800             g_gen_item_data.push_back(item_data);
801
802             id = (Item_Data *)calloc(sizeof(Item_Data), 1);
803             if (id) {
804                 id->index = i;
805
806                 id->item = elm_genlist_item_append(ad->genlist,
807                         itc_im_list_keyboard_list,
808                         id,
809                         NULL,
810                         ELM_GENLIST_ITEM_NONE,
811                         im_setting_list_item_sel_cb,
812                         (void *)(unsigned long int)(i));
813
814                 if (g_ime_info_list[i].is_preinstalled || (i == g_active_ime_index)) {
815                     elm_object_item_disabled_set(id->item, EINA_TRUE);
816                 }
817
818                 g_gen_item_data[i].gen_item = id->item;
819             }
820         }
821     }
822
823 #ifdef _CIRCLE
824     im_setting_list_add_padding(ad->genlist);
825 #endif
826 }
827
828 static Eina_Bool im_setting_list_navi_item_pop_cb(void *data, Elm_Object_Item *it)
829 {
830     static bool in_exit = false;
831     if (in_exit)
832         return EINA_TRUE;
833     in_exit = true;
834     if (data == NULL)
835         return EINA_TRUE;
836     ui_app_exit();
837     return EINA_TRUE;
838 }
839
840 static void im_setting_list_navi_back_btn_call_cb(void *data, Evas_Object *obj, void *event_info)
841 {
842     evas_object_smart_callback_del(obj, "clicked", im_setting_list_navi_back_btn_call_cb);
843     ui_app_exit();
844 }
845
846 void im_setting_list_add_padding(Evas_Object *genlist)
847 {
848     /* Add padding area in wearable circle profile */
849     Elm_Genlist_Item_Class *ptc = elm_genlist_item_class_new();
850     Elm_Object_Item *item;
851     if (!ptc) return;
852
853     ptc->item_style = "padding";
854     item = elm_genlist_item_append(genlist, ptc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
855     elm_atspi_accessible_role_set(item, ELM_ATSPI_ROLE_REDUNDANT_OBJECT);
856     elm_genlist_item_class_free(ptc);
857 }
858
859 Evas_Object *im_setting_list_list_create(void *data)
860 {
861     appdata *ad = (appdata *)data;
862     if (!ad)
863         return NULL;
864     ad->conform = im_setting_list_conform_create(ad->win);
865     ad->naviframe = im_setting_list_naviframe_create(ad->conform);
866     ad->genlist = im_setting_list_genlist_create(ad);
867     im_setting_list_add_ime(ad);
868
869     /* Add genlist to naviframe */
870     Evas_Object *back_btn = NULL;
871     const char *title = NULL;
872     const char *item_style = NULL;
873 #ifdef _WEARABLE
874     item_style = "empty";
875 #else
876     title = IM_SETTING_LIST_TITLE;
877
878     back_btn = elm_button_add(ad->naviframe);
879     elm_object_style_set(back_btn, "naviframe/back_btn/default");
880     evas_object_smart_callback_add(back_btn, "clicked", im_setting_list_navi_back_btn_call_cb, NULL);
881 #endif
882
883     Elm_Object_Item *nf_main_item = elm_naviframe_item_push(ad->naviframe,
884                 title,
885                 back_btn,
886                 NULL,
887                 ad->genlist,
888                 item_style);
889
890     elm_object_item_domain_text_translatable_set(nf_main_item, PACKAGE, EINA_TRUE);
891
892     elm_naviframe_item_title_enabled_set(nf_main_item, EINA_TRUE, EINA_TRUE);
893     elm_naviframe_item_pop_cb_set(nf_main_item, im_setting_list_navi_item_pop_cb, ad);
894     elm_object_content_set(ad->conform, ad->naviframe);
895
896     return ad->genlist;
897 }
898
899 void im_setting_list_app_terminate(void *data)
900 {
901     g_ime_info_list.clear();
902     g_gen_item_data.clear();
903     if (NULL != itc_im_list_keyboard_list)
904     {
905         elm_genlist_item_class_free(itc_im_list_keyboard_list);
906         itc_im_list_keyboard_list = NULL;
907     }
908
909     if (NULL != itc_im_list_group)
910     {
911         elm_genlist_item_class_free(itc_im_list_group);
912         itc_im_list_group = NULL;
913     }
914
915     if (NULL != itc_im_list_item)
916     {
917         elm_genlist_item_class_free(itc_im_list_item);
918         itc_im_list_item = NULL;
919     }
920
921     if (NULL != itc_im_list_title)
922     {
923         elm_genlist_item_class_free(itc_im_list_title);
924         itc_im_list_title = NULL;
925     }
926
927     if (pkgmgr) {
928         package_manager_destroy(pkgmgr);
929         pkgmgr = NULL;
930     }
931 }
932
933 void im_setting_list_update_window(void *data)
934 {
935     appdata *ad = (appdata *)data;
936     if (!ad)
937         return;
938     im_setting_list_load_ime_info();
939     im_setting_list_add_ime(ad);
940 }
941
942 static void _package_manager_event_cb(const char *type, const char *package, package_manager_event_type_e event_type, package_manager_event_state_e event_state, int progress, package_manager_error_e error, void *user_data)
943 {
944     appdata *ad = (appdata *)user_data;
945
946     if (!package || !type)
947         return;
948
949     if (event_state != PACKAGE_MANAGER_EVENT_STATE_COMPLETED)
950         return;
951
952     if (event_type == PACKAGE_MANAGER_EVENT_TYPE_INSTALL ||
953         event_type == PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL ||
954         event_type == PACKAGE_MANAGER_EVENT_TYPE_UPDATE) {
955         LOGD("PACKAGE_MANAGER_EVENT type : %d", event_type);
956         /* Wait for updating IME package list in ISF */
957         usleep(20000);
958         im_setting_list_popup_view_del(ad);
959         im_setting_list_popup_view_create(ad);
960     }
961 }
962
963 void
964 im_setting_list_app_create(void *data)
965 {
966     appdata *ad = (appdata *)data;
967     if (!ad)
968         return;
969     im_setting_list_text_domain_set();
970     ad->win = im_setting_list_main_window_create(PACKAGE, ad->app_type);
971     im_setting_list_bg_create(ad->win);
972     im_setting_list_load_ime_info();
973
974     if (!pkgmgr) {
975         int ret = package_manager_create(&pkgmgr);
976         if (ret == PACKAGE_MANAGER_ERROR_NONE) {
977             ret = package_manager_set_event_cb(pkgmgr, _package_manager_event_cb, ad);
978             if (ret == PACKAGE_MANAGER_ERROR_NONE) {
979                 LOGD("package_manager_set_event_cb succeeded.\n");
980             } else {
981                 LOGD("package_manager_set_event_cb failed(%d)\n", ret);
982             }
983         } else {
984             LOGD("package_manager_create failed(%d)\n", ret);
985         }
986     }
987
988     im_setting_list_list_create(ad);
989     evas_object_show(ad->win);
990 }
991
992 void
993 im_setting_list_app_resume(void *data)
994 {
995     appdata *ad = (appdata *)data;
996     if (!ad)
997         return;
998
999     isf_control_resume_ime_option_window();
1000 }