3 * Copyright 2012 Samsung Electronics Co., Ltd
5 * Licensed under the Flora License, Version 1.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://floralicense.org/license/
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 #include "detail-view.h"
22 #include "noti-handler.h"
23 #include "external-ug.h"
25 #include "cld-images.h"
26 #include "list-base.h"
27 #include "searchbar.h"
29 static Elm_Entry_Filter_Limit_Size _limit_20char = {
44 Evas_Object *layout; // self
47 Evas_Object *searchbar;
48 Evas_Object *no_contents;
52 Eina_List *append_list;
53 int appended_event_count;
55 const char *searchtext;
58 Ecore_Idler* idler; // To append list
60 struct tm last_itc_h; // To prevent duplicated cal_list_itc_h, in add events & add events idler
62 Eina_Bool is_today_added; //To check real today item is added.
66 Ecore_Event_Handler *event_handler;
69 Elm_Object_Item *sweep_it;
71 Elm_Object_Item* navi_item;
75 Evas_Object *ctx_popup;
76 Evas_Object *scope_button;
77 Eina_Bool has_repeated_events;
78 Elm_Object_Item *repeated_group_it;
80 search_scope_mode search_type;
81 Eina_Bool is_today_has_instance;
82 }cal_search_list_data;
85 Elm_Object_Item *it; // Genlist Item pointer
86 Eina_Bool checked; // Check status
87 calendar_record_h record;
90 }cal_search_list_genlist_item_data;
92 static void __cal_search_list_create_ctx_popup(cal_search_list_data* p);
93 static void __cal_search_list_update_list(cal_search_list_data *p);
95 extern Elm_Genlist_Item_Class cal_list_today_group_itc_h;
97 static void __cal_search_list_append_list_with_iter(Eina_List **event_list, calendar_list_h list)
99 c_ret_if(!event_list);
102 calendar_record_h record = NULL;
108 calendar_error_e error = CALENDAR_ERROR_NONE;
110 error = calendar_list_get_count(list, &count);
111 c_warn_if(error != CALENDAR_ERROR_NONE, "calendar_list_get_count() is failed(%x)", error);
113 for (i = 0; i < count; i++) {
114 error = calendar_list_get_current_record_p(list, &record);
115 c_warn_if(error != CALENDAR_ERROR_NONE, "calendar_list_get_current_record_p() is failed(%x)", error);
117 *event_list = eina_list_append(*event_list, record);
119 calendar_list_next(list);
123 static void __cal_search_list_get_data_with_search(cal_search_list_data *p, calendar_list_h (*_cal_svc_search)(const char *))
129 calendar_list_h list = _cal_svc_search(p->searchtext);
132 __cal_search_list_append_list_with_iter(&p->append_list, list);
134 calendar_error_e error = CALENDAR_ERROR_NONE;
136 error = calendar_list_destroy(list, false);
137 c_warn_if(error != CALENDAR_ERROR_NONE, "calendar_list_destroy() is failed(%x)", error);
142 static void __cal_search_list_get_events_with_search(cal_search_list_data *p)
148 __cal_search_list_get_data_with_search(p, _calendar_search_event);
153 static void __cal_search_list_get_todo_with_search(cal_search_list_data *p)
159 __cal_search_list_get_data_with_search(p, _calendar_search_task);
164 static Eina_Bool __cal_search_list_check_idler_condition(cal_search_list_data *p)
166 c_retv_if(!p, ECORE_CALLBACK_CANCEL);
168 if (p->appended_event_count < eina_list_count(p->append_list)) {
170 return ECORE_CALLBACK_RENEW;
174 ecore_idler_del(p->idler);
178 return ECORE_CALLBACK_CANCEL;
181 static void __cal_search_list_append_event_to_genlist(cal_search_list_data *p)
185 struct appdata* ad = p->ad;
188 Elm_Object_Item *it = NULL;
189 int time_previous = 0;
190 int time_today = (ad->today_tm.tm_year << 9) | (ad->today_tm.tm_mon << 5) | ad->today_tm.tm_mday;
193 calendar_record_h record;
194 int appended_event_count = 0;
195 struct tm tm_current;
197 calendar_time_s time = {0};
199 if (0 < p->appended_event_count) {
200 list = eina_list_nth_list(p->append_list, p->appended_event_count - 1);
203 record = eina_list_data_get(list);
206 if (_calendar_is_task_record(record)) {
207 _calendar_get_end_time(record, &time);
209 cal_util_convert_lli_to_tm(NULL, time.time.utime, &tm_current);
211 _calendar_get_start_time(record, &time);
213 if (_calendar_is_allday_record(record)) {
215 tm_current.tm_year = time.time.date.year - 1900;
216 tm_current.tm_mon = time.time.date.month - 1;
217 tm_current.tm_mday = time.time.date.mday;
219 cal_util_convert_lli_to_tm(NULL, time.time.utime, &tm_current);
223 time_previous = (tm_current.tm_year << 9) | (tm_current.tm_mon << 5) | tm_current.tm_mday;
225 list = eina_list_next(list);
229 list = p->append_list;
231 EINA_LIST_FOREACH(list, l, record) {
235 tm_current = p->ad->base_tm;
237 if (_calendar_is_recurrent_record(record)) {
238 p->has_repeated_events = EINA_TRUE;
241 if (_calendar_is_task_record(record)) {
242 _calendar_get_end_time(record, &time);
244 cal_util_convert_lli_to_tm(NULL, time.time.utime, &tm_current);
245 if (tm_current.tm_mday == 0) {
249 _calendar_get_start_time(record, &time);
251 if (_calendar_is_allday_record(record)) {
253 tm_current.tm_year = time.time.date.year - 1900;
254 tm_current.tm_mon = time.time.date.month - 1;
255 tm_current.tm_mday = time.time.date.mday;
258 cal_util_convert_lli_to_tm(NULL, time.time.utime, &tm_current);
261 int time_current = (tm_current.tm_year << 9) | (tm_current.tm_mon << 5) | tm_current.tm_mday;
263 if (_calendar_is_recurrent_record(record)) {
265 if (!p->repeated_group_it)
266 p->repeated_group_it = cal_list_base_append_genlist_group_item(cal_list_base_get_genlist_p(p->list), &cal_list_itc_h, NULL, CAL_TASK_NONE);
267 cal_list_base_add_item_after(p->list, record, p->repeated_group_it);
271 if (time_previous != time_current) {
272 if ((time_current == time_today) && (!p->is_today_has_instance)) {
273 it = cal_list_base_append_genlist_group_item(cal_list_base_get_genlist_p(p->list), &cal_list_today_group_itc_h, &tm_current, CAL_TASK_NONE);
274 p->is_today_has_instance = EINA_TRUE;
276 it = cal_list_base_append_genlist_group_item(cal_list_base_get_genlist_p(p->list), &cal_list_itc_h, &tm_current, CAL_TASK_NONE);
279 time_previous = time_current;
281 if (time_today == time_current) {
283 p->is_today_added = EINA_TRUE;
286 if (!p->is_today_added) {
287 if (time_today < time_current) {
289 p->is_today_added = EINA_TRUE;
295 p->last_itc_h = tm_current;
299 cal_list_base_add_item(p->list, record, false);
302 appended_event_count++;
304 if (10 < appended_event_count)
309 p->appended_event_count += appended_event_count;
312 Eina_Bool __cal_search_list_idler_callback(void* data)
314 c_retv_if(!data, ECORE_CALLBACK_CANCEL);
316 cal_search_list_data *p = data;
318 c_retv_if(!p->idler, ECORE_CALLBACK_CANCEL);
320 __cal_search_list_append_event_to_genlist(p);
322 return __cal_search_list_check_idler_condition(p);
325 static void __cal_search_list_add_idler(cal_search_list_data *p)
329 if (p->appended_event_count < eina_list_count(p->append_list)) {
332 ecore_idler_del(p->idler);
334 p->idler = ecore_idler_add(__cal_search_list_idler_callback, p);
340 static void __cal_search_list_delete_idler(cal_search_list_data *p)
349 ecore_idler_del(p->idler);
354 static void __cal_search_list_create_no_contents(cal_search_list_data *p)
359 c_ret_if(!p->layout);
366 title = S_("IDS_COM_BODY_NO_ITEMS");
368 Evas_Object *no_contents = cal_util_add_search_nocontents(p->layout, title);
369 c_ret_if(!no_contents);
371 elm_object_part_content_set(p->layout, "sw", no_contents);
373 p->no_contents = no_contents;
376 static inline void __cal_search_list_show_searchbar(cal_search_list_data *p)
378 edje_object_signal_emit(CAL_UTIL_GET_EDJ_DATA(p->layout), "searchbar,show", "prog");
381 static inline void __cal_search_list_hide_searchbar(cal_search_list_data *p)
383 if (!CAL_STRLEN(p->searchtext))
384 edje_object_signal_emit(CAL_UTIL_GET_EDJ_DATA(p->layout), "searchbar,hide", "prog");
387 static void __cal_search_list_delete_no_contents(cal_search_list_data *p)
396 elm_object_part_content_unset(p->layout, "sw");
398 evas_object_del(p->no_contents);
400 p->no_contents = NULL;
403 static void __cal_search_list_delete_genlist(cal_search_list_data *p)
408 c_ret_if(!cal_list_base_get_genlist_p(p->list));
410 cal_list_base_delete(p->list);
415 static void __cal_search_genlist_item_selected_callback(void *data)
417 c_retm_if(!data, "data is null");
419 cal_search_list_data *p = data;
420 c_retm_if(!p, "p is null");
422 calendar_record_h record = _calendar_get_record_with_index(p->ad->cid);
423 c_retm_if(!record, "record is null");
425 cal_detail_create_view(p->ad, record, NULL, NULL);
426 calendar_record_destroy(record, true);
431 static void __cal_search_list_update_genlist(cal_search_list_data *p)
437 __cal_search_list_delete_idler(p);
439 cal_list_base_clear(p->list);
441 struct appdata* ad = p->ad;
444 ad->today_item = NULL;
446 p->appended_event_count = 0;
447 p->repeated_group_it = NULL;
448 p->has_repeated_events = EINA_FALSE;
449 p->is_today_has_instance = EINA_FALSE;
451 if (eina_list_count(p->append_list)) {
453 __cal_search_list_show_searchbar(p);
455 __cal_search_list_delete_no_contents(p);
458 p->list = cal_list_base_create(ad, p->layout, "sw", true,
459 __cal_search_genlist_item_selected_callback, p);
463 cal_list_base_set_search_text(p->list, p->searchtext);
465 __cal_search_list_append_event_to_genlist(p);
467 __cal_search_list_add_idler(p);
471 __cal_search_list_show_searchbar(p);
473 __cal_search_list_delete_genlist(p);
475 __cal_search_list_create_no_contents(p);
481 static void __cal_search_list_update_events(cal_search_list_data *p)
485 _calendar_free_record_list(&p->append_list);
487 struct appdata *ad = p->ad;
490 if (CAL_STRLEN(p->searchtext)) {
491 if (p->search_type == CAL_SEARCH_ALL) {
492 __cal_search_list_get_events_with_search(p);
493 __cal_search_list_get_todo_with_search(p);
494 } else if (p->search_type == CAL_SEARCH_EVENTS) {
495 __cal_search_list_get_events_with_search(p);
496 } else if (p->search_type == CAL_SEARCH_TASKS) {
497 __cal_search_list_get_todo_with_search(p);
502 static void __cal_search_list_update_list(cal_search_list_data *p)
508 __cal_search_list_update_events(p);
510 __cal_search_list_update_genlist(p);
515 static void __cal_search_list_searchbar_entry_changed_callback(void *data, Evas_Object *obj, void *event_info)
521 cal_search_list_data *p = data;
522 c_ret_if(!p->searchbar);
524 p->searchtext = elm_entry_markup_to_utf8(elm_object_text_get(elm_object_part_content_get(p->searchbar, "elm.swallow.content")));
526 __cal_search_list_update_list(p);
531 static void __cal_search_list_cancel_button_callback(void *data, Evas_Object *obj, void *event_info)
535 cal_search_list_data *p = data;
538 elm_object_disabled_set(p->ad->new_event_button, EINA_FALSE);
540 Evas_Object *en = elm_object_part_content_get(p->searchbar, "elm.swallow.content");
542 Ecore_IMF_Context *imf_context = elm_entry_imf_context_get(en);
543 c_ret_if(!imf_context);
545 ecore_imf_context_input_panel_hide(imf_context);
550 static void __cal_search_list_text_refresh_callback(void *data)
554 c_retm_if(!data, "data is null");
555 cal_search_list_data *p = data;
557 elm_object_item_part_text_set(p->navi_item, "default", S_("IDS_COM_BODY_SEARCH"));
559 if (p->search_type == CAL_SEARCH_ALL) {
560 elm_object_text_set(p->scope_button, S_("IDS_COM_BODY_ALL"));
561 } else if (p->search_type == CAL_SEARCH_EVENTS) {
562 elm_object_text_set(p->scope_button, C_("IDS_CLD_BODY_EVENTS"));
563 } else if (p->search_type == CAL_SEARCH_TASKS) {
564 elm_object_text_set(p->scope_button, C_("IDS_CLD_BODY_TASKS"));
567 elm_object_part_text_set(p->searchbar, "elm.guidetext", S_("IDS_COM_BODY_SEARCH"));
568 elm_object_text_set(elm_object_part_content_get(p->searchbar, "button_cancel"), S_("IDS_COM_SK_CANCEL"));
571 elm_object_part_text_set(p->no_contents, "elm.text", S_("IDS_COM_BODY_NO_ITEMS"));
573 elm_genlist_realized_items_update(p->list);
576 static void __cal_search_list_delete_layout(void *data, Evas *e, Evas_Object *obj, void *ei)
581 cal_search_list_data *p = data;
582 c_retm_if(!p, "priv is null.");
584 elm_win_conformant_set(p->ad->win, EINA_TRUE);
586 p->ad->current_view = p->ad->tapbar_focus_view;
589 ecore_idler_del(p->idler);
593 _calendar_free_record_list(&p->append_list);
595 if (p->event_handler)
596 ecore_event_handler_del(p->event_handler);
599 evas_object_del(p->popup);
603 cal_lang_manager_remove_callback(__cal_search_list_text_refresh_callback, p);
610 static void __cal_search_list_searchbar_entry_unfocused_callback(void *data, Evas_Object *obj, void *event_info)
615 cal_search_list_data *p = data;
616 c_ret_if(!p->searchbar);
618 elm_object_disabled_set(p->ad->new_event_button, EINA_FALSE);
619 elm_win_conformant_set(p->ad->win, EINA_TRUE);
622 static void __cal_search_list_searchbar_entry_focused_callback(void *data, Evas_Object *obj, void *event_info)
627 cal_search_list_data *p = data;
628 c_ret_if(!p->searchbar);
630 elm_win_conformant_set(p->ad->win, EINA_FALSE);
635 static void __cal_search_list_searchbar_clicked_callback(void *data, Evas_Object *obj, void *event_info)
637 cal_search_list_data *p = data;
639 elm_object_disabled_set(p->ad->new_event_button, EINA_TRUE);
642 static void __cal_search_list_search_scope_click_callback(void *data, Evas_Object *obj, void *event_info)
645 c_retm_if(!data, "data is null");
647 cal_search_list_data *p = data;
649 __cal_search_list_create_ctx_popup(p);
652 static void __cal_search_list_create_searchbar(cal_search_list_data *p)
655 c_ret_if(!p->layout);
657 Evas_Object *button = elm_button_add(p->layout);
658 c_retm_if(!button, "button is NULL");
660 p->scope_button = button;
661 elm_object_style_set(button, "searchbar/default");
662 if (p->ad->tapbar_focus_view == CV_TODO) {
663 elm_object_text_set(button, C_("IDS_CLD_BODY_TASKS"));
665 elm_object_text_set(button, S_("IDS_COM_BODY_ALL"));
667 evas_object_data_set(button, "priv", p);
668 elm_object_part_content_set(p->layout, "search_scope_button", button);
669 evas_object_smart_callback_add(button, "clicked", __cal_search_list_search_scope_click_callback, p);
670 elm_object_focus_allow_set(button, EINA_FALSE);
672 Evas_Object *searchbar = cal_util_add_searchbar(p->layout, NULL, NULL, EINA_TRUE, NULL, p);
673 c_ret_if(!searchbar);
675 Evas_Object *entry = elm_object_part_content_get(searchbar, "elm.swallow.content");
677 elm_entry_cnp_mode_set(entry, ELM_CNP_MODE_PLAINTEXT);
679 elm_object_focus_set(entry, EINA_TRUE);
680 elm_entry_input_panel_layout_set(entry, ELM_INPUT_PANEL_LAYOUT_NORMAL);
681 elm_entry_markup_filter_append(entry, elm_entry_filter_limit_size, &_limit_20char);
683 evas_object_size_hint_weight_set(searchbar, EVAS_HINT_EXPAND, 0);
684 evas_object_size_hint_align_set(searchbar, EVAS_HINT_FILL, 0.0);
686 evas_object_smart_callback_add(entry, "changed", __cal_search_list_searchbar_entry_changed_callback, p);
687 evas_object_smart_callback_add(entry, "preedit,changed", __cal_search_list_searchbar_entry_changed_callback, p);
688 evas_object_smart_callback_add(entry, "unfocused", __cal_search_list_searchbar_entry_unfocused_callback, p);
689 evas_object_smart_callback_add(entry, "focused", __cal_search_list_searchbar_entry_focused_callback, p);
690 evas_object_smart_callback_add(searchbar, "clicked", __cal_search_list_searchbar_clicked_callback, p);
691 evas_object_smart_callback_add(searchbar, "cancel,clicked", __cal_search_list_cancel_button_callback, p);
693 evas_object_show(searchbar);
694 elm_object_part_content_set(p->layout, "searchbar", searchbar);
696 p->searchbar = searchbar;
699 static void __cal_search_list_context_popup_hide_callback(void *data, Evas_Object *obj, void *ei)
701 c_retm_if(!data, "data is null");
702 c_retm_if(!obj, "obj is null");
704 cal_search_list_data* p = data;
706 evas_object_del(obj);
708 c_retm_if(!p->searchbar, "entry is NULL.");
710 Evas_Object *entry = elm_object_part_content_get(p->searchbar, "elm.swallow.content");
711 c_retm_if(!entry, "entry is NULL.");
713 elm_object_focus_set(entry, EINA_TRUE);
717 static void __cal_search_list_context_popup_selected_callback(void *data, Evas_Object *obj, void *ei)
719 cal_search_list_data* p = CAL_UTIL_GET_PRIV_DATA(obj);
720 c_retm_if(!p, "p is NULL.");
722 int index = (int)data;
724 if (p->search_type == index) {
725 elm_ctxpopup_dismiss(obj);
729 p->search_type = index;
731 if (p->search_type == CAL_SEARCH_ALL) {
732 elm_object_text_set(p->scope_button, S_("IDS_COM_BODY_ALL"));
733 } else if (p->search_type == CAL_SEARCH_EVENTS) {
734 elm_object_text_set(p->scope_button, C_("IDS_CLD_BODY_EVENTS"));
735 } else if (p->search_type == CAL_SEARCH_TASKS) {
736 elm_object_text_set(p->scope_button, C_("IDS_CLD_BODY_TASKS"));
738 __cal_search_list_update_list(p);
740 elm_ctxpopup_dismiss(obj);
744 static void __cal_search_list_create_ctx_popup(cal_search_list_data* p)
746 c_retm_if(!p, "p is NULL.");
747 c_retm_if(!p->searchbar, "p->searchbar is NULL.");
751 Evas_Object *ctx = p->ctx_popup;
754 evas_object_del(ctx);
756 p->ctx_popup = elm_ctxpopup_add(p->ad->win);
757 c_retm_if(!p->ctx_popup, "elm_ctxpopup_add(p->ad->naviframe) returned null");
760 evas_object_data_set(ctx, "priv", p);
762 Evas_Object *entry = elm_object_part_content_get(p->searchbar, "elm.swallow.content");
763 c_retm_if(!entry, "entry is NULL.");
765 elm_object_focus_set(entry, EINA_FALSE);
767 evas_object_smart_callback_add(ctx, "dismissed", __cal_search_list_context_popup_hide_callback, p);
768 elm_ctxpopup_item_append(ctx, S_("IDS_COM_BODY_ALL"), NULL, __cal_search_list_context_popup_selected_callback, (const void *)0);
769 elm_ctxpopup_item_append(ctx, C_("IDS_CLD_BODY_EVENTS"), NULL, __cal_search_list_context_popup_selected_callback, (const void *)1);
770 elm_ctxpopup_item_append(ctx, C_("IDS_CLD_BODY_TASKS"), NULL, __cal_search_list_context_popup_selected_callback, (const void *)2);
771 elm_object_focus_allow_set(ctx, EINA_FALSE);
773 evas_object_geometry_get(p->scope_button, &x, &y, &w, &h);
775 evas_object_move(ctx, x + w/2 , y+h);
777 elm_ctxpopup_direction_priority_set(ctx, ELM_CTXPOPUP_DIRECTION_DOWN,
778 ELM_CTXPOPUP_DIRECTION_LEFT,
779 ELM_CTXPOPUP_DIRECTION_RIGHT,
780 ELM_CTXPOPUP_DIRECTION_UP);
781 evas_object_show(ctx);
784 static Eina_Bool __cal_search_list_mouse_button_down_callback(void *data, int type, void *event)
786 c_retvm_if(!event, EINA_FALSE, "event is null");
787 c_retvm_if(!data, EINA_FALSE, "data is null");
789 Ecore_Event_Mouse_Button *ev = event;
790 cal_search_list_data *p = data;
795 return ECORE_CALLBACK_RENEW;
798 Evas_Object* cal_search_list_create_list(struct appdata *ad, Evas_Object *parent)
802 c_retv_if(!ad, NULL);
803 c_retv_if(!parent, NULL);
805 if (ad->current_view == CV_SEARCH) {
809 ad->current_view = CV_SEARCH;
811 cal_search_list_data *p = calloc(1, sizeof(cal_search_list_data));
817 p->tm_start.tm_year = 70;
818 p->tm_end.tm_year = 137;
820 Evas_Object *layout = cal_util_add_layout(parent, "search/list/base");
824 ERR("layout is null.");
829 evas_object_data_set(layout, "priv", p);
833 Evas_Object *bg = cal_util_add_bg(layout, EINA_FALSE);
844 elm_object_part_content_set(layout, "base", bg);
846 p->navi_item = elm_naviframe_item_push(ad->naviframe, S_("IDS_COM_BODY_SEARCH"), NULL, NULL, layout, NULL);
849 ERR("elm_naviframe_item_push is failed");
850 evas_object_del(layout);
854 evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, __cal_search_list_delete_layout, p);
856 p->event_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, __cal_search_list_mouse_button_down_callback, p);
858 cal_lang_manager_add_callback(__cal_search_list_text_refresh_callback, p)
865 void cal_search_list_scroll_today(struct appdata* ad)
869 c_retm_if(!ad, "ad is null.");
871 Elm_Object_Item* it = ad->today_item;
873 elm_genlist_item_bring_in(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
874 DBG("scroll to : %p", it);
880 void cal_search_list_update_list(Evas_Object *ly)
886 cal_search_list_data *p = CAL_UTIL_GET_PRIV_DATA(ly);
889 struct appdata *ad = p->ad;
893 __cal_search_list_create_searchbar(p);
896 __cal_search_list_update_list(p);