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