Fix indentation
[platform/core/uifw/inputmethod-setting.git] / im_setting_list / input_method_setting_list_popup_view.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 <efl_extension.h>
22 #include <vector>
23 #include <isf_control.h>
24 #include <algorithm>
25 #include <inputmethod_manager.h>
26 #include <vconf.h>
27
28 #define IM_SETTING_LIST_POPUP_VIEW_TITLE          "IDS_ST_HEADER_DEFAULT_KEYBOARD_ABB"
29
30 static std::vector<ime_info_s>      g_active_ime_info_list;
31 static Elm_Genlist_Item_Class       *itc_im_list = NULL;
32 static Evas_Object                  *group_radio = NULL;
33 static int                          g_active_ime_id = -1;
34
35 typedef struct {
36     void        *data;
37     int         index;
38 } sel_cb_data;
39
40 class ime_info_compare
41 {
42     public:
43     bool operator()(const ime_info_s &first, const ime_info_s &sec)
44     {
45         return (strcasecmp(first.label, sec.label) < 0);
46     }
47 };
48
49 static int selected_index = 0;
50
51 static void im_setting_list_sort_ime_info(std::vector<ime_info_s> &preinstall, std::vector<ime_info_s> &user)
52 {
53     std::sort(preinstall.begin(), preinstall.end(), ime_info_compare());
54     std::sort(user.begin(), user.end(), ime_info_compare());
55     for (unsigned int i = 0; i < preinstall.size(); ++i)
56     {
57         g_active_ime_info_list.push_back(preinstall[i]);
58     }
59     for (unsigned int i = 0; i < user.size(); ++i)
60     {
61         g_active_ime_info_list.push_back(user[i]);
62     }
63 }
64
65 static void im_setting_list_load_active_ime_info(void)
66 {
67     std::vector<ime_info_s>      active_ime_info_list_preinstall;
68     std::vector<ime_info_s>      active_ime_info_list_user;
69     g_active_ime_info_list.clear();
70     char *active_ime_appid = NULL;
71
72     int ret = ime_manager_get_active_ime(&active_ime_appid);
73     if (ret == IME_MANAGER_ERROR_NONE)
74         LOGD("get active ime : %s\n", active_ime_appid);
75     else
76         LOGW("Failed to get active ime. error : %d\n", ret);
77
78     ime_info_s *info = NULL;
79     int cnt = isf_control_get_all_ime_info(&info);
80     if (info)
81     {
82         for (int i = 0; i < cnt; ++i)
83         {
84             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);
85             if (info[i].is_enabled && info[i].is_preinstalled) {
86                 active_ime_info_list_preinstall.push_back(info[i]);
87             } else if (info[i].is_enabled) {
88                 active_ime_info_list_user.push_back(info[i]);
89             }
90         }
91         free(info);
92     }
93
94     im_setting_list_sort_ime_info(active_ime_info_list_preinstall, active_ime_info_list_user);
95     for (unsigned int i = 0; i < g_active_ime_info_list.size(); ++i)
96     {
97         if (active_ime_appid && (!strcmp(active_ime_appid, g_active_ime_info_list[i].appid)))
98         {
99             g_active_ime_id = i;
100         }
101     }
102
103     if (active_ime_appid)
104     {
105         free(active_ime_appid);
106     }
107 }
108
109 static void im_setting_list_update_radio_state(Elm_Object_Item *item, Evas_Object *obj, int index)
110 {
111     if (index < 0 || index >= (int)g_active_ime_info_list.size()) {
112         LOGW("Wrong value. index : %d, g_active_ime_info_list.size() : %zu\n", index, g_active_ime_info_list.size());
113         return;
114     }
115
116     if (item && obj) {
117         elm_genlist_item_selected_set(item, EINA_FALSE);
118         /* Update radio button */
119         Evas_Object *radio = elm_object_item_part_content_get(item, "elm.swallow.end");
120         if (radio == NULL) {
121             radio = elm_object_item_part_content_get(item, "elm.icon");
122         }
123         evas_object_data_set(radio, "parent_genlist", obj);
124         elm_radio_value_set(group_radio, index);
125     }
126 }
127
128 void im_setting_list_update_window_selector(void *data)
129 {
130     appdata *ad = (appdata *)data;
131     if (!ad)
132         return;
133     im_setting_list_load_active_ime_info();
134     im_setting_list_update_window(ad);
135 }
136
137 static Eina_Bool _ime_select_idler_cb(void *data)
138 {
139     appdata *ad = (appdata *)data;
140     if (!ad) return ECORE_CALLBACK_CANCEL;
141
142     LOGD("set active IME\n");
143     if (isf_control_set_active_ime(g_active_ime_info_list[selected_index].appid) != 0)
144         LOGW("Failed to set active IME : %s\n", g_active_ime_info_list[selected_index].appid);
145
146     LOGD("update window selector\n");
147     im_setting_list_update_window_selector(ad);
148
149     LOGD("delete popup\n");
150     if (ad->popup) {
151         evas_object_del(ad->popup);
152     }
153     ad->popup = NULL;
154
155     if (ad->app_type == APP_TYPE_NORMAL) {
156         if (ad->naviframe)
157             elm_naviframe_item_pop(ad->naviframe);
158     } else {
159 #ifdef _WEARABLE
160         if (ad->naviframe)
161             elm_naviframe_item_pop(ad->naviframe);
162 #endif
163     }
164
165     return ECORE_CALLBACK_CANCEL;
166 }
167
168 static void im_setting_list_ime_sel_cb(void *data, Evas_Object *obj, void *event_info)
169 {
170     sel_cb_data *cb_data = (sel_cb_data *)data;
171     if (!cb_data)
172         return;
173
174     appdata *ad = (appdata *)cb_data->data;
175     if (!ad)
176         return;
177
178     int index = cb_data->index;
179     selected_index = index;
180
181     Elm_Object_Item *item = (Elm_Object_Item *)event_info;
182     if (!item) {
183         return;
184     }
185
186     im_setting_list_update_radio_state(item, obj, index);
187
188     ecore_idler_add(_ime_select_idler_cb, ad);
189 }
190
191 static void gl_lang_changed(void *data, Evas_Object *obj, void *event_info)
192 {
193     im_setting_list_load_active_ime_info();
194
195     elm_genlist_realized_items_update(obj);
196 }
197
198 static Evas_Object *im_setting_list_genlist_create(appdata *ad, Evas_Object* parent, Evas_Object* conform)
199 {
200     if (!parent)
201         return NULL;
202     Evas_Object *genlist = elm_genlist_add(parent);
203     elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);
204 #ifdef _CIRCLE
205     /* Circle Surface Creation */
206     if (ad->circle_surface == NULL)
207         ad->circle_surface = eext_circle_surface_conformant_add(conform);
208     Evas_Object *circle_genlist = eext_circle_object_genlist_add(genlist, ad->circle_surface);
209     eext_rotary_object_event_activated_set(circle_genlist, EINA_TRUE);
210 #endif
211     evas_object_size_hint_weight_set(genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
212     evas_object_size_hint_align_set(genlist, EVAS_HINT_FILL, EVAS_HINT_FILL);
213     elm_scroller_content_min_limit(genlist, EINA_FALSE, EINA_TRUE);
214     evas_object_smart_callback_add(genlist, "language,changed", gl_lang_changed, NULL);
215     evas_object_show(genlist);
216     return genlist;
217 }
218
219 static char *im_setting_list_genlist_item_label_get(void *data, Evas_Object *obj, const char *part)
220 {
221     sel_cb_data *cb_data = (sel_cb_data *)data;
222     if (!cb_data)
223         return NULL;
224
225     int index = cb_data->index;
226     if (index < 0 || index >= (int)g_active_ime_info_list.size()) {
227         LOGW("Wrong value. index : %d, g_active_ime_info_list.size() : %zu\n", index, g_active_ime_info_list.size());
228         return NULL;
229     }
230
231     if (!strcmp(part, "elm.text") ||
232         !strcmp(part, "elm.text.main") ||
233         !strcmp(part, "elm.text.main.left")) {
234         return strdup(g_active_ime_info_list[index].label);
235     }
236
237     return NULL;
238 }
239
240 static Evas_Object *im_setting_list_genlist_item_icon_get(void *data, Evas_Object *obj, const char *part)
241 {
242     sel_cb_data *cb_data = (sel_cb_data *)data;
243     if (!cb_data)
244         return NULL;
245
246     int index = cb_data->index;
247     Elm_Object_Item *it = elm_genlist_nth_item_get(obj, index);
248
249     if (!strcmp(part, "elm.swallow.end") ||
250         !strcmp(part, "elm.icon")) {
251         Evas_Object *radio = elm_radio_add(obj);
252         elm_object_style_set(radio, "list");
253         elm_radio_state_value_set(radio, index);
254         evas_object_propagate_events_set(radio, EINA_TRUE);
255         elm_radio_group_add(radio, group_radio);
256         evas_object_show(radio);
257
258         elm_atspi_accessible_relationship_append(it, ELM_ATSPI_RELATION_DESCRIBED_BY, radio);
259         elm_atspi_accessible_relationship_append(radio, ELM_ATSPI_RELATION_CONTROLLED_BY, it);
260
261         return radio;
262     }
263     return NULL;
264 }
265
266 static void im_setting_list_genlist_item_del_cb(void *data, Evas_Object *obj)
267 {
268     sel_cb_data *cb_data = (sel_cb_data *)data;
269     if (!cb_data)
270         return;
271
272     delete cb_data;
273 }
274
275 static void im_setting_list_genlist_item_class_create(void)
276 {
277     itc_im_list = elm_genlist_item_class_new();
278     if (itc_im_list) {
279 #ifdef _WEARABLE
280         itc_im_list->item_style = "1text.1icon.1";
281 #else
282         itc_im_list->item_style = "type1";
283 #endif
284         itc_im_list->func.text_get = im_setting_list_genlist_item_label_get;
285         itc_im_list->func.content_get = im_setting_list_genlist_item_icon_get;
286         itc_im_list->func.state_get = NULL;
287         itc_im_list->func.del = im_setting_list_genlist_item_del_cb;
288     }
289 }
290
291 #ifndef _WEARABLE
292 static Evas_Object *im_setting_list_list_create(void *data)
293 {
294     appdata *ad = (appdata *)data;
295     if (!ad)
296         return NULL;
297     im_setting_list_genlist_item_class_create();
298     Evas_Object *genlist = NULL;
299     genlist = im_setting_list_genlist_create(ad, ad->popup, ad->conform);
300     unsigned int i = 0;
301
302     /* keyboard list */
303     for (i = 0; i < g_active_ime_info_list.size(); i++) {
304         sel_cb_data *cb_data = new sel_cb_data;
305         cb_data->data = data;
306         cb_data->index = i;
307         elm_genlist_item_append(genlist,
308             itc_im_list,
309             (void *)(cb_data),
310             NULL,
311             ELM_GENLIST_ITEM_NONE,
312             im_setting_list_ime_sel_cb,
313             (void *)(cb_data));
314     }
315     elm_radio_value_set(group_radio, g_active_ime_id);
316
317     return genlist;
318 }
319
320 static void
321 im_setting_list_popup_block_clicked_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
322 {
323     appdata *ad = (appdata *)data;
324     if (!ad)
325         return;
326     if (ad->popup) {
327         evas_object_del(ad->popup);
328     }
329     ad->popup = NULL;
330 }
331
332 static void im_setting_list_popup_view_back_cb(void *data, Evas_Object *obj, void *event_info)
333 {
334     appdata *ad = (appdata *)data;
335     if (!ad)
336         return;
337     eext_object_event_callback_del(obj, EEXT_CALLBACK_BACK, im_setting_list_popup_view_back_cb);
338     if (ad->popup) {
339         evas_object_del(ad->popup);
340     }
341     ad->popup = NULL;
342 }
343
344 static Evas_Object *im_setting_list_popup_create(void *data)
345 {
346     appdata *ad = (appdata *)data;
347     if (!ad || !ad->win)
348         return NULL;
349     Evas_Object *parentWin = ad->win;
350     if (NULL == group_radio)
351     {
352         group_radio = elm_radio_add(parentWin);
353         elm_radio_state_value_set(group_radio, -1);
354     }
355
356     Evas_Object *popup = elm_popup_add(parentWin);
357     elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
358     evas_object_smart_callback_add(popup, "block,clicked", im_setting_list_popup_block_clicked_cb, data);
359     elm_object_domain_translatable_part_text_set(popup, "title,text", PACKAGE, IM_SETTING_LIST_POPUP_VIEW_TITLE);
360     elm_object_style_set(popup, "theme_bg");
361     eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, im_setting_list_popup_view_back_cb, data);
362     ad->popup = popup;
363
364     Evas_Object *genlist = im_setting_list_list_create(data);
365     elm_object_content_set(popup, genlist);
366     evas_object_show(popup);
367     return popup;
368 }
369 #endif
370
371 #ifdef _WEARABLE
372 static void _active_keyboard_changed_cb(keynode_t* node, void* data)
373 {
374     im_setting_list_load_active_ime_info();
375     if (group_radio != NULL) {
376         elm_radio_value_set(group_radio, g_active_ime_id);
377     }
378 }
379
380 static char *
381 im_setting_list_default_keyboard_title_text_get(void *data, Evas_Object *obj, const char *part)
382 {
383     return strdup(dgettext(PACKAGE, IM_SETTING_LIST_POPUP_VIEW_TITLE));
384 }
385
386 static Eina_Bool _pop_cb(void *data, Elm_Object_Item *it)
387 {
388 #ifdef _CIRCLE
389     appdata *ad = (appdata *)data;
390     if (ad && ad->main_circle_genlist)
391         eext_rotary_object_event_activated_set(ad->main_circle_genlist, EINA_TRUE);
392 #endif
393
394     vconf_ignore_key_changed(VCONFKEY_ISF_ACTIVE_KEYBOARD_UUID, _active_keyboard_changed_cb);
395
396     return EINA_TRUE;
397 }
398
399 static void im_setting_list_screen_create(void *data)
400 {
401     appdata *ad = NULL;
402     Evas_Object *genlist = NULL;
403
404     ad = (appdata *) data;
405     if (ad == NULL) return;
406
407     Elm_Genlist_Item_Class *ttc = elm_genlist_item_class_new();
408     if (!ttc) return;
409
410     ttc->item_style = "title";
411     ttc->func.text_get = im_setting_list_default_keyboard_title_text_get;
412
413     im_setting_list_genlist_item_class_create();
414     genlist = im_setting_list_genlist_create(ad, ad->win, ad->conform);
415
416     elm_genlist_mode_set(genlist, ELM_LIST_SCROLL);
417     elm_genlist_item_append(genlist, ttc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
418
419     if (NULL == group_radio) {
420         group_radio = elm_radio_add(ad->win);
421         elm_radio_state_value_set(group_radio, g_active_ime_id);
422     }
423
424     /* keyboard list */
425     for (unsigned int i = 0; i < g_active_ime_info_list.size(); i++) {
426         sel_cb_data *cb_data = new sel_cb_data;
427         cb_data->data = data;
428         cb_data->index = i;
429         elm_genlist_item_append(genlist,
430             itc_im_list,
431             (void *)(cb_data),
432             NULL,
433             ELM_GENLIST_ITEM_NONE,
434             im_setting_list_ime_sel_cb,
435             (void *)(cb_data));
436     }
437
438     elm_radio_state_value_set(group_radio, g_active_ime_id);
439     elm_radio_value_set(group_radio, g_active_ime_id);
440     elm_genlist_item_class_free(ttc);
441
442 #ifdef _CIRCLE
443     im_setting_list_add_padding(genlist);
444 #endif
445
446     Elm_Object_Item *navi_it = elm_naviframe_item_push(ad->naviframe, NULL, NULL, NULL, genlist, "empty");
447 #ifdef _WEARABLE
448     elm_atspi_accessible_name_set(navi_it, dgettext(PACKAGE, IM_SETTING_LIST_POPUP_VIEW_TITLE));
449 #endif
450     elm_naviframe_item_pop_cb_set(navi_it, _pop_cb, ad);
451
452     vconf_notify_key_changed(VCONFKEY_ISF_ACTIVE_KEYBOARD_UUID, _active_keyboard_changed_cb, data);
453 }
454 #endif
455
456 void im_setting_list_popup_view_del(void *data)
457 {
458     appdata *ad = (appdata *)data;
459     if (!ad || !ad->win)
460         return;
461
462     if (ad->popup) {
463         evas_object_del(ad->popup);
464     }
465     ad->popup = NULL;
466
467     if (ad->naviframe) {
468         elm_naviframe_item_pop(ad->naviframe);
469     }
470 }
471
472 void
473 im_setting_list_popup_view_create(void *data)
474 {
475     appdata *ad = (appdata *)data;
476     if (!ad || !ad->win)
477         return;
478
479     im_setting_list_load_active_ime_info();
480 #ifdef _WEARABLE
481     im_setting_list_screen_create(data);
482 #else
483     im_setting_list_popup_create(data);
484 #endif
485 }